Merge pull request #43334 from BenchmarkingBuffalo
* pr/43334: Polish "Make UserDetailsServiceAutoConfiguration conditional on servlet app" Make UserDetailsServiceAutoConfiguration conditional on servlet app Closes gh-43334
This commit is contained in:
commit
32b39955c6
|
|
@ -31,6 +31,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.MissingAlternativeOrUserPropertiesConfigured;
|
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.MissingAlternativeOrUserPropertiesConfigured;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -53,6 +55,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
|
* @author Lasse Wulff
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
|
|
@ -61,6 +64,7 @@ import org.springframework.util.StringUtils;
|
||||||
@ConditionalOnBean(ObjectPostProcessor.class)
|
@ConditionalOnBean(ObjectPostProcessor.class)
|
||||||
@ConditionalOnMissingBean(value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class,
|
@ConditionalOnMissingBean(value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class,
|
||||||
AuthenticationManagerResolver.class }, type = "org.springframework.security.oauth2.jwt.JwtDecoder")
|
AuthenticationManagerResolver.class }, type = "org.springframework.security.oauth2.jwt.JwtDecoder")
|
||||||
|
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||||
public class UserDetailsServiceAutoConfiguration {
|
public class UserDetailsServiceAutoConfiguration {
|
||||||
|
|
||||||
private static final String NOOP_PASSWORD_PREFIX = "{noop}";
|
private static final String NOOP_PASSWORD_PREFIX = "{noop}";
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
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.CapturedOutput;
|
||||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -56,17 +58,41 @@ import static org.mockito.Mockito.mock;
|
||||||
*
|
*
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @author HaiTao Zhang
|
* @author HaiTao Zhang
|
||||||
|
* @author Lasse Wulff
|
||||||
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
@ExtendWith(OutputCaptureExtension.class)
|
@ExtendWith(OutputCaptureExtension.class)
|
||||||
class UserDetailsServiceAutoConfigurationTests {
|
class UserDetailsServiceAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||||
.withUserConfiguration(TestSecurityConfiguration.class)
|
.withUserConfiguration(TestSecurityConfiguration.class)
|
||||||
.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.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
|
@Test
|
||||||
void testDefaultUsernamePassword(CapturedOutput output) {
|
void testDefaultUsernamePassword(CapturedOutput output) {
|
||||||
this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath()).run((context) -> {
|
this.contextRunner.with(AuthenticationExclude.servletApp()).run((context) -> {
|
||||||
UserDetailsService manager = context.getBean(UserDetailsService.class);
|
UserDetailsService manager = context.getBean(UserDetailsService.class);
|
||||||
assertThat(output).contains("Using generated security password:");
|
assertThat(output).contains("Using generated security password:");
|
||||||
assertThat(manager.loadUserByUsername("user")).isNotNull();
|
assertThat(manager.loadUserByUsername("user")).isNotNull();
|
||||||
|
|
@ -128,7 +154,7 @@ class UserDetailsServiceAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() {
|
void userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() {
|
||||||
this.contextRunner.with(noOtherFormsOfAuthenticationOnTheClasspath())
|
this.contextRunner.with(AuthenticationExclude.servletApp())
|
||||||
.withUserConfiguration(TestSecurityConfiguration.class)
|
.withUserConfiguration(TestSecurityConfiguration.class)
|
||||||
.run(((context) -> {
|
.run(((context) -> {
|
||||||
InMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class);
|
InMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class);
|
||||||
|
|
@ -192,14 +218,8 @@ class UserDetailsServiceAutoConfigurationTests {
|
||||||
.run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class)));
|
.run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<ApplicationContextRunner, ApplicationContextRunner> noOtherFormsOfAuthenticationOnTheClasspath() {
|
|
||||||
return (contextRunner) -> contextRunner
|
|
||||||
.withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class,
|
|
||||||
RelyingPartyRegistrationRepository.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testPasswordEncoding(Class<?> configClass, String providedPassword, String expectedPassword) {
|
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,
|
.withClassLoader(new FilteredClassLoader(ClientRegistrationRepository.class, OpaqueTokenIntrospector.class,
|
||||||
RelyingPartyRegistrationRepository.class))
|
RelyingPartyRegistrationRepository.class))
|
||||||
.withUserConfiguration(configClass)
|
.withUserConfiguration(configClass)
|
||||||
|
|
@ -211,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<WebApplicationContextRunner, WebApplicationContextRunner> servletApp() {
|
||||||
|
return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Function<ReactiveWebApplicationContextRunner, ReactiveWebApplicationContextRunner> reactiveApp() {
|
||||||
|
return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Function<ApplicationContextRunner, ApplicationContextRunner> noWebApp() {
|
||||||
|
return (contextRunner) -> contextRunner.withClassLoader(filteredClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class TestAuthenticationManagerConfiguration {
|
static class TestAuthenticationManagerConfiguration {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue