Update to Spring Security 3.2.1
Also change strategy for defaulting of Authentication. Spring Boot authentication defaults are now encapsulated and can easily be overridden by a user defined AuthenticationManager.
This commit is contained in:
parent
13e040c06e
commit
6b0eba3759
Notes:
Phillip Webb
2014-03-03 21:40:33 -08:00
Fixes gh-338
|
|
@ -292,16 +292,21 @@ Try it out:
|
||||||
The default auto configuration has an in-memory user database with one
|
The default auto configuration has an in-memory user database with one
|
||||||
entry, and the `<password>` value has to be read from the logs (at
|
entry, and the `<password>` value has to be read from the logs (at
|
||||||
INFO level) by default. If you want to extend or expand that, or
|
INFO level) by default. If you want to extend or expand that, or
|
||||||
point to a database or directory server, you only need to provide a
|
point to a database or directory server, you can add the `@EnableGlobalAuthentication`
|
||||||
`@Bean` definition for an `AuthenticationManager`, e.g. in your
|
annotation and configure the global `AuthenticationManagerBuilder` as shown below:
|
||||||
`SampleController`:
|
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
@EnableGlobalAuthentication
|
||||||
|
public class SampleController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.inMemoryAuthentication()
|
||||||
|
.withUser("client").password("secret").roles("USER");
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired
|
...
|
||||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
|
||||||
auth.inMemoryAuthentication()
|
|
||||||
.withUser("client").password("secret").roles("USER");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Try it out:
|
Try it out:
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,9 @@ public class ManagementSecurityAutoConfigurationTests {
|
||||||
|
|
||||||
private UserDetails getUser() {
|
private UserDetails getUser() {
|
||||||
ProviderManager manager = this.context.getBean(ProviderManager.class);
|
ProviderManager manager = this.context.getBean(ProviderManager.class);
|
||||||
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) manager
|
ProviderManager parent = (ProviderManager) ReflectionTestUtils.getField(
|
||||||
|
manager, "parent");
|
||||||
|
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) parent
|
||||||
.getProviders().get(0);
|
.getProviders().get(0);
|
||||||
UserDetailsService service = (UserDetailsService) ReflectionTestUtils.getField(
|
UserDetailsService service = (UserDetailsService) ReflectionTestUtils.getField(
|
||||||
provider, "userDetailsService");
|
provider, "userDetailsService");
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,26 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.security;
|
package org.springframework.boot.autoconfigure.security;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
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.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for a Spring Security in-memory {@link AuthenticationManager}.
|
* Configuration for a Spring Security in-memory {@link AuthenticationManager}.
|
||||||
|
|
@ -41,26 +47,77 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
@ConditionalOnMissingBean(AuthenticationManager.class)
|
@ConditionalOnMissingBean(AuthenticationManager.class)
|
||||||
@ConditionalOnWebApplication
|
@ConditionalOnWebApplication
|
||||||
@Order(Ordered.LOWEST_PRECEDENCE - 3)
|
@Order(Ordered.LOWEST_PRECEDENCE - 3)
|
||||||
public class AuthenticationManagerConfiguration implements
|
public class AuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter {
|
||||||
WebSecurityConfigurer<WebSecurity> {
|
|
||||||
|
|
||||||
@Autowired
|
private static Log logger = LogFactory.getLog(AuthenticationManagerConfiguration.class);
|
||||||
private SecurityProperties security;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private List<SecurityPrequisite> dependencies;
|
private List<SecurityPrequisite> dependencies;
|
||||||
|
|
||||||
@Override
|
@Autowired
|
||||||
public void init(WebSecurity builder) throws Exception {
|
private ObjectPostProcessor<Object> objectPostProcessor;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(WebSecurity builder) throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void authentication(AuthenticationManagerBuilder builder) throws Exception {
|
private SecurityProperties security;
|
||||||
SecurityAutoConfiguration.authentication(builder, this.security);
|
|
||||||
|
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.apply(new BootDefaultingAuthenticationConfigurerAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We must add {@link BootDefaultingAuthenticationConfigurerAdapter} in the
|
||||||
|
* init phase of the last {@link GlobalAuthenticationConfigurerAdapter}. The
|
||||||
|
* reason is that the typical flow is something like:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>A
|
||||||
|
* {@link GlobalAuthenticationConfigurerAdapter#init(AuthenticationManagerBuilder)}
|
||||||
|
* exists that adds a {@link SecurityConfigurer} to the
|
||||||
|
* {@link AuthenticationManagerBuilder}</li>
|
||||||
|
* <li>
|
||||||
|
* {@link AuthenticationManagerConfiguration#init(AuthenticationManagerBuilder)}
|
||||||
|
* adds BootDefaultingAuthenticationConfigurerAdapter so it is after the
|
||||||
|
* {@link SecurityConfigurer} in the first step</li>
|
||||||
|
* <li>We then can default an {@link AuthenticationProvider} if necessary.
|
||||||
|
* Note we can only invoke the
|
||||||
|
* {@link AuthenticationManagerBuilder#authenticationProvider(AuthenticationProvider)}
|
||||||
|
* method since all other methods add a {@link SecurityConfigurer} which is
|
||||||
|
* not allowed in the configure stage. It is not allowed because we
|
||||||
|
* guarantee all init methods are invoked before configure, which cannot be
|
||||||
|
* guaranteed at this point.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
*/
|
||||||
|
private class BootDefaultingAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(AuthenticationManagerBuilder auth)
|
||||||
|
throws Exception {
|
||||||
|
if(auth.isConfigured()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = AuthenticationManagerConfiguration.this.security.getUser();
|
||||||
|
if (user.isDefaultPassword()) {
|
||||||
|
logger.info("\n\nUsing default password for application endpoints: "
|
||||||
|
+ user.getPassword() + "\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthenticationManagerBuilder defaultAuth = new AuthenticationManagerBuilder(objectPostProcessor);
|
||||||
|
|
||||||
|
Set<String> roles = new LinkedHashSet<String>(user.getRole());
|
||||||
|
|
||||||
|
AuthenticationManager parent = defaultAuth.
|
||||||
|
inMemoryAuthentication()
|
||||||
|
.withUser(user.getName())
|
||||||
|
.password(user.getPassword())
|
||||||
|
.roles(roles.toArray(new String[roles.size()]))
|
||||||
|
.and()
|
||||||
|
.and()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
auth.parentAuthenticationManager(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,28 +16,15 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.security;
|
package org.springframework.boot.autoconfigure.security;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
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.security.SecurityProperties.User;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security. Provides an
|
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security. Provides an
|
||||||
|
|
@ -58,68 +45,9 @@ import org.springframework.util.ReflectionUtils;
|
||||||
@Import({ SpringBootWebSecurityConfiguration.class,
|
@Import({ SpringBootWebSecurityConfiguration.class,
|
||||||
AuthenticationManagerConfiguration.class })
|
AuthenticationManagerConfiguration.class })
|
||||||
public class SecurityAutoConfiguration {
|
public class SecurityAutoConfiguration {
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(SecurityAutoConfiguration.class);
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public SecurityProperties securityProperties() {
|
public SecurityProperties securityProperties() {
|
||||||
return new SecurityProperties();
|
return new SecurityProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnBean(AuthenticationManagerBuilder.class)
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public AuthenticationManager authenticationManager(
|
|
||||||
AuthenticationManagerBuilder builder, ObjectPostProcessor<Object> processor)
|
|
||||||
throws Exception {
|
|
||||||
if (!isBuilt(builder)) {
|
|
||||||
authentication(builder, securityProperties());
|
|
||||||
}
|
|
||||||
else if (builder.getOrBuild() == null) {
|
|
||||||
builder = new AuthenticationManagerBuilder(processor);
|
|
||||||
authentication(builder, securityProperties());
|
|
||||||
}
|
|
||||||
return builder.getOrBuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for building the default AuthenticationManager from
|
|
||||||
* SecurityProperties.
|
|
||||||
*
|
|
||||||
* @param builder the AuthenticationManagerBuilder to use
|
|
||||||
* @param security the SecurityProperties in use
|
|
||||||
*/
|
|
||||||
public static void authentication(AuthenticationManagerBuilder builder,
|
|
||||||
SecurityProperties security) throws Exception {
|
|
||||||
|
|
||||||
if (isBuilt(builder)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
User user = security.getUser();
|
|
||||||
|
|
||||||
if (user.isDefaultPassword()) {
|
|
||||||
logger.info("\n\nUsing default password for application endpoints: "
|
|
||||||
+ user.getPassword() + "\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> roles = new LinkedHashSet<String>(user.getRole());
|
|
||||||
|
|
||||||
builder.inMemoryAuthentication().withUser(user.getName())
|
|
||||||
.password(user.getPassword())
|
|
||||||
.roles(roles.toArray(new String[roles.size()]));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isBuilt(AuthenticationManagerBuilder builder) {
|
|
||||||
Method configurers = ReflectionUtils.findMethod(
|
|
||||||
AbstractConfiguredSecurityBuilder.class, "getConfigurers");
|
|
||||||
Method unbuilt = ReflectionUtils.findMethod(
|
|
||||||
AbstractConfiguredSecurityBuilder.class, "isUnbuilt");
|
|
||||||
ReflectionUtils.makeAccessible(configurers);
|
|
||||||
ReflectionUtils.makeAccessible(unbuilt);
|
|
||||||
return !((Collection<?>) ReflectionUtils.invokeMethod(configurers, builder))
|
|
||||||
.isEmpty() || !((Boolean) ReflectionUtils.invokeMethod(unbuilt, builder));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue