SEC-2447: Fix AuthenticationManagerBuilder ordering issues
This commit is contained in:
parent
c42e13c966
commit
6c35c33abe
|
@ -35,6 +35,7 @@ dependencies {
|
||||||
"org.springframework:spring-orm:$springVersion",
|
"org.springframework:spring-orm:$springVersion",
|
||||||
"org.springframework:spring-tx:$springVersion",
|
"org.springframework:spring-tx:$springVersion",
|
||||||
"org.spockframework:spock-core:$spockVersion",
|
"org.spockframework:spock-core:$spockVersion",
|
||||||
|
"org.spockframework:spock-spring:$spockVersion",
|
||||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
||||||
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final",
|
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final",
|
||||||
"org.hibernate:hibernate-entitymanager:4.1.0.Final",
|
"org.hibernate:hibernate-entitymanager:4.1.0.Final",
|
||||||
|
@ -46,12 +47,15 @@ dependencies {
|
||||||
"org.apache.directory.server:apacheds-server-jndi:$apacheDsVersion",
|
"org.apache.directory.server:apacheds-server-jndi:$apacheDsVersion",
|
||||||
'org.apache.directory.shared:shared-ldap:0.9.15',
|
'org.apache.directory.shared:shared-ldap:0.9.15',
|
||||||
'ldapsdk:ldapsdk:4.1',
|
'ldapsdk:ldapsdk:4.1',
|
||||||
powerMockDependencies
|
powerMockDependencies,
|
||||||
|
"org.springframework.data:spring-data-jpa:1.2.0.RELEASE",
|
||||||
|
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final",
|
||||||
|
"org.hibernate:hibernate-entitymanager:3.6.10.Final",
|
||||||
|
"org.hsqldb:hsqldb:2.2.8"
|
||||||
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
|
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
|
||||||
exclude group: 'com.google.code.guice', module: 'guice'
|
exclude group: 'com.google.code.guice', module: 'guice'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
|
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
|
||||||
"cglib:cglib-nodep:2.2"
|
"cglib:cglib-nodep:2.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.springframework.security.authentication.ProviderManager;
|
||||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||||
|
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
|
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
|
||||||
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
|
||||||
|
@ -221,7 +222,7 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ProviderManager performBuild() throws Exception {
|
protected ProviderManager performBuild() throws Exception {
|
||||||
if(authenticationProviders.isEmpty() && parentAuthenticationManager == null) {
|
if(!isConfigured()) {
|
||||||
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
|
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -236,6 +237,26 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
|
||||||
return providerManager;
|
return providerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the {@link AuthenticationManagerBuilder} is configured to
|
||||||
|
* build a non null {@link AuthenticationManager}. This means that either a
|
||||||
|
* non-null parent is specified or at least one
|
||||||
|
* {@link AuthenticationProvider} has been specified.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* When using {@link SecurityConfigurer} instances, the
|
||||||
|
* {@link AuthenticationManagerBuilder} will not be configured until the
|
||||||
|
* {@link SecurityConfigurer#configure(SecurityBuilder)} methods. This means
|
||||||
|
* a {@link SecurityConfigurer} that is last could check this method and
|
||||||
|
* provide a default configuration in the
|
||||||
|
* {@link SecurityConfigurer#configure(SecurityBuilder)} method.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isConfigured() {
|
||||||
|
return !authenticationProviders.isEmpty() || parentAuthenticationManager != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default {@link UserDetailsService} for the
|
* Gets the default {@link UserDetailsService} for the
|
||||||
* {@link AuthenticationManagerBuilder}. The result may be null in some
|
* {@link AuthenticationManagerBuilder}. The result may be null in some
|
||||||
|
|
|
@ -15,10 +15,25 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.config.annotation.authentication.configuration;
|
package org.springframework.security.config.annotation.authentication.configuration;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.aop.framework.ProxyFactoryBean;
|
||||||
|
import org.springframework.aop.target.LazyInitTargetSource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
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.core.annotation.AnnotationAwareOrderComparator;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
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.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports the authentication {@link Configuration}
|
* Exports the authentication {@link Configuration}
|
||||||
|
@ -29,9 +44,98 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class AuthenticationConfiguration {
|
public class AuthenticationConfiguration {
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
private boolean authenticationManagerInitialized;
|
||||||
|
|
||||||
|
private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigures = Collections.emptyList();
|
||||||
|
|
||||||
|
private ObjectPostProcessor<Object> objectPostProcessor;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||||
return new AuthenticationManagerBuilder(objectPostProcessor);
|
return new AuthenticationManagerBuilder(objectPostProcessor);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Bean
|
||||||
|
public GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
|
||||||
|
return new EnableGlobalAuthenticationAutowiredConfigurer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationManager getAuthenticationManager() throws Exception {
|
||||||
|
if(authenticationManagerInitialized) {
|
||||||
|
return authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(objectPostProcessor);
|
||||||
|
for(GlobalAuthenticationConfigurerAdapter config : globalAuthConfigures) {
|
||||||
|
authBuilder.apply(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticationManager = authBuilder.build();
|
||||||
|
|
||||||
|
if(authenticationManager == null) {
|
||||||
|
authenticationManager = getAuthenticationMangerBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.authenticationManagerInitialized = true;
|
||||||
|
return authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
public void setGlobalAuthenticationConfigurers(List<GlobalAuthenticationConfigurerAdapter> configurers) throws Exception {
|
||||||
|
Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE);
|
||||||
|
this.globalAuthConfigures = configurers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||||
|
this.objectPostProcessor = objectPostProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> T lazyBean(Class<T> interfaceName) {
|
||||||
|
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
|
||||||
|
String[] beanNamesForType = applicationContext.getBeanNamesForType(interfaceName);
|
||||||
|
if(beanNamesForType.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Assert.isTrue(beanNamesForType.length == 1 , "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType));
|
||||||
|
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
|
||||||
|
lazyTargetSource.setBeanFactory(applicationContext);
|
||||||
|
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
|
||||||
|
proxyFactory.setTargetSource(lazyTargetSource);
|
||||||
|
proxyFactory.setInterfaces(new Class[] { interfaceName });
|
||||||
|
return (T) proxyFactory.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthenticationManager getAuthenticationMangerBean() {
|
||||||
|
return lazyBean(AuthenticationManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
private final ApplicationContext context;
|
||||||
|
private static final Log logger = LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
|
||||||
|
|
||||||
|
public EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(AuthenticationManagerBuilder auth) {
|
||||||
|
Map<String, Object> beansWithAnnotation = context.getBeansWithAnnotation(EnableGlobalAuthentication.class);
|
||||||
|
if(logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Eagerly initializing " + beansWithAnnotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.authentication.configuration;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link EnableGlobalAuthentication} annotation signals that the annotated
|
||||||
|
* class can be used to configure a global instance of
|
||||||
|
* {@link AuthenticationManagerBuilder}. For example:
|
||||||
|
*
|
||||||
|
* <pre class="code">
|
||||||
|
* @Configuration
|
||||||
|
* @EnableGlobalAuthentication
|
||||||
|
* public class MyGlobalAuthenticationConfiguration {
|
||||||
|
*
|
||||||
|
* @Autowired
|
||||||
|
* public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||||
|
* auth
|
||||||
|
* .inMemoryAuthentication()
|
||||||
|
* .withUser("user").password("password").roles("USER").and()
|
||||||
|
* .withUser("admin").password("password").roles("USER", "ADMIN");
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Annotations that are annotated with {@link EnableGlobalAuthentication} also
|
||||||
|
* signal that the annotated class can be used to configure a global instance of
|
||||||
|
* {@link AuthenticationManagerBuilder}. For example:
|
||||||
|
*
|
||||||
|
* <pre class="code">
|
||||||
|
* @Configuration
|
||||||
|
* @EnableWebSecurity
|
||||||
|
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||||
|
*
|
||||||
|
* @Autowired
|
||||||
|
* public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||||
|
* auth
|
||||||
|
* .inMemoryAuthentication()
|
||||||
|
* .withUser("user").password("password").roles("USER").and()
|
||||||
|
* .withUser("admin").password("password").roles("USER", "ADMIN");
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Possibly overridden methods ...
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* The following annotations are annotated with {@link EnableGlobalAuthentication}
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li> {@link EnableWebSecurity} </li>
|
||||||
|
* <li> {@link EnableWebMvcSecurity} </li>
|
||||||
|
* <li> {@link EnableGlobalMethodSecurity} </li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* Configuring {@link AuthenticationManagerBuilder} in a class without the {@link EnableGlobalAuthentication} annotation has
|
||||||
|
* unpredictable results.
|
||||||
|
*
|
||||||
|
* @see EnableWebMvcSecurity
|
||||||
|
* @see EnableWebSecurity
|
||||||
|
* @see EnableGlobalMethodSecurity
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||||
|
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||||
|
@Documented
|
||||||
|
@Import(AuthenticationConfiguration.class)
|
||||||
|
public @interface EnableGlobalAuthentication {}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.authentication.configurers;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SecurityConfigurer} that can be exposed as a bean to configure the
|
||||||
|
* global {@link AuthenticationManagerBuilder}. Beans of this type are
|
||||||
|
* automatically used by {@link AuthenticationConfiguration} to configure the
|
||||||
|
* global {@link AuthenticationManagerBuilder}.
|
||||||
|
*
|
||||||
|
* @since 3.2.1
|
||||||
|
* @author Rob Winch
|
||||||
|
*/
|
||||||
|
@Order(100)
|
||||||
|
public abstract class GlobalAuthenticationConfigurerAdapter implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
|
||||||
|
|
||||||
|
public void init(AuthenticationManagerBuilder auth) throws Exception {}
|
||||||
|
|
||||||
|
public void configure(AuthenticationManagerBuilder auth) throws Exception {}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ import org.springframework.context.annotation.AdviceMode;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.security.access.annotation.Secured;
|
import org.springframework.security.access.annotation.Secured;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,7 +44,8 @@ import org.springframework.security.config.annotation.configuration.ObjectPostPr
|
||||||
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||||
@Documented
|
@Documented
|
||||||
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class,AuthenticationConfiguration.class})
|
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class})
|
||||||
|
@EnableGlobalAuthentication
|
||||||
public @interface EnableGlobalMethodSecurity {
|
public @interface EnableGlobalMethodSecurity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,19 +16,14 @@
|
||||||
package org.springframework.security.config.annotation.method.configuration;
|
package org.springframework.security.config.annotation.method.configuration;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.aop.framework.ProxyFactoryBean;
|
|
||||||
import org.springframework.aop.target.LazyInitTargetSource;
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
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.ImportAware;
|
import org.springframework.context.annotation.ImportAware;
|
||||||
|
@ -67,6 +62,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
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.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,7 +77,6 @@ import org.springframework.util.Assert;
|
||||||
@Configuration
|
@Configuration
|
||||||
public class GlobalMethodSecurityConfiguration implements ImportAware {
|
public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||||
private static final Log logger = LogFactory.getLog(GlobalMethodSecurityConfiguration.class);
|
private static final Log logger = LogFactory.getLog(GlobalMethodSecurityConfiguration.class);
|
||||||
private ApplicationContext context;
|
|
||||||
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
|
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
|
||||||
public <T> T postProcess(T object) {
|
public <T> T postProcess(T object) {
|
||||||
throw new IllegalStateException(ObjectPostProcessor.class.getName()+ " is a required bean. Ensure you have used @"+EnableGlobalMethodSecurity.class.getName());
|
throw new IllegalStateException(ObjectPostProcessor.class.getName()+ " is a required bean. Ensure you have used @"+EnableGlobalMethodSecurity.class.getName());
|
||||||
|
@ -93,6 +88,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||||
private boolean disableAuthenticationRegistry;
|
private boolean disableAuthenticationRegistry;
|
||||||
private AnnotationAttributes enableMethodSecurity;
|
private AnnotationAttributes enableMethodSecurity;
|
||||||
private MethodSecurityExpressionHandler expressionHandler;
|
private MethodSecurityExpressionHandler expressionHandler;
|
||||||
|
private AuthenticationConfiguration authenticationConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the default MethodInterceptor which is a MethodSecurityInterceptor using the following methods to
|
* Creates the default MethodInterceptor which is a MethodSecurityInterceptor using the following methods to
|
||||||
|
@ -248,19 +244,11 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||||
auth = new AuthenticationManagerBuilder(objectPostProcessor);
|
auth = new AuthenticationManagerBuilder(objectPostProcessor);
|
||||||
auth.authenticationEventPublisher(eventPublisher);
|
auth.authenticationEventPublisher(eventPublisher);
|
||||||
configure(auth);
|
configure(auth);
|
||||||
if(!disableAuthenticationRegistry) {
|
if(disableAuthenticationRegistry) {
|
||||||
|
authenticationManager = getAuthenticationConfiguration().getAuthenticationManager();
|
||||||
|
} else {
|
||||||
authenticationManager = auth.build();
|
authenticationManager = auth.build();
|
||||||
}
|
}
|
||||||
if(authenticationManager == null) {
|
|
||||||
try {
|
|
||||||
authenticationManager = context.getBean(AuthenticationManagerBuilder.class).getOrBuild();
|
|
||||||
} catch(NoSuchBeanDefinitionException e) {
|
|
||||||
logger.debug("Could not obtain the AuthenticationManagerBuilder. This is ok for now, we will try using an AuthenticationManager directly",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(authenticationManager == null) {
|
|
||||||
authenticationManager = lazyBean(AuthenticationManager.class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return authenticationManager;
|
return authenticationManager;
|
||||||
}
|
}
|
||||||
|
@ -351,11 +339,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||||
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
|
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public void setApplicationContext(ApplicationContext context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired(required=false)
|
@Autowired(required=false)
|
||||||
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||||
this.objectPostProcessor = objectPostProcessor;
|
this.objectPostProcessor = objectPostProcessor;
|
||||||
|
@ -370,17 +353,14 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||||
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators.get(0));
|
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@Autowired(required = false)
|
||||||
private <T> T lazyBean(Class<T> interfaceName) {
|
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
|
||||||
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
|
this.authenticationConfiguration = authenticationConfiguration;
|
||||||
String[] beanNamesForType = context.getBeanNamesForType(interfaceName);
|
}
|
||||||
Assert.isTrue(beanNamesForType.length == 1 , "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType));
|
|
||||||
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
|
private AuthenticationConfiguration getAuthenticationConfiguration() {
|
||||||
lazyTargetSource.setBeanFactory(context);
|
Assert.notNull(authenticationConfiguration, "authenticationConfiguration cannot be null");
|
||||||
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
|
return authenticationConfiguration;
|
||||||
proxyFactory.setTargetSource(lazyTargetSource);
|
|
||||||
proxyFactory.setInterfaces(new Class[] { interfaceName });
|
|
||||||
return (T) proxyFactory.getObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean prePostEnabled() {
|
private boolean prePostEnabled() {
|
||||||
|
@ -414,5 +394,4 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
|
||||||
}
|
}
|
||||||
return this.enableMethodSecurity;
|
return this.enableMethodSecurity;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
|
@ -20,7 +20,7 @@ import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||||
|
|
||||||
|
@ -77,7 +77,8 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||||
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||||
@Documented
|
@Documented
|
||||||
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class,AuthenticationConfiguration.class})
|
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class})
|
||||||
|
@EnableGlobalAuthentication
|
||||||
public @interface EnableWebSecurity {
|
public @interface EnableWebSecurity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
@ -31,6 +30,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolverIm
|
||||||
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
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.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
|
@ -43,6 +43,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private AuthenticationConfiguration authenticationConfiguration;
|
||||||
private AuthenticationManagerBuilder authenticationBuilder;
|
private AuthenticationManagerBuilder authenticationBuilder;
|
||||||
private AuthenticationManagerBuilder parentAuthenticationBuilder;
|
private AuthenticationManagerBuilder parentAuthenticationBuilder;
|
||||||
private boolean disableAuthenticationRegistration;
|
private boolean disableAuthenticationRegistration;
|
||||||
|
@ -221,18 +223,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||||
if(!authenticationManagerInitialized) {
|
if(!authenticationManagerInitialized) {
|
||||||
configure(parentAuthenticationBuilder);
|
configure(parentAuthenticationBuilder);
|
||||||
if(disableAuthenticationRegistration) {
|
if(disableAuthenticationRegistration) {
|
||||||
try {
|
authenticationManager = authenticationConfiguration.getAuthenticationManager();
|
||||||
authenticationManager = context.getBean(AuthenticationManagerBuilder.class).getOrBuild();
|
|
||||||
} catch(NoSuchBeanDefinitionException e) {
|
|
||||||
logger.debug("Could not obtain the AuthenticationManagerBuilder. This is ok for now, we will try using an AuthenticationManager directly",e);
|
|
||||||
}
|
|
||||||
if(authenticationManager == null) {
|
|
||||||
try {
|
|
||||||
authenticationManager = context.getBean(AuthenticationManager.class);
|
|
||||||
} catch(NoSuchBeanDefinitionException e) {
|
|
||||||
logger.debug("The AuthenticationManager was not found. This is ok for now as it may not be required.",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
authenticationManager = parentAuthenticationBuilder.build();
|
authenticationManager = parentAuthenticationBuilder.build();
|
||||||
}
|
}
|
||||||
|
@ -341,7 +332,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||||
this.contentNegotiationStrategy = contentNegotiationStrategy;
|
this.contentNegotiationStrategy = contentNegotiationStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired(required=false)
|
@Autowired
|
||||||
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||||
this.objectPostProcessor = objectPostProcessor;
|
this.objectPostProcessor = objectPostProcessor;
|
||||||
|
|
||||||
|
@ -356,6 +347,10 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
|
||||||
|
this.authenticationConfiguration = authenticationConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delays the use of the {@link UserDetailsService} from the
|
* Delays the use of the {@link UserDetailsService} from the
|
||||||
|
@ -416,8 +411,9 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
|
||||||
private AuthenticationManager delegate;
|
private AuthenticationManager delegate;
|
||||||
private final Object delegateMonitor = new Object();
|
private final Object delegateMonitor = new Object();
|
||||||
|
|
||||||
AuthenticationManagerDelegator(AuthenticationManagerBuilder authentication) {
|
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
|
||||||
this.delegateBuilder = authentication;
|
Assert.notNull(delegateBuilder,"delegateBuilder cannot be null");
|
||||||
|
this.delegateBuilder = delegateBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,5 +34,6 @@ import org.springframework.context.annotation.Import;
|
||||||
@Target(value={java.lang.annotation.ElementType.TYPE})
|
@Target(value={java.lang.annotation.ElementType.TYPE})
|
||||||
@Documented
|
@Documented
|
||||||
@Import(WebMvcSecurityConfiguration.class)
|
@Import(WebMvcSecurityConfiguration.class)
|
||||||
|
@EnableGlobalAuthentication
|
||||||
public @interface EnableWebMvcSecurity {
|
public @interface EnableWebMvcSecurity {
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,4 +52,4 @@ public class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
|
||||||
public RequestDataValueProcessor requestDataValueProcessor() {
|
public RequestDataValueProcessor requestDataValueProcessor() {
|
||||||
return new CsrfRequestDataValueProcessor();
|
return new CsrfRequestDataValueProcessor();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -87,4 +87,37 @@ class AuthenticationManagerBuilderTests extends BaseSpringSpec {
|
||||||
.withUser("admin").password("password").roles("USER","ADMIN")
|
.withUser("admin").password("password").roles("USER","ADMIN")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "isConfigured with AuthenticationProvider"() {
|
||||||
|
setup:
|
||||||
|
ObjectPostProcessor opp = Mock()
|
||||||
|
AuthenticationProvider provider = Mock()
|
||||||
|
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||||
|
when:
|
||||||
|
auth
|
||||||
|
.authenticationProvider(provider)
|
||||||
|
then:
|
||||||
|
auth.isConfigured()
|
||||||
|
}
|
||||||
|
|
||||||
|
def "isConfigured with parent"() {
|
||||||
|
setup:
|
||||||
|
ObjectPostProcessor opp = Mock()
|
||||||
|
AuthenticationManager parent = Mock()
|
||||||
|
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||||
|
when:
|
||||||
|
auth
|
||||||
|
.parentAuthenticationManager(parent)
|
||||||
|
then:
|
||||||
|
auth.isConfigured()
|
||||||
|
}
|
||||||
|
|
||||||
|
def "isConfigured not configured"() {
|
||||||
|
setup:
|
||||||
|
ObjectPostProcessor opp = Mock()
|
||||||
|
when:
|
||||||
|
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
|
||||||
|
then:
|
||||||
|
auth.isConfigured() == false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.authentication.configuration;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import org.springframework.core.Ordered
|
||||||
|
import org.springframework.core.annotation.Order
|
||||||
|
import org.springframework.security.access.annotation.Secured
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
||||||
|
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter
|
||||||
|
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
|
||||||
|
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity
|
||||||
|
import org.springframework.security.core.AuthenticationException
|
||||||
|
import org.springframework.security.core.authority.AuthorityUtils
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder
|
||||||
|
import org.springframework.security.core.userdetails.User
|
||||||
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||||
|
|
||||||
|
class AuthenticationConfigurationTests extends BaseSpringSpec {
|
||||||
|
|
||||||
|
def "Ordering Autowired on EnableGlobalMethodSecurity"() {
|
||||||
|
setup:
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||||
|
when:
|
||||||
|
loadConfig(GlobalMethodSecurityAutowiredConfigAndServicesConfig)
|
||||||
|
then:
|
||||||
|
context.getBean(Service).run()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import([GlobalMethodSecurityAutowiredConfig,ServicesConfig])
|
||||||
|
static class GlobalMethodSecurityAutowiredConfigAndServicesConfig {}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||||
|
static class GlobalMethodSecurityAutowiredConfig {
|
||||||
|
@Autowired
|
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||||
|
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def "Ordering Autowired on EnableWebSecurity"() {
|
||||||
|
setup:
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||||
|
when:
|
||||||
|
loadConfig(GlobalMethodSecurityConfigAndServicesConfig)
|
||||||
|
then:
|
||||||
|
context.getBean(Service).run()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import([GlobalMethodSecurityConfig,WebSecurityConfig,ServicesConfig])
|
||||||
|
static class GlobalMethodSecurityConfigAndServicesConfig {}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||||
|
static class GlobalMethodSecurityConfig {}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Autowired
|
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||||
|
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
def "Ordering Autowired on EnableWebMvcSecurity"() {
|
||||||
|
setup:
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
|
||||||
|
when:
|
||||||
|
loadConfig(GlobalMethodSecurityMvcSecurityAndServicesConfig)
|
||||||
|
then:
|
||||||
|
context.getBean(Service).run()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import([GlobalMethodSecurityConfig,WebMvcSecurityConfig,ServicesConfig])
|
||||||
|
static class GlobalMethodSecurityMvcSecurityAndServicesConfig {}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvcSecurity
|
||||||
|
static class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Autowired
|
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||||
|
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
def "no authentication getAuthenticationManager falls back to null"() {
|
||||||
|
when:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||||
|
then:
|
||||||
|
context.getBean(AuthenticationConfiguration).authenticationManager == null
|
||||||
|
}
|
||||||
|
|
||||||
|
def "QuiesentGlobalAuthenticationConfiguererAdapter falls back to null"() {
|
||||||
|
when:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,QuiesentGlobalAuthenticationConfiguererAdapter)
|
||||||
|
then:
|
||||||
|
context.getBean(AuthenticationConfiguration).authenticationManager == null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class QuiesentGlobalAuthenticationConfiguererAdapter extends GlobalAuthenticationConfigurerAdapter {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
def "GlobalAuthenticationConfiguererAdapterImpl configures authentication successfully"() {
|
||||||
|
setup:
|
||||||
|
def token = new UsernamePasswordAuthenticationToken("user", "password")
|
||||||
|
when:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,GlobalAuthenticationConfiguererAdapterImpl)
|
||||||
|
then:
|
||||||
|
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token)?.name == "user"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class GlobalAuthenticationConfiguererAdapterImpl extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
def "AuthenticationManagerBean configures authentication successfully"() {
|
||||||
|
setup:
|
||||||
|
def token = new UsernamePasswordAuthenticationToken("user", "password")
|
||||||
|
def auth = new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||||
|
AuthenticationManagerBeanConfig.AM = Mock(AuthenticationManager)
|
||||||
|
1 * AuthenticationManagerBeanConfig.AM.authenticate(token) >> auth
|
||||||
|
when:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,AuthenticationManagerBeanConfig)
|
||||||
|
then:
|
||||||
|
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token).name == auth.name
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class AuthenticationManagerBeanConfig {
|
||||||
|
static AuthenticationManager AM
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager() {
|
||||||
|
AM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class ServicesConfig {
|
||||||
|
@Bean
|
||||||
|
public Service service() {
|
||||||
|
return new ServiceImpl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface Service {
|
||||||
|
public void run();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ServiceImpl implements Service {
|
||||||
|
@Secured("ROLE_USER")
|
||||||
|
public void run() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
def "GlobalAuthenticationConfigurerAdapter are ordered"() {
|
||||||
|
setup:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||||
|
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||||
|
config.setGlobalAuthenticationConfigurers([new LowestOrderGlobalAuthenticationConfigurerAdapter(), new HighestOrderGlobalAuthenticationConfigurerAdapter(), new DefaultOrderGlobalAuthenticationConfigurerAdapter()])
|
||||||
|
when:
|
||||||
|
config.getAuthenticationManager()
|
||||||
|
then:
|
||||||
|
DefaultOrderGlobalAuthenticationConfigurerAdapter.inits == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
|
||||||
|
DefaultOrderGlobalAuthenticationConfigurerAdapter.configs == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
static List inits = []
|
||||||
|
static List configs = []
|
||||||
|
|
||||||
|
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
inits.add(getClass())
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
configs.add(getClass())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
|
||||||
|
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
static class HighestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
def "Spring Boot not triggered when already configured"() {
|
||||||
|
setup:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||||
|
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||||
|
config.setGlobalAuthenticationConfigurers([new ConfiguresInMemoryConfigurerAdapter(), new BootGlobalAuthenticationConfigurerAdapter()])
|
||||||
|
AuthenticationManager authenticationManager = config.authenticationManager
|
||||||
|
when:
|
||||||
|
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
|
||||||
|
then:
|
||||||
|
noExceptionThrown()
|
||||||
|
when:
|
||||||
|
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
|
||||||
|
then:
|
||||||
|
thrown(AuthenticationException)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def "Spring Boot is triggered when not already configured"() {
|
||||||
|
setup:
|
||||||
|
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
|
||||||
|
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
|
||||||
|
config.setGlobalAuthenticationConfigurers([new BootGlobalAuthenticationConfigurerAdapter()])
|
||||||
|
AuthenticationManager authenticationManager = config.authenticationManager
|
||||||
|
when:
|
||||||
|
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
|
||||||
|
then:
|
||||||
|
noExceptionThrown()
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
|
||||||
|
|
||||||
|
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth
|
||||||
|
.inMemoryAuthentication()
|
||||||
|
.withUser("user").password("password").roles("USER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
|
||||||
|
public void init(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DefaultBootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
|
||||||
|
@Override
|
||||||
|
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
if(auth.isConfigured()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User("boot","password", AuthorityUtils.createAuthorityList("ROLE_USER"))
|
||||||
|
|
||||||
|
List<User> users = Arrays.asList(user);
|
||||||
|
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
|
||||||
|
|
||||||
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
|
||||||
|
provider.userDetailsService = inMemory
|
||||||
|
|
||||||
|
auth.authenticationProvider(provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.issue50;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
import org.springframework.orm.jpa.vendor.Database;
|
||||||
|
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||||
|
import org.springframework.security.config.annotation.issue50.domain.User;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableJpaRepositories("org.springframework.security.config.annotation.issue50.repo")
|
||||||
|
@EnableTransactionManagement
|
||||||
|
public class ApplicationConfig {
|
||||||
|
@Bean
|
||||||
|
public DataSource dataSource() {
|
||||||
|
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
||||||
|
return builder.setType(EmbeddedDatabaseType.HSQL).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||||
|
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||||
|
vendorAdapter.setDatabase(Database.HSQL);
|
||||||
|
vendorAdapter.setGenerateDdl(true);
|
||||||
|
vendorAdapter.setShowSql(true);
|
||||||
|
|
||||||
|
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
|
||||||
|
factory.setJpaVendorAdapter(vendorAdapter);
|
||||||
|
factory.setPackagesToScan(User.class.getPackage().getName());
|
||||||
|
factory.setDataSource(dataSource());
|
||||||
|
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager transactionManager() {
|
||||||
|
JpaTransactionManager txManager = new JpaTransactionManager();
|
||||||
|
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
||||||
|
return txManager;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.issue50;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.security.access.AccessDeniedException
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||||
|
import org.springframework.security.config.annotation.issue50.domain.User
|
||||||
|
import org.springframework.security.config.annotation.issue50.repo.UserRepository
|
||||||
|
import org.springframework.security.core.Authentication
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
||||||
|
import org.springframework.security.web.FilterChainProxy
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@ContextConfiguration(classes=[ApplicationConfig,SecurityConfig])
|
||||||
|
@Transactional
|
||||||
|
class Issue50Tests extends Specification {
|
||||||
|
@Autowired
|
||||||
|
private FilterChainProxy springSecurityFilterChain
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationManager authenticationManager
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepo
|
||||||
|
|
||||||
|
def setup() {
|
||||||
|
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_ADMIN")
|
||||||
|
}
|
||||||
|
|
||||||
|
def cleanup() {
|
||||||
|
SecurityContextHolder.clearContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/SpringSource/spring-security-javaconfig/issues/50
|
||||||
|
def "#50 - GlobalMethodSecurityConfiguration should load AuthenticationManager lazily"() {
|
||||||
|
when:
|
||||||
|
"Configuration Loads"
|
||||||
|
then: "GlobalMethodSecurityConfiguration loads AuthenticationManager lazily"
|
||||||
|
noExceptionThrown()
|
||||||
|
}
|
||||||
|
|
||||||
|
def "AuthenticationManager will not authenticate missing user"() {
|
||||||
|
when:
|
||||||
|
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("test", "password"))
|
||||||
|
then:
|
||||||
|
thrown(UsernameNotFoundException)
|
||||||
|
}
|
||||||
|
|
||||||
|
def "AuthenticationManager will not authenticate with invalid password"() {
|
||||||
|
when:
|
||||||
|
User user = new User(username:"test",password:"password")
|
||||||
|
userRepo.save(user)
|
||||||
|
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , "invalid"))
|
||||||
|
then:
|
||||||
|
thrown(BadCredentialsException)
|
||||||
|
}
|
||||||
|
|
||||||
|
def "AuthenticationManager can be used to authenticate a user"() {
|
||||||
|
when:
|
||||||
|
User user = new User(username:"test",password:"password")
|
||||||
|
userRepo.save(user)
|
||||||
|
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
|
||||||
|
then:
|
||||||
|
result.principal == user.username
|
||||||
|
}
|
||||||
|
|
||||||
|
def "Global Method Security is enabled and works"() {
|
||||||
|
setup:
|
||||||
|
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_USER")
|
||||||
|
when:
|
||||||
|
User user = new User(username:"denied",password:"password")
|
||||||
|
userRepo.save(user)
|
||||||
|
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
|
||||||
|
then:
|
||||||
|
thrown(AccessDeniedException)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.issue50;
|
||||||
|
|
||||||
|
import org.spockframework.util.Assert;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.issue50.domain.User;
|
||||||
|
import org.springframework.security.config.annotation.issue50.repo.UserRepository;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
|
@Configuration
|
||||||
|
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
@Autowired
|
||||||
|
private UserRepository myUserRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth
|
||||||
|
.authenticationProvider(authenticationProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers("/*").permitAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
public AuthenticationManager authenticationManagerBean()
|
||||||
|
throws Exception {
|
||||||
|
return super.authenticationManagerBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationProvider authenticationProvider() {
|
||||||
|
Assert.notNull(myUserRepository);
|
||||||
|
return new AuthenticationProvider() {
|
||||||
|
public boolean supports(Class<?> authentication) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public Authentication authenticate(Authentication authentication)
|
||||||
|
throws AuthenticationException {
|
||||||
|
Object principal = authentication.getPrincipal();
|
||||||
|
String username = String.valueOf(principal);
|
||||||
|
User user = myUserRepository.findByUsername(username);
|
||||||
|
if(user == null) {
|
||||||
|
throw new UsernameNotFoundException("No user for principal "+principal);
|
||||||
|
}
|
||||||
|
if(!authentication.getCredentials().equals(user.getPassword())) {
|
||||||
|
throw new BadCredentialsException("Invalid password");
|
||||||
|
}
|
||||||
|
return new TestingAuthenticationToken(principal, null, "ROLE_USER");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.issue50.domain;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.config.annotation.issue50.repo;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.config.annotation.issue50.domain.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface UserRepository extends CrudRepository<User, String> {
|
||||||
|
|
||||||
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
|
User findByUsername(String username);
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
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.TestingAuthenticationToken;
|
||||||
import org.springframework.security.config.annotation.BaseSpringSpec
|
import org.springframework.security.config.annotation.BaseSpringSpec
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
@ -36,11 +37,13 @@ import org.springframework.stereotype.Component
|
||||||
class Issue55Tests extends BaseSpringSpec {
|
class Issue55Tests extends BaseSpringSpec {
|
||||||
|
|
||||||
def "WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
def "WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
||||||
|
setup:
|
||||||
|
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
|
||||||
when:
|
when:
|
||||||
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
||||||
then:
|
then:
|
||||||
context.getBean(FilterChainProxy)
|
context.getBean(FilterChainProxy)
|
||||||
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
|
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -66,12 +69,14 @@ class Issue55Tests extends BaseSpringSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
def "multi http WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
def "multi http WebSecurityConfigurerAdapter defaults to @Autowired"() {
|
||||||
|
setup:
|
||||||
|
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
|
||||||
when:
|
when:
|
||||||
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
|
||||||
then:
|
then:
|
||||||
context.getBean(FilterChainProxy)
|
context.getBean(FilterChainProxy)
|
||||||
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
|
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||||
findFilter(FilterSecurityInterceptor,1).authenticationManager.parent.class == CustomAuthenticationManager
|
findFilter(FilterSecurityInterceptor,1).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -107,8 +112,9 @@ class Issue55Tests extends BaseSpringSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class CustomAuthenticationManager implements AuthenticationManager {
|
static class CustomAuthenticationManager implements AuthenticationManager {
|
||||||
|
static Authentication RESULT = new TestingAuthenticationToken("test", "this","ROLE_USER")
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
return null;
|
return RESULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
NOTE: The name of the configureGlobal method is not important. However, it is important to only configure AuthenticationManagerBuilder in a class annotated with either `@EnableWebSecurity`, `@EnableWebMvcSecurity`, `@EnableGlobalMethodSecurity`, or `@EnableGlobalAuthentication`. Doing otherwise has unpredictable results.
|
||||||
|
|
||||||
[[servlet-api-integration]]
|
[[servlet-api-integration]]
|
||||||
The <<security-config-java,SecurityConfig>> will:
|
The <<security-config-java,SecurityConfig>> will:
|
||||||
|
|
||||||
|
|
|
@ -431,6 +431,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
NOTE: The name of the configureGlobal method is not important. However, it is important to only configure AuthenticationManagerBuilder in a class annotated with either `@EnableWebSecurity`, `@EnableWebMvcSecurity`, `@EnableGlobalMethodSecurity`, or `@EnableGlobalAuthentication`. Doing otherwise has unpredictable results.
|
||||||
|
|
||||||
There really isn't much to this configuration, but it does a lot. You can find a summary of the features below:
|
There really isn't much to this configuration, but it does a lot. You can find a summary of the features below:
|
||||||
|
|
||||||
* Require authentication to every URL in your application
|
* Require authentication to every URL in your application
|
||||||
|
|
Loading…
Reference in New Issue