Skip to content

Commit 9902f98

Browse files
author
Dave Syer
committed
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
1 parent 0950072 commit 9902f98

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/AuthenticationManagerConfiguration.java

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2727
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2828
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
29+
import org.springframework.context.ApplicationContext;
2930
import org.springframework.context.ApplicationListener;
3031
import org.springframework.context.annotation.Bean;
3132
import org.springframework.context.annotation.Configuration;
@@ -41,9 +42,15 @@
4142
import org.springframework.security.config.annotation.SecurityConfigurer;
4243
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
4344
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
45+
import org.springframework.stereotype.Component;
4446

4547
/**
46-
* Configuration for a Spring Security in-memory {@link AuthenticationManager}.
48+
* Configuration for a Spring Security in-memory {@link AuthenticationManager}. Can be
49+
* disabled by providing a bean of type AuthenticationManager. The value provided by this
50+
* configuration will become the "global" authentication manager (from Spring Security),
51+
* or the parent of the global instance. Thus it acts as a fallback when no others are
52+
* provided, is used by method security if enabled, and as a parent authentication manager
53+
* for "local" authentication managers in individual filter chains.
4754
*
4855
* @author Dave Syer
4956
* @author Rob Winch
@@ -53,52 +60,64 @@
5360
@ConditionalOnMissingBean(AuthenticationManager.class)
5461
@Order(Ordered.LOWEST_PRECEDENCE - 3)
5562
public class AuthenticationManagerConfiguration extends
56-
GlobalAuthenticationConfigurerAdapter implements
57-
ApplicationListener<ContextRefreshedEvent> {
63+
GlobalAuthenticationConfigurerAdapter {
64+
65+
/*
66+
* Yes, this class is a GlobalAuthenticationConfigurerAdapter, even though none of
67+
* those methods are overridden: we want Spring Security to instantiate us early, so
68+
* we can in turn force the SecurityPrequisites to be instantiated. This will prevent
69+
* ordering issues between Spring Boot modules when they need to influence the default
70+
* security configuration.
71+
*/
5872

5973
private static Log logger = LogFactory
6074
.getLog(AuthenticationManagerConfiguration.class);
6175

6276
@Autowired
6377
private List<SecurityPrequisite> dependencies;
6478

65-
@Autowired
66-
private ObjectPostProcessor<Object> objectPostProcessor;
67-
6879
@Autowired
6980
private SecurityProperties security;
7081

7182
@Autowired
72-
private AuthenticationEventPublisher authenticationEventPublisher;
73-
74-
private BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter();
75-
76-
@Override
77-
public void init(AuthenticationManagerBuilder auth) throws Exception {
78-
auth.apply(this.configurer);
79-
}
80-
81-
@Override
82-
public void configure(AuthenticationManagerBuilder auth) throws Exception {
83-
this.configurer.configureParent(auth);
84-
}
83+
private ObjectPostProcessor<Object> objectPostProcessor;
8584

8685
@Bean
8786
@Primary
88-
public AuthenticationManager authenticationManager() {
89-
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
87+
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth)
88+
throws Exception {
89+
/*
90+
* This AuthenticationManagerBuilder is for the global AuthenticationManager
91+
*/
92+
BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter();
93+
configurer.init(auth);
94+
configurer.configure(auth);
95+
AuthenticationManager manager = configurer.getAuthenticationManagerBuilder()
9096
.getOrBuild();
97+
configurer.configureParent(auth);
9198
return manager;
9299
}
93100

94-
@Override
95-
public void onApplicationEvent(ContextRefreshedEvent event) {
96-
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
97-
.getOrBuild();
98-
if (manager instanceof ProviderManager) {
99-
((ProviderManager) manager)
100-
.setAuthenticationEventPublisher(this.authenticationEventPublisher);
101+
@Component
102+
protected static class AuthenticationManagerConfigurationListener implements
103+
ApplicationListener<ContextRefreshedEvent> {
104+
105+
@Autowired
106+
private AuthenticationEventPublisher authenticationEventPublisher;
107+
108+
@Override
109+
public void onApplicationEvent(ContextRefreshedEvent event) {
110+
ApplicationContext context = event.getApplicationContext();
111+
if (context.getBeanNamesForType(AuthenticationManager.class).length == 0) {
112+
return;
113+
}
114+
AuthenticationManager manager = context.getBean(AuthenticationManager.class);
115+
if (manager instanceof ProviderManager) {
116+
((ProviderManager) manager)
117+
.setAuthenticationEventPublisher(this.authenticationEventPublisher);
118+
}
101119
}
120+
102121
}
103122

104123
/**
@@ -163,7 +182,8 @@ public void configure(AuthenticationManagerBuilder auth) throws Exception {
163182
.roles(roles.toArray(new String[roles.size()])).and().and().build();
164183

165184
// Defer actually setting the parent on the AuthenticationManagerBuilder
166-
// because it makes it "configured" and we are only in the init() phase here.
185+
// because it makes it "configured" and we are only in the init() phase
186+
// here.
167187

168188
}
169189
}

spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/ui/secure/SampleWebSecureApplication.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public void init(AuthenticationManagerBuilder auth) throws Exception {
101101
.password("admin").roles("ADMIN", "USER").and().withUser("user")
102102
.password("user").roles("USER");
103103
}
104+
104105
}
105106

106107
}

0 commit comments

Comments
 (0)