Register an AuthenticationManager in security autoconfig
This is quite a big step, but I think it helps a lot. Since Spring Boot always creates an AuthenticationManager if it doesn't find one already registered, it makes sense to also make it into a @Bean. Spring Security does not register its AuthenticationManager by default though, so we have to do that for it if the user has created one with an @Autowired AuthenticationManagerBuilder, but not registered it as a @Bean. Having the @Bean (marked @Primary to prevent issues with @Autowired) makes it easier to reason about what Spring Boot has done for you, and easier to default in simple use cases to the boot-created AuthenticationManager. For example, if I want an OAuth2 Authorization Server with password grant, it makes total sense for the AuthenticationManager for users to be the same as the @Primary one. Now it is easy to set that up (just @Autowire it).
This commit is contained in:
@@ -40,10 +40,19 @@ public abstract class SpringBootCondition implements Condition {
|
||||
@Override
|
||||
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
String classOrMethodName = getClassOrMethodName(metadata);
|
||||
ConditionOutcome outcome = getMatchOutcome(context, metadata);
|
||||
logOutcome(classOrMethodName, outcome);
|
||||
recordEvaluation(context, classOrMethodName, outcome);
|
||||
return outcome.isMatch();
|
||||
try {
|
||||
ConditionOutcome outcome = getMatchOutcome(context, metadata);
|
||||
logOutcome(classOrMethodName, outcome);
|
||||
recordEvaluation(context, classOrMethodName, outcome);
|
||||
return outcome.isMatch();
|
||||
}
|
||||
catch (NoClassDefFoundError e) {
|
||||
throw new IllegalStateException(
|
||||
"Could not evaluate condition owing to internal class not found. "
|
||||
+ "This can happen if you are @ComponentScanning a springframework package "
|
||||
+ "(e.g. if you put a @ComponentScan in the default package by mistake)",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getClassOrMethodName(AnnotatedTypeMetadata metadata) {
|
||||
|
||||
@@ -26,7 +26,12 @@ 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.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
@@ -60,9 +65,25 @@ public class AuthenticationManagerConfiguration extends
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
private BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter();
|
||||
|
||||
@Override
|
||||
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.apply(new BootDefaultingAuthenticationConfigurerAdapter());
|
||||
auth.apply(this.configurer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
// avoid issues with scopedTarget (SPR-11548)
|
||||
@Primary
|
||||
public AuthenticationManager authenticationManager() {
|
||||
return lazyAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
|
||||
protected AuthenticationManager lazyAuthenticationManager() {
|
||||
return this.configurer.getAuthenticationManagerBuilder().getOrBuild();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,9 +113,16 @@ public class AuthenticationManagerConfiguration extends
|
||||
private class BootDefaultingAuthenticationConfigurerAdapter extends
|
||||
GlobalAuthenticationConfigurerAdapter {
|
||||
|
||||
private AuthenticationManagerBuilder defaultAuth;
|
||||
|
||||
public AuthenticationManagerBuilder getAuthenticationManagerBuilder() {
|
||||
return this.defaultAuth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
if (auth.isConfigured()) {
|
||||
this.defaultAuth = auth;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,12 +132,12 @@ public class AuthenticationManagerConfiguration extends
|
||||
+ user.getPassword() + "\n\n");
|
||||
}
|
||||
|
||||
AuthenticationManagerBuilder defaultAuth = new AuthenticationManagerBuilder(
|
||||
this.defaultAuth = new AuthenticationManagerBuilder(
|
||||
AuthenticationManagerConfiguration.this.objectPostProcessor);
|
||||
|
||||
Set<String> roles = new LinkedHashSet<String>(user.getRole());
|
||||
|
||||
AuthenticationManager parent = defaultAuth.inMemoryAuthentication()
|
||||
AuthenticationManager parent = this.defaultAuth.inMemoryAuthentication()
|
||||
.withUser(user.getName()).password(user.getPassword())
|
||||
.roles(roles.toArray(new String[roles.size()])).and().and().build();
|
||||
|
||||
|
||||
@@ -19,15 +19,11 @@ package org.springframework.boot.autoconfigure.security;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
|
||||
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
||||
import org.springframework.boot.logging.LoggingApplicationListener;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -60,7 +56,7 @@ public class SecurityAutoConfigurationTests {
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
debugRefresh(this.context);
|
||||
this.context.refresh();
|
||||
assertNotNull(this.context.getBean(AuthenticationManagerBuilder.class));
|
||||
// 4 for static resources and one for the rest
|
||||
List<SecurityFilterChain> filterChains = this.context.getBean(
|
||||
@@ -93,6 +89,16 @@ public class SecurityAutoConfigurationTests {
|
||||
assertEquals(0, this.context.getBeanNamesForType(FilterChainProxy.class).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationManagerCreated() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertNotNull(this.context.getBean(AuthenticationManager.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideAuthenticationManager() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
@@ -118,18 +124,6 @@ public class SecurityAutoConfigurationTests {
|
||||
assertNotNull(this.context.getBean(JpaTransactionManager.class));
|
||||
}
|
||||
|
||||
private static AnnotationConfigWebApplicationContext debugRefresh(
|
||||
AnnotationConfigWebApplicationContext context) {
|
||||
EnvironmentTestUtils.addEnvironment(context, "debug:true");
|
||||
LoggingApplicationListener logging = new LoggingApplicationListener();
|
||||
logging.onApplicationEvent(new ApplicationPreparedEvent(new SpringApplication(),
|
||||
new String[0], context));
|
||||
AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
|
||||
initializer.initialize(context);
|
||||
context.refresh();
|
||||
return context;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
protected static class EntityConfiguration {
|
||||
|
||||
Reference in New Issue
Block a user