Ensure the AuthenticationManager is created when needed
There was too much state really in the old implementation of AuthenticationManagerConfiguration, and it was leading occasionally to null pointers when method A assumed that method B had already been called and it hadn't. This change manages to concentrate all the references to an AuthenticationManagerBuilder into a single method call, removoing the need for storing it at all. Fixes gh-1556
This commit is contained in:
parent
0950072b5e
commit
9902f98a3d
|
|
@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
|
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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.SecurityConfigurer;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
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 Dave Syer
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
|
|
@ -53,8 +60,15 @@ import org.springframework.security.config.annotation.authentication.configurers
|
||||||
@ConditionalOnMissingBean(AuthenticationManager.class)
|
@ConditionalOnMissingBean(AuthenticationManager.class)
|
||||||
@Order(Ordered.LOWEST_PRECEDENCE - 3)
|
@Order(Ordered.LOWEST_PRECEDENCE - 3)
|
||||||
public class AuthenticationManagerConfiguration extends
|
public class AuthenticationManagerConfiguration extends
|
||||||
GlobalAuthenticationConfigurerAdapter implements
|
GlobalAuthenticationConfigurerAdapter {
|
||||||
ApplicationListener<ContextRefreshedEvent> {
|
|
||||||
|
/*
|
||||||
|
* 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
|
private static Log logger = LogFactory
|
||||||
.getLog(AuthenticationManagerConfiguration.class);
|
.getLog(AuthenticationManagerConfiguration.class);
|
||||||
|
|
@ -62,43 +76,48 @@ public class AuthenticationManagerConfiguration extends
|
||||||
@Autowired
|
@Autowired
|
||||||
private List<SecurityPrequisite> dependencies;
|
private List<SecurityPrequisite> dependencies;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ObjectPostProcessor<Object> objectPostProcessor;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SecurityProperties security;
|
private SecurityProperties security;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationEventPublisher authenticationEventPublisher;
|
private ObjectPostProcessor<Object> objectPostProcessor;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Primary
|
@Primary
|
||||||
public AuthenticationManager authenticationManager() {
|
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth)
|
||||||
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
|
throws Exception {
|
||||||
|
/*
|
||||||
|
* This AuthenticationManagerBuilder is for the global AuthenticationManager
|
||||||
|
*/
|
||||||
|
BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter();
|
||||||
|
configurer.init(auth);
|
||||||
|
configurer.configure(auth);
|
||||||
|
AuthenticationManager manager = configurer.getAuthenticationManagerBuilder()
|
||||||
.getOrBuild();
|
.getOrBuild();
|
||||||
|
configurer.configureParent(auth);
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Component
|
||||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
protected static class AuthenticationManagerConfigurationListener implements
|
||||||
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
|
ApplicationListener<ContextRefreshedEvent> {
|
||||||
.getOrBuild();
|
|
||||||
if (manager instanceof ProviderManager) {
|
@Autowired
|
||||||
((ProviderManager) manager)
|
private AuthenticationEventPublisher authenticationEventPublisher;
|
||||||
.setAuthenticationEventPublisher(this.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();
|
.roles(roles.toArray(new String[roles.size()])).and().and().build();
|
||||||
|
|
||||||
// Defer actually setting the parent on the AuthenticationManagerBuilder
|
// 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.
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ public class SampleWebSecureApplication extends WebMvcConfigurerAdapter {
|
||||||
.password("admin").roles("ADMIN", "USER").and().withUser("user")
|
.password("admin").roles("ADMIN", "USER").and().withUser("user")
|
||||||
.password("user").roles("USER");
|
.password("user").roles("USER");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue