From 0a446cb962033727e85df0f2760fdb6e76cc0afc Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 7 Feb 2018 16:12:46 -0800 Subject: [PATCH] Refactor Spring Security auto-configuration classes The auto-configuration for a `UserDetailsService` and the web bits has been split into two. Closes gh-11915 Fixes gh-11891 --- .../ReactiveSecurityAutoConfiguration.java | 12 +- ...eUserDetailsServiceAutoConfiguration.java} | 4 +- .../WebFluxSecurityConfiguration.java | 5 +- .../servlet/SecurityAutoConfiguration.java | 12 +- .../SpringBootWebSecurityConfiguration.java | 2 + ... UserDetailsServiceAutoConfiguration.java} | 6 +- .../main/resources/META-INF/spring.factories | 2 + ...eactiveSecurityAutoConfigurationTests.java | 108 +------- ...DetailsServiceAutoConfigurationTests.java} | 87 ++++++- .../WebFluxSecurityConfigurationTests.java | 68 ++++++ ...thenticationManagerConfigurationTests.java | 125 ---------- .../SecurityAutoConfigurationTests.java | 100 -------- ...ConfigurationEarlyInitializationTests.java | 1 + ...rDetailsServiceAutoConfigurationTests.java | 230 ++++++++++++++++++ 14 files changed, 401 insertions(+), 361 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/{ReactiveAuthenticationManagerConfiguration.java => ReactiveUserDetailsServiceAutoConfiguration.java} (96%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/{AuthenticationManagerConfiguration.java => UserDetailsServiceAutoConfiguration.java} (93%) rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/{ReactiveAuthenticationManagerConfigurationTests.java => ReactiveUserDetailsServiceAutoConfigurationTests.java} (54%) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfigurationTests.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java index 1d62a9cf47..75646b5385 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java @@ -17,29 +17,21 @@ package org.springframework.boot.autoconfigure.security.reactive; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; -import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Security in a reactive - * application. This auto-configuration adds {@link EnableWebFluxSecurity} and delegates - * to Spring Security's content-negotiation mechanism for authentication. In a webapp this - * configuration also secures all web endpoints. + * application. * * @author Madhura Bhave * @since 2.0.0 */ @Configuration -@ConditionalOnClass({ EnableWebFluxSecurity.class, - AuthenticationPrincipalArgumentResolver.class }) @EnableConfigurationProperties(SecurityProperties.class) -@Import({ WebFluxSecurityConfiguration.class, - ReactiveAuthenticationManagerConfiguration.class }) +@Import(WebFluxSecurityConfiguration.class) public class ReactiveSecurityAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java similarity index 96% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java index eafa5c3099..7f36829df6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java @@ -49,7 +49,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; @ConditionalOnMissingBean({ ReactiveAuthenticationManager.class, ReactiveUserDetailsService.class }) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) -class ReactiveAuthenticationManagerConfiguration { +public class ReactiveUserDetailsServiceAutoConfiguration { private static final String NOOP_PASSWORD_PREFIX = "{noop}"; @@ -57,7 +57,7 @@ class ReactiveAuthenticationManagerConfiguration { .compile("^\\{.+}.*$"); private static final Log logger = LogFactory - .getLog(ReactiveAuthenticationManagerConfiguration.class); + .getLog(ReactiveUserDetailsServiceAutoConfiguration.class); @Bean public MapReactiveUserDetailsService reactiveUserDetailsService( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfiguration.java index debcba4d0e..e2a0a07a9b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfiguration.java @@ -24,8 +24,9 @@ import org.springframework.security.web.server.WebFilterChainProxy; /** * Switches on {@link EnableWebFluxSecurity} for a reactive web application if this - * annotation has not been added by the user. This configuration also backs off if a bean - * of type {@link WebFilterChainProxy} has been configured in any other way. + * annotation has not been added by the user. It delegates + * to Spring Security's content-negotiation mechanism for authentication. This configuration also + * backs off if a bean of type {@link WebFilterChainProxy} has been configured in any other way. * * @author Madhura Bhave */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfiguration.java index b984053ae2..6e7ddc475b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfiguration.java @@ -27,26 +27,20 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.security.authentication.AuthenticationEventPublisher; -import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Security. Provides an - * {@link InMemoryUserDetailsManager} with one user (named "user") whose password is - * random and printed on the console at INFO level during startup. In a webapp, this - * configuration also secures all web endpoints (including static resources). + * {@link EnableAutoConfiguration Auto-configuration} for Spring Security. * * @author Dave Syer * @author Andy Wilkinson * @author Madhura Bhave */ @Configuration -@ConditionalOnClass({ AuthenticationManager.class, EnableWebSecurity.class }) +@ConditionalOnClass(DefaultAuthenticationEventPublisher.class) @EnableConfigurationProperties(SecurityProperties.class) @Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class, - AuthenticationManagerConfiguration.class, SecurityDataConfiguration.class }) + SecurityDataConfiguration.class }) public class SecurityAutoConfiguration { @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java index d2bef77ed3..1dc8403afc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.security.servlet; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; @@ -35,6 +36,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur * @author Madhura Bhave * @since 2.0.0 */ +@ConditionalOnClass(WebSecurityConfigurerAdapter.class) @ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) @ConditionalOnWebApplication(type = Type.SERVLET) public class SpringBootWebSecurityConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java similarity index 93% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java index 3ec5147d9f..20602c6576 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfiguration.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Bean; @@ -47,10 +48,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; * @author Madhura Bhave */ @Configuration +@ConditionalOnClass(AuthenticationManager.class) @ConditionalOnBean(ObjectPostProcessor.class) @ConditionalOnMissingBean({ AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class }) -public class AuthenticationManagerConfiguration { +public class UserDetailsServiceAutoConfiguration { private static final String NOOP_PASSWORD_PREFIX = "{noop}"; @@ -58,7 +60,7 @@ public class AuthenticationManagerConfiguration { .compile("^\\{.+}.*$"); private static final Log logger = LogFactory - .getLog(AuthenticationManagerConfiguration.class); + .getLog(UserDetailsServiceAutoConfiguration.class); @Bean @ConditionalOnMissingBean(type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 30de6c79c4..b7d2b31508 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -97,8 +97,10 @@ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\ org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java index ba74b3a8d0..c944e5eee8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java @@ -17,25 +17,10 @@ package org.springframework.boot.autoconfigure.security.reactive; import org.junit.Test; -import reactor.core.publisher.Mono; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.reactive.MockReactiveWebServerFactory; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; -import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.server.reactive.HttpHandler; -import org.springframework.security.authentication.ReactiveAuthenticationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; -import org.springframework.security.core.userdetails.ReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.web.server.WebFilterChainProxy; -import org.springframework.web.reactive.config.EnableWebFlux; -import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import static org.assertj.core.api.Assertions.assertThat; @@ -49,10 +34,11 @@ public class ReactiveSecurityAutoConfigurationTests { private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(); @Test - public void enablesWebFluxSecurity() { - this.contextRunner.withUserConfiguration(TestConfig.class) + public void importsConfigurationThatEnablesWebFluxSecurity() { + this.contextRunner .withConfiguration( - AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class, + ReactiveUserDetailsServiceAutoConfiguration.class)) .run((context) -> { assertThat(context).getBean(WebFilterChainProxy.class).isNotNull(); assertThat(context).getBean(WebFluxSecurityConfiguration.class) @@ -61,90 +47,4 @@ public class ReactiveSecurityAutoConfigurationTests { }); } - @Test - public void configuresADefaultUser() { - this.contextRunner.withUserConfiguration(TestConfig.class) - .withConfiguration( - AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) - .run((context) -> { - ReactiveUserDetailsService userDetailsService = context - .getBean(ReactiveUserDetailsService.class); - assertThat(userDetailsService.findByUsername("user").block()) - .isNotNull(); - }); - } - - @Test - public void doesNotConfigureDefaultUserIfUserDetailsServiceAvailable() { - this.contextRunner.withUserConfiguration(UserConfig.class, TestConfig.class) - .withConfiguration( - AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) - .run((context) -> { - ReactiveUserDetailsService userDetailsService = context - .getBean(ReactiveUserDetailsService.class); - assertThat(userDetailsService.findByUsername("user").block()) - .isNull(); - assertThat(userDetailsService.findByUsername("foo").block()) - .isNotNull(); - assertThat(userDetailsService.findByUsername("admin").block()) - .isNotNull(); - }); - } - - @Test - public void doesNotConfigureDefaultUserIfAuthenticationManagerAvailable() { - this.contextRunner - .withUserConfiguration(AuthenticationManagerConfig.class, - TestConfig.class) - .withConfiguration( - AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) - .run((context) -> assertThat(context) - .getBean(ReactiveUserDetailsService.class).isNull()); - } - - @Configuration - @EnableWebFlux - static class TestConfig { - - @Bean - public HttpHandler httpHandler(ApplicationContext applicationContext) { - return WebHttpHandlerBuilder.applicationContext(applicationContext).build(); - } - - @Bean - public ReactiveWebServerFactory reactiveWebServerFactory() { - return new MockReactiveWebServerFactory(); - } - - } - - @Configuration - static class UserConfig { - - @Bean - public MapReactiveUserDetailsService userDetailsService() { - UserDetails foo = User.withUsername("foo").password("foo").roles("USER") - .build(); - UserDetails admin = User.withUsername("admin").password("admin") - .roles("USER", "ADMIN").build(); - return new MapReactiveUserDetailsService(foo, admin); - } - - } - - @Configuration - static class AuthenticationManagerConfig { - - @Bean - public ReactiveAuthenticationManager reactiveAuthenticationManager() { - return new ReactiveAuthenticationManager() { - @Override - public Mono authenticate(Authentication authentication) { - return null; - } - }; - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfigurationTests.java similarity index 54% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfigurationTests.java index bc546623ea..41d713afff 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveAuthenticationManagerConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfigurationTests.java @@ -17,34 +17,79 @@ package org.springframework.boot.autoconfigure.security.reactive; import org.junit.Test; +import reactor.core.publisher.Mono; +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.runner.ReactiveWebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.core.userdetails.ReactiveUserDetailsService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; /** - * Tests for {@link ReactiveAuthenticationManagerConfiguration}. + * Tests for {@link ReactiveUserDetailsServiceAutoConfiguration}. * * @author Madhura Bhave */ -public class ReactiveAuthenticationManagerConfigurationTests { +public class ReactiveUserDetailsServiceAutoConfigurationTests { - private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(); + private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(ReactiveUserDetailsServiceAutoConfiguration.class)); + + @Test + public void configuresADefaultUser() { + this.contextRunner.withUserConfiguration(TestSecurityConfiguration.class) + .run((context) -> { + ReactiveUserDetailsService userDetailsService = context + .getBean(ReactiveUserDetailsService.class); + assertThat(userDetailsService.findByUsername("user").block()) + .isNotNull(); + }); + } + + @Test + public void doesNotConfigureDefaultUserIfUserDetailsServiceAvailable() { + this.contextRunner.withUserConfiguration(UserConfig.class, TestSecurityConfiguration.class) + .run((context) -> { + ReactiveUserDetailsService userDetailsService = context + .getBean(ReactiveUserDetailsService.class); + assertThat(userDetailsService.findByUsername("user").block()) + .isNull(); + assertThat(userDetailsService.findByUsername("foo").block()) + .isNotNull(); + assertThat(userDetailsService.findByUsername("admin").block()) + .isNotNull(); + }); + } + + @Test + public void doesNotConfigureDefaultUserIfAuthenticationManagerAvailable() { + this.contextRunner + .withUserConfiguration(AuthenticationManagerConfig.class, + TestSecurityConfiguration.class) + .withConfiguration( + AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .run((context) -> assertThat(context) + .getBean(ReactiveUserDetailsService.class).isNull()); + } @Test public void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() { this.contextRunner - .withUserConfiguration(TestSecurityConfiguration.class, - ReactiveAuthenticationManagerConfiguration.class) + .withUserConfiguration(TestSecurityConfiguration.class) .run(((context) -> { MapReactiveUserDetailsService userDetailsService = context .getBean(MapReactiveUserDetailsService.class); @@ -73,8 +118,7 @@ public class ReactiveAuthenticationManagerConfigurationTests { private void testPasswordEncoding(Class configClass, String providedPassword, String expectedPassword) { this.contextRunner - .withUserConfiguration(configClass, - ReactiveAuthenticationManagerConfiguration.class) + .withUserConfiguration(configClass) .withPropertyValues("spring.security.user.password=" + providedPassword) .run(((context) -> { MapReactiveUserDetailsService userDetailsService = context @@ -92,6 +136,35 @@ public class ReactiveAuthenticationManagerConfigurationTests { } + @Configuration + static class UserConfig { + + @Bean + public MapReactiveUserDetailsService userDetailsService() { + UserDetails foo = User.withUsername("foo").password("foo").roles("USER") + .build(); + UserDetails admin = User.withUsername("admin").password("admin") + .roles("USER", "ADMIN").build(); + return new MapReactiveUserDetailsService(foo, admin); + } + + } + + @Configuration + static class AuthenticationManagerConfig { + + @Bean + public ReactiveAuthenticationManager reactiveAuthenticationManager() { + return new ReactiveAuthenticationManager() { + @Override + public Mono authenticate(Authentication authentication) { + return null; + } + }; + } + + } + @Configuration @Import(TestSecurityConfiguration.class) protected static class TestConfigWithPasswordEncoder { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfigurationTests.java new file mode 100644 index 0000000000..7de4fb88e8 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/WebFluxSecurityConfigurationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.security.reactive; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.web.server.WebFilterChainProxy; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link WebFluxSecurityConfiguration}. + * + * @author Madhura Bhave + */ +public class WebFluxSecurityConfigurationTests { + + private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(); + + @Test + public void backsOffWhenWebFilterChainProxyBeanPresent() { + this.contextRunner.withUserConfiguration(WebFilterChainProxyConfiguration.class, WebFluxSecurityConfiguration.class) + .run(context -> assertThat(context).doesNotHaveBean(WebFluxSecurityConfiguration.class)); + } + + @Test + public void enablesWebFluxSecurity() { + this.contextRunner + .withConfiguration( + AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class, + ReactiveUserDetailsServiceAutoConfiguration.class)) + .run((context) -> { + assertThat(context).getBean(WebFilterChainProxy.class).isNotNull(); + assertThat(context).getBean(WebFluxSecurityConfiguration.class) + .isNotNull(); + assertThat(context).getBean(WebFilterChainProxy.class).isNotNull(); + }); + } + + @Configuration + static class WebFilterChainProxyConfiguration { + + @Bean + public WebFilterChainProxy webFilterChainProxy() { + return mock(WebFilterChainProxy.class); + } + + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfigurationTests.java deleted file mode 100644 index 511463ef9f..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/AuthenticationManagerConfigurationTests.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2012-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.autoconfigure.security.servlet; - -import org.junit.Test; - -import org.springframework.boot.autoconfigure.security.SecurityProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link AuthenticationManagerConfiguration}. - * - * @author Madhura Bhave - */ -public class AuthenticationManagerConfigurationTests { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); - - @Test - public void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() { - this.contextRunner.withUserConfiguration(TestSecurityConfiguration.class, - AuthenticationManagerConfiguration.class).run(((context) -> { - InMemoryUserDetailsManager userDetailsService = context - .getBean(InMemoryUserDetailsManager.class); - String password = userDetailsService.loadUserByUsername("user") - .getPassword(); - assertThat(password).startsWith("{noop}"); - })); - } - - @Test - public void userDetailsServiceWhenPasswordEncoderAbsentAndRawPassword() { - testPasswordEncoding(TestSecurityConfiguration.class, "secret", "{noop}secret"); - } - - @Test - public void userDetailsServiceWhenPasswordEncoderAbsentAndEncodedPassword() { - String password = "{bcrypt}$2a$10$sCBi9fy9814vUPf2ZRbtp.fR5/VgRk2iBFZ.ypu5IyZ28bZgxrVDa"; - testPasswordEncoding(TestSecurityConfiguration.class, password, password); - } - - @Test - public void userDetailsServiceWhenPasswordEncoderBeanPresent() { - testPasswordEncoding(TestConfigWithPasswordEncoder.class, "secret", "secret"); - } - - @Test - public void userDetailsServiceWhenClientRegistrationRepositoryBeanPresent() { - this.contextRunner - .withUserConfiguration(TestConfigWithClientRegistrationRepository.class, - AuthenticationManagerConfiguration.class) - .run(((context) -> assertThat(context) - .doesNotHaveBean(InMemoryUserDetailsManager.class))); - } - - private void testPasswordEncoding(Class configClass, String providedPassword, - String expectedPassword) { - this.contextRunner - .withUserConfiguration(configClass, - AuthenticationManagerConfiguration.class) - .withPropertyValues("spring.security.user.password=" + providedPassword) - .run(((context) -> { - InMemoryUserDetailsManager userDetailsService = context - .getBean(InMemoryUserDetailsManager.class); - String password = userDetailsService.loadUserByUsername("user") - .getPassword(); - assertThat(password).isEqualTo(expectedPassword); - })); - } - - @Configuration - @EnableWebSecurity - @EnableConfigurationProperties(SecurityProperties.class) - protected static class TestSecurityConfiguration { - - } - - @Configuration - @Import(TestSecurityConfiguration.class) - protected static class TestConfigWithPasswordEncoder { - - @Bean - public PasswordEncoder passwordEncoder() { - return mock(PasswordEncoder.class); - } - - } - - @Configuration - @Import(TestSecurityConfiguration.class) - protected static class TestConfigWithClientRegistrationRepository { - - @Bean - public ClientRegistrationRepository clientRegistrationRepository() { - return mock(ClientRegistrationRepository.class); - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java index c87dd9e0c6..820270dee8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityAutoConfigurationTests.java @@ -16,7 +16,6 @@ package org.springframework.boot.autoconfigure.security.servlet; -import java.util.Collections; import java.util.EnumSet; import javax.servlet.DispatcherType; @@ -39,21 +38,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.security.authentication.AuthenticationEventPublisher; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; -import org.springframework.security.authentication.ProviderManager; -import org.springframework.security.authentication.TestingAuthenticationProvider; -import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.FilterChainProxy; import org.springframework.test.util.ReflectionTestUtils; @@ -149,61 +140,6 @@ public class SecurityAutoConfigurationTests { .getOrder()).isEqualTo(12345)); } - @Test - public void testDefaultUsernamePassword() { - this.contextRunner.run((context) -> { - UserDetailsService manager = context.getBean(UserDetailsService.class); - assertThat(this.outputCapture.toString()) - .contains("Using generated security password:"); - assertThat(manager.loadUserByUsername("user")).isNotNull(); - }); - } - - @Test - public void defaultUserNotCreatedIfAuthenticationManagerBeanPresent() { - this.contextRunner - .withUserConfiguration(TestAuthenticationManagerConfiguration.class) - .run((context) -> { - AuthenticationManager manager = context - .getBean(AuthenticationManager.class); - assertThat(manager).isEqualTo(context.getBean( - TestAuthenticationManagerConfiguration.class).authenticationManager); - assertThat(this.outputCapture.toString()) - .doesNotContain("Using generated security password: "); - TestingAuthenticationToken token = new TestingAuthenticationToken( - "foo", "bar"); - assertThat(manager.authenticate(token)).isNotNull(); - }); - } - - @Test - public void defaultUserNotCreatedIfUserDetailsServiceBeanPresent() { - this.contextRunner - .withUserConfiguration(TestUserDetailsServiceConfiguration.class) - .run((context) -> { - UserDetailsService userDetailsService = context - .getBean(UserDetailsService.class); - assertThat(this.outputCapture.toString()) - .doesNotContain("Using default security password: "); - assertThat(userDetailsService.loadUserByUsername("foo")).isNotNull(); - }); - } - - @Test - public void defaultUserNotCreatedIfAuthenticationProviderBeanPresent() { - this.contextRunner - .withUserConfiguration(TestAuthenticationProviderConfiguration.class) - .run((context) -> { - AuthenticationProvider provider = context - .getBean(AuthenticationProvider.class); - assertThat(this.outputCapture.toString()) - .doesNotContain("Using default security password: "); - TestingAuthenticationToken token = new TestingAuthenticationToken( - "foo", "bar"); - assertThat(provider.authenticate(token)).isNotNull(); - }); - } - @Test public void testJpaCoexistsHappily() { this.contextRunner @@ -292,42 +228,6 @@ public class SecurityAutoConfigurationTests { } - @Configuration - protected static class TestAuthenticationManagerConfiguration { - - private AuthenticationManager authenticationManager; - - @Bean - public AuthenticationManager myAuthenticationManager() { - AuthenticationProvider authenticationProvider = new TestingAuthenticationProvider(); - this.authenticationManager = new ProviderManager( - Collections.singletonList(authenticationProvider)); - return this.authenticationManager; - } - - } - - @Configuration - protected static class TestUserDetailsServiceConfiguration { - - @Bean - public InMemoryUserDetailsManager myUserDetailsManager() { - return new InMemoryUserDetailsManager( - User.withUsername("foo").password("bar").roles("USER").build()); - } - - } - - @Configuration - protected static class TestAuthenticationProviderConfiguration { - - @Bean - public AuthenticationProvider myAuthenticationProvider() { - return new TestingAuthenticationProvider(); - } - - } - @Configuration @EnableWebSecurity static class WebSecurity extends WebSecurityConfigurerAdapter { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityFilterAutoConfigurationEarlyInitializationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityFilterAutoConfigurationEarlyInitializationTests.java index 3c52f4c67a..b4ce90b5ef 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityFilterAutoConfigurationEarlyInitializationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/SecurityFilterAutoConfigurationEarlyInitializationTests.java @@ -78,6 +78,7 @@ public class SecurityFilterAutoConfigurationEarlyInitializationTests { @ImportAutoConfiguration({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class, SecurityAutoConfiguration.class, + UserDetailsServiceAutoConfiguration.class, SecurityFilterAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) static class Config { 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 new file mode 100644 index 0000000000..7e3fc32123 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/UserDetailsServiceAutoConfigurationTests.java @@ -0,0 +1,230 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.security.servlet; + +import java.util.Collections; + +import org.junit.Rule; +import org.junit.Test; + +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.runner.ApplicationContextRunner; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.TestingAuthenticationProvider; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link UserDetailsServiceAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class UserDetailsServiceAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(TestSecurityConfiguration.class) + .withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class)); + + @Rule + public OutputCapture outputCapture = new OutputCapture(); + + @Test + public void testDefaultUsernamePassword() { + this.contextRunner.run((context) -> { + UserDetailsService manager = context.getBean(UserDetailsService.class); + assertThat(this.outputCapture.toString()) + .contains("Using generated security password:"); + assertThat(manager.loadUserByUsername("user")).isNotNull(); + }); + } + + @Test + public void defaultUserNotCreatedIfAuthenticationManagerBeanPresent() { + this.contextRunner + .withUserConfiguration(TestAuthenticationManagerConfiguration.class) + .run((context) -> { + AuthenticationManager manager = context + .getBean(AuthenticationManager.class); + assertThat(manager).isEqualTo(context.getBean( + TestAuthenticationManagerConfiguration.class).authenticationManager); + assertThat(this.outputCapture.toString()) + .doesNotContain("Using generated security password: "); + TestingAuthenticationToken token = new TestingAuthenticationToken( + "foo", "bar"); + assertThat(manager.authenticate(token)).isNotNull(); + }); + } + + @Test + public void defaultUserNotCreatedIfUserDetailsServiceBeanPresent() { + this.contextRunner + .withUserConfiguration(TestUserDetailsServiceConfiguration.class) + .run((context) -> { + UserDetailsService userDetailsService = context + .getBean(UserDetailsService.class); + assertThat(this.outputCapture.toString()) + .doesNotContain("Using default security password: "); + assertThat(userDetailsService.loadUserByUsername("foo")).isNotNull(); + }); + } + + @Test + public void defaultUserNotCreatedIfAuthenticationProviderBeanPresent() { + this.contextRunner + .withUserConfiguration(TestAuthenticationProviderConfiguration.class) + .run((context) -> { + AuthenticationProvider provider = context + .getBean(AuthenticationProvider.class); + assertThat(this.outputCapture.toString()) + .doesNotContain("Using default security password: "); + TestingAuthenticationToken token = new TestingAuthenticationToken( + "foo", "bar"); + assertThat(provider.authenticate(token)).isNotNull(); + }); + } + + @Test + public void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() { + this.contextRunner.withUserConfiguration(TestSecurityConfiguration.class).run(((context) -> { + InMemoryUserDetailsManager userDetailsService = context + .getBean(InMemoryUserDetailsManager.class); + String password = userDetailsService.loadUserByUsername("user") + .getPassword(); + assertThat(password).startsWith("{noop}"); + })); + } + + @Test + public void userDetailsServiceWhenPasswordEncoderAbsentAndRawPassword() { + testPasswordEncoding(TestSecurityConfiguration.class, "secret", "{noop}secret"); + } + + @Test + public void userDetailsServiceWhenPasswordEncoderAbsentAndEncodedPassword() { + String password = "{bcrypt}$2a$10$sCBi9fy9814vUPf2ZRbtp.fR5/VgRk2iBFZ.ypu5IyZ28bZgxrVDa"; + testPasswordEncoding(TestSecurityConfiguration.class, password, password); + } + + @Test + public void userDetailsServiceWhenPasswordEncoderBeanPresent() { + testPasswordEncoding(TestConfigWithPasswordEncoder.class, "secret", "secret"); + } + + @Test + public void userDetailsServiceWhenClientRegistrationRepositoryBeanPresent() { + this.contextRunner + .withUserConfiguration(TestConfigWithClientRegistrationRepository.class) + .run(((context) -> assertThat(context) + .doesNotHaveBean(InMemoryUserDetailsManager.class))); + } + + private void testPasswordEncoding(Class configClass, String providedPassword, + String expectedPassword) { + this.contextRunner + .withUserConfiguration(configClass) + .withPropertyValues("spring.security.user.password=" + providedPassword) + .run(((context) -> { + InMemoryUserDetailsManager userDetailsService = context + .getBean(InMemoryUserDetailsManager.class); + String password = userDetailsService.loadUserByUsername("user") + .getPassword(); + assertThat(password).isEqualTo(expectedPassword); + })); + } + + @Configuration + protected static class TestAuthenticationManagerConfiguration { + + private AuthenticationManager authenticationManager; + + @Bean + public AuthenticationManager myAuthenticationManager() { + AuthenticationProvider authenticationProvider = new TestingAuthenticationProvider(); + this.authenticationManager = new ProviderManager( + Collections.singletonList(authenticationProvider)); + return this.authenticationManager; + } + + } + + @Configuration + protected static class TestUserDetailsServiceConfiguration { + + @Bean + public InMemoryUserDetailsManager myUserDetailsManager() { + return new InMemoryUserDetailsManager( + User.withUsername("foo").password("bar").roles("USER").build()); + } + + } + + @Configuration + protected static class TestAuthenticationProviderConfiguration { + + @Bean + public AuthenticationProvider myAuthenticationProvider() { + return new TestingAuthenticationProvider(); + } + + } + + @Configuration + @EnableWebSecurity + @EnableConfigurationProperties(SecurityProperties.class) + protected static class TestSecurityConfiguration { + + } + + @Configuration + @Import(TestSecurityConfiguration.class) + protected static class TestConfigWithPasswordEncoder { + + @Bean + public PasswordEncoder passwordEncoder() { + return mock(PasswordEncoder.class); + } + + } + + @Configuration + @Import(TestSecurityConfiguration.class) + protected static class TestConfigWithClientRegistrationRepository { + + @Bean + public ClientRegistrationRepository clientRegistrationRepository() { + return mock(ClientRegistrationRepository.class); + } + + } + +}