From ff9fde0ef4a116bf13f0c5860414b0b2798fbdda Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 2 Dec 2024 13:30:36 +0100 Subject: [PATCH] Polish "Make UserDetailsServiceAutoConfiguration conditional on servlet app" See gh-43334 --- ...rDetailsServiceAutoConfigurationTests.java | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java index d80e3a686c..6c4ee3c918 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java @@ -26,6 +26,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; @@ -57,6 +59,7 @@ import static org.mockito.Mockito.mock; * @author Madhura Bhave * @author HaiTao Zhang * @author Lasse Wulff + * @author Moritz Halbritter */ @ExtendWith(OutputCaptureExtension.class) class UserDetailsServiceAutoConfigurationTests { @@ -65,9 +68,31 @@ class UserDetailsServiceAutoConfigurationTests { .withUserConfiguration(TestSecurityConfiguration.class) .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)); + @Test + void shouldSupplyUserDetailsServiceInServletApp() { + this.contextRunner.with(AuthenticationExclude.servletApp()) + .run((context) -> assertThat(context).hasSingleBean(UserDetailsService.class)); + } + + @Test + void shouldNotSupplyUserDetailsServiceInReactiveApp() { + new ReactiveWebApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class) + .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)) + .with(AuthenticationExclude.reactiveApp()) + .run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class)); + } + + @Test + void shouldNotSupplyUserDetailsServiceInNonWebApp() { + new ApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class) + .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)) + .with(AuthenticationExclude.noWebApp()) + .run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class)); + } + @Test void testDefaultUsernamePassword(CapturedOutput output) { - this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()).run((context) -> { + this.contextRunner.with(AuthenticationExclude.servletApp()).run((context) -> { UserDetailsService manager = context.getBean(UserDetailsService.class); assertThat(output).contains("Using generated security password:"); assertThat(manager.loadUserByUsername("user")).isNotNull(); @@ -129,7 +154,7 @@ class UserDetailsServiceAutoConfigurationTests { @Test void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() { - this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()) + this.contextRunner.with(AuthenticationExclude.servletApp()) .withUserConfiguration(TestSecurityConfiguration.class) .run(((context) -> { InMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class); @@ -193,14 +218,8 @@ class UserDetailsServiceAutoConfigurationTests { .run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class))); } - private Function noOtherFormsOfAuthenticationOnTheClasspath() { - return (contextRunner) -> contextRunner - .withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, - RelyingPartyRegistrationRepository.class)); - } - private void testPasswordEncoding(Class configClass, String providedPassword, String expectedPassword) { - this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()) + this.contextRunner.with(AuthenticationExclude.servletApp()) .withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, RelyingPartyRegistrationRepository.class)) .withUserConfiguration(configClass) @@ -212,6 +231,26 @@ class UserDetailsServiceAutoConfigurationTests { })); } + private static final class AuthenticationExclude { + + private static final FilteredClassLoader filteredClassLoader = new FilteredClassLoader( + ClientRegistrationRepository.class, OpaqueTokenIntrospector.class, + RelyingPartyRegistrationRepository.class); + + static Function servletApp() { + return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader); + } + + static Function reactiveApp() { + return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader); + } + + static Function noWebApp() { + return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader); + } + + } + @Configuration(proxyBeanMethods = false) static class TestAuthenticationManagerConfiguration {