Skip to content

Commit 32b3995

Browse files
committed
Merge pull request #43334 from BenchmarkingBuffalo
* pr/43334: Polish "Make UserDetailsServiceAutoConfiguration conditional on servlet app" Make UserDetailsServiceAutoConfiguration conditional on servlet app Closes gh-43334
2 parents a93055c + ff9fde0 commit 32b3995

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

Diff for: spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3232
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
3333
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
35+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
3436
import org.springframework.boot.autoconfigure.security.SecurityProperties;
3537
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.MissingAlternativeOrUserPropertiesConfigured;
3638
import org.springframework.context.annotation.Bean;
@@ -53,6 +55,7 @@
5355
* @author Dave Syer
5456
* @author Rob Winch
5557
* @author Madhura Bhave
58+
* @author Lasse Wulff
5659
* @since 2.0.0
5760
*/
5861
@AutoConfiguration
@@ -61,6 +64,7 @@
6164
@ConditionalOnBean(ObjectPostProcessor.class)
6265
@ConditionalOnMissingBean(value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class,
6366
AuthenticationManagerResolver.class }, type = "org.springframework.security.oauth2.jwt.JwtDecoder")
67+
@ConditionalOnWebApplication(type = Type.SERVLET)
6468
public class UserDetailsServiceAutoConfiguration {
6569

6670
private static final String NOOP_PASSWORD_PREFIX = "{noop}";

Diff for: spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java

+50-10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2828
import org.springframework.boot.test.context.FilteredClassLoader;
2929
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
30+
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
31+
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
3032
import org.springframework.boot.test.system.CapturedOutput;
3133
import org.springframework.boot.test.system.OutputCaptureExtension;
3234
import org.springframework.context.annotation.Bean;
@@ -56,17 +58,41 @@
5658
*
5759
* @author Madhura Bhave
5860
* @author HaiTao Zhang
61+
* @author Lasse Wulff
62+
* @author Moritz Halbritter
5963
*/
6064
@ExtendWith(OutputCaptureExtension.class)
6165
class UserDetailsServiceAutoConfigurationTests {
6266

63-
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
67+
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
6468
.withUserConfiguration(TestSecurityConfiguration.class)
6569
.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class));
6670

71+
@Test
72+
void shouldSupplyUserDetailsServiceInServletApp() {
73+
this.contextRunner.with(AuthenticationExclude.servletApp())
74+
.run((context) -> assertThat(context).hasSingleBean(UserDetailsService.class));
75+
}
76+
77+
@Test
78+
void shouldNotSupplyUserDetailsServiceInReactiveApp() {
79+
new ReactiveWebApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class)
80+
.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class))
81+
.with(AuthenticationExclude.reactiveApp())
82+
.run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class));
83+
}
84+
85+
@Test
86+
void shouldNotSupplyUserDetailsServiceInNonWebApp() {
87+
new ApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class)
88+
.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class))
89+
.with(AuthenticationExclude.noWebApp())
90+
.run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class));
91+
}
92+
6793
@Test
6894
void testDefaultUsernamePassword(CapturedOutput output) {
69-
this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()).run((context) -> {
95+
this.contextRunner.with(AuthenticationExclude.servletApp()).run((context) -> {
7096
UserDetailsService manager = context.getBean(UserDetailsService.class);
7197
assertThat(output).contains("Using generated security password:");
7298
assertThat(manager.loadUserByUsername("user")).isNotNull();
@@ -128,7 +154,7 @@ void defaultUserNotCreatedIfResourceServerWithJWTIsUsed() {
128154

129155
@Test
130156
void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() {
131-
this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath())
157+
this.contextRunner.with(AuthenticationExclude.servletApp())
132158
.withUserConfiguration(TestSecurityConfiguration.class)
133159
.run(((context) -> {
134160
InMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class);
@@ -192,14 +218,8 @@ void userDetailsServiceWhenRelyingPartyRegistrationRepositoryPresentAndPasswordC
192218
.run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class)));
193219
}
194220

195-
private Function<ApplicationContextRunner, ApplicationContextRunner> noOtherFormsOfAuthenticationOnTheClasspath() {
196-
return (contextRunner) -> contextRunner
197-
.withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class,
198-
RelyingPartyRegistrationRepository.class));
199-
}
200-
201221
private void testPasswordEncoding(Class<?> configClass, String providedPassword, String expectedPassword) {
202-
this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath())
222+
this.contextRunner.with(AuthenticationExclude.servletApp())
203223
.withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class,
204224
RelyingPartyRegistrationRepository.class))
205225
.withUserConfiguration(configClass)
@@ -211,6 +231,26 @@ private void testPasswordEncoding(Class<?> configClass, String providedPassword,
211231
}));
212232
}
213233

234+
private static final class AuthenticationExclude {
235+
236+
private static final FilteredClassLoader filteredClassLoader = new FilteredClassLoader(
237+
ClientRegistrationRepository.class, OpaqueTokenIntrospector.class,
238+
RelyingPartyRegistrationRepository.class);
239+
240+
static Function<WebApplicationContextRunner, WebApplicationContextRunner> servletApp() {
241+
return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader);
242+
}
243+
244+
static Function<ReactiveWebApplicationContextRunner, ReactiveWebApplicationContextRunner> reactiveApp() {
245+
return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader);
246+
}
247+
248+
static Function<ApplicationContextRunner, ApplicationContextRunner> noWebApp() {
249+
return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader);
250+
}
251+
252+
}
253+
214254
@Configuration(proxyBeanMethods = false)
215255
static class TestAuthenticationManagerConfiguration {
216256

0 commit comments

Comments
 (0)