diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/AuthenticationManagerConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/AuthenticationManagerConfiguration.java index 5436f511d37..16a2e4e0ea7 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/AuthenticationManagerConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/AuthenticationManagerConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.security.SecurityProperties.User; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,9 +42,15 @@ import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityConfigurer; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; +import org.springframework.stereotype.Component; /** - * Configuration for a Spring Security in-memory {@link AuthenticationManager}. + * Configuration for a Spring Security in-memory {@link AuthenticationManager}. Can be + * disabled by providing a bean of type AuthenticationManager. The value provided by this + * configuration will become the "global" authentication manager (from Spring Security), + * or the parent of the global instance. Thus it acts as a fallback when no others are + * provided, is used by method security if enabled, and as a parent authentication manager + * for "local" authentication managers in individual filter chains. * * @author Dave Syer * @author Rob Winch @@ -53,8 +60,15 @@ import org.springframework.security.config.annotation.authentication.configurers @ConditionalOnMissingBean(AuthenticationManager.class) @Order(Ordered.LOWEST_PRECEDENCE - 3) public class AuthenticationManagerConfiguration extends - GlobalAuthenticationConfigurerAdapter implements - ApplicationListener { + GlobalAuthenticationConfigurerAdapter { + + /* + * Yes, this class is a GlobalAuthenticationConfigurerAdapter, even though none of + * those methods are overridden: we want Spring Security to instantiate us early, so + * we can in turn force the SecurityPrequisites to be instantiated. This will prevent + * ordering issues between Spring Boot modules when they need to influence the default + * security configuration. + */ private static Log logger = LogFactory .getLog(AuthenticationManagerConfiguration.class); @@ -62,43 +76,48 @@ public class AuthenticationManagerConfiguration extends @Autowired private List dependencies; - @Autowired - private ObjectPostProcessor objectPostProcessor; - @Autowired private SecurityProperties security; @Autowired - private AuthenticationEventPublisher authenticationEventPublisher; - - private BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter(); - - @Override - public void init(AuthenticationManagerBuilder auth) throws Exception { - auth.apply(this.configurer); - } - - @Override - public void configure(AuthenticationManagerBuilder auth) throws Exception { - this.configurer.configureParent(auth); - } + private ObjectPostProcessor objectPostProcessor; @Bean @Primary - public AuthenticationManager authenticationManager() { - AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder() + public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) + throws Exception { + /* + * This AuthenticationManagerBuilder is for the global AuthenticationManager + */ + BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter(); + configurer.init(auth); + configurer.configure(auth); + AuthenticationManager manager = configurer.getAuthenticationManagerBuilder() .getOrBuild(); + configurer.configureParent(auth); return manager; } - @Override - public void onApplicationEvent(ContextRefreshedEvent event) { - AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder() - .getOrBuild(); - if (manager instanceof ProviderManager) { - ((ProviderManager) manager) - .setAuthenticationEventPublisher(this.authenticationEventPublisher); + @Component + protected static class AuthenticationManagerConfigurationListener implements + ApplicationListener { + + @Autowired + private AuthenticationEventPublisher authenticationEventPublisher; + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + ApplicationContext context = event.getApplicationContext(); + if (context.getBeanNamesForType(AuthenticationManager.class).length == 0) { + return; + } + AuthenticationManager manager = context.getBean(AuthenticationManager.class); + if (manager instanceof ProviderManager) { + ((ProviderManager) manager) + .setAuthenticationEventPublisher(this.authenticationEventPublisher); + } } + } /** @@ -163,7 +182,8 @@ public class AuthenticationManagerConfiguration extends .roles(roles.toArray(new String[roles.size()])).and().and().build(); // Defer actually setting the parent on the AuthenticationManagerBuilder - // because it makes it "configured" and we are only in the init() phase here. + // because it makes it "configured" and we are only in the init() phase + // here. } } diff --git a/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java b/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java index cec652a47db..65174bceb04 100644 --- a/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java +++ b/spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java @@ -101,6 +101,7 @@ public class SampleWebSecureApplication extends WebMvcConfigurerAdapter { .password("admin").roles("ADMIN", "USER").and().withUser("user") .password("user").roles("USER"); } + } }