SEC-1126: separated out spring-security-config module containing namespace configuration classes and resources
This commit is contained in:
-82
@@ -1,82 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String CACHE_REF = "cache-ref";
|
||||
public static final String CACHING_SUFFIX = ".caching";
|
||||
|
||||
/** UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */
|
||||
private String id;
|
||||
|
||||
protected abstract String getBeanClassName(Element element);
|
||||
|
||||
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClassName(element));
|
||||
|
||||
doParse(element, parserContext, builder);
|
||||
|
||||
RootBeanDefinition userService = (RootBeanDefinition) builder.getBeanDefinition();
|
||||
String beanId = resolveId(element, userService, parserContext);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(beanId, userService);
|
||||
|
||||
String cacheRef = element.getAttribute(CACHE_REF);
|
||||
|
||||
// Register a caching version of the user service if there's a cache-ref
|
||||
if (StringUtils.hasText(cacheRef)) {
|
||||
BeanDefinitionBuilder cachingUSBuilder = BeanDefinitionBuilder.rootBeanDefinition(CachingUserDetailsService.class);
|
||||
cachingUSBuilder.addConstructorArgReference(beanId);
|
||||
|
||||
cachingUSBuilder.addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
|
||||
BeanDefinition cachingUserService = cachingUSBuilder.getBeanDefinition();
|
||||
parserContext.getRegistry().registerBeanDefinition(beanId + CACHING_SUFFIX, cachingUserService);
|
||||
}
|
||||
|
||||
id = beanId;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
String id = element.getAttribute("id");
|
||||
|
||||
if (StringUtils.hasText(id)) {
|
||||
return id;
|
||||
}
|
||||
|
||||
if(Elements.AUTHENTICATION_PROVIDER.equals(element.getParentNode().getNodeName())) {
|
||||
return parserContext.getReaderContext().generateBeanName(definition);
|
||||
}
|
||||
|
||||
// If top level, use the default name or throw an exception if already used
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
|
||||
throw new BeanDefinitionStoreException("No id supplied and another " +
|
||||
"bean is already registered as " + BeanIds.USER_DETAILS_SERVICE);
|
||||
}
|
||||
|
||||
return BeanIds.USER_DETAILS_SERVICE;
|
||||
}
|
||||
|
||||
String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider;
|
||||
import org.springframework.security.providers.anonymous.AnonymousProcessingFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @version $Id: RememberMeBeanDefinitionParser.java 2231 2007-11-07 13:29:15Z luke_t $
|
||||
*/
|
||||
public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_KEY = "key";
|
||||
static final String DEF_KEY = "doesNotMatter";
|
||||
|
||||
static final String ATT_USERNAME = "username";
|
||||
static final String DEF_USERNAME = "roleAnonymous";
|
||||
|
||||
static final String ATT_GRANTED_AUTHORITY = "granted-authority";
|
||||
static final String DEF_GRANTED_AUTHORITY = "ROLE_ANONYMOUS";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String grantedAuthority = null;
|
||||
String username = null;
|
||||
String key = null;
|
||||
Object source = null;
|
||||
|
||||
if (element != null) {
|
||||
grantedAuthority = element.getAttribute(ATT_GRANTED_AUTHORITY);
|
||||
username = element.getAttribute(ATT_USERNAME);
|
||||
key = element.getAttribute(ATT_KEY);
|
||||
source = parserContext.extractSource(element);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(grantedAuthority)) {
|
||||
grantedAuthority = DEF_GRANTED_AUTHORITY;
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(username)) {
|
||||
username = DEF_USERNAME;
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
key = DEF_KEY;
|
||||
}
|
||||
|
||||
RootBeanDefinition filter = new RootBeanDefinition(AnonymousProcessingFilter.class);
|
||||
|
||||
filter.setSource(source);
|
||||
filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority);
|
||||
filter.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
provider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filter, BeanIds.ANONYMOUS_PROCESSING_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Registers an alias name for the default ProviderManager used by the namespace
|
||||
* configuration, allowing users to reference it in their beans and clearly see where the name is
|
||||
* coming from. Also allows the ConcurrentSessionController to be set on the ProviderManager.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String ATT_SESSION_CONTROLLER_REF = "session-controller-ref";
|
||||
private static final String ATT_ALIAS = "alias";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
String alias = element.getAttribute(ATT_ALIAS);
|
||||
|
||||
if (!StringUtils.hasText(alias)) {
|
||||
parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element );
|
||||
}
|
||||
|
||||
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
|
||||
|
||||
if (StringUtils.hasText(sessionControllerRef)) {
|
||||
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
|
||||
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController",
|
||||
new RuntimeBeanReference(sessionControllerRef));
|
||||
RootBeanDefinition sessionRegistryInjector = new RootBeanDefinition(SessionRegistryInjectionBeanPostProcessor.class);
|
||||
sessionRegistryInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
sessionRegistryInjector.getConstructorArgumentValues().addGenericArgumentValue(sessionControllerRef);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_REGISTRY_INJECTION_POST_PROCESSOR, sessionRegistryInjector);
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.providers.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Wraps a UserDetailsService bean with a DaoAuthenticationProvider and registers the latter with the
|
||||
* ProviderManager.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static String ATT_USER_DETAILS_REF = "user-service-ref";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
|
||||
authProvider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
authProvider.setSource(parserContext.extractSource(element));
|
||||
|
||||
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
|
||||
|
||||
if (passwordEncoderElt != null) {
|
||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
|
||||
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
|
||||
if (pep.getSaltSource() != null) {
|
||||
authProvider.getPropertyValues().addPropertyValue("saltSource", pep.getSaltSource());
|
||||
}
|
||||
}
|
||||
|
||||
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
|
||||
Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
|
||||
Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
|
||||
|
||||
// We need to register the provider to access it in the post processor to check if it has a cache
|
||||
final String id = parserContext.getReaderContext().generateBeanName(authProvider);
|
||||
parserContext.getRegistry().registerBeanDefinition(id, authProvider);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(authProvider, id));
|
||||
|
||||
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
|
||||
|
||||
if (StringUtils.hasText(ref)) {
|
||||
if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
|
||||
parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
|
||||
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
|
||||
Elements.LDAP_USER_SERVICE + "'", element);
|
||||
}
|
||||
} else {
|
||||
// Use the child elements to create the UserDetailsService
|
||||
AbstractUserDetailsServiceBeanDefinitionParser parser = null;
|
||||
Element elt = null;
|
||||
|
||||
if (userServiceElt != null) {
|
||||
elt = userServiceElt;
|
||||
parser = new UserServiceBeanDefinitionParser();
|
||||
} else if (jdbcUserServiceElt != null) {
|
||||
elt = jdbcUserServiceElt;
|
||||
parser = new JdbcUserServiceBeanDefinitionParser();
|
||||
} else if (ldapUserServiceElt != null) {
|
||||
elt = ldapUserServiceElt;
|
||||
parser = new LdapUserServiceBeanDefinitionParser();
|
||||
} else {
|
||||
parserContext.getReaderContext().error("A user-service is required", element);
|
||||
}
|
||||
|
||||
parser.parse(elt, parserContext);
|
||||
ref = parser.getId();
|
||||
}
|
||||
|
||||
authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));
|
||||
|
||||
BeanDefinitionBuilder cacheResolverBldr = BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProviderCacheResolver.class);
|
||||
cacheResolverBldr.addConstructorArgValue(id);
|
||||
cacheResolverBldr.addConstructorArgValue(ref);
|
||||
cacheResolverBldr.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
BeanDefinition cacheResolver = cacheResolverBldr.getBeanDefinition();
|
||||
|
||||
String name = parserContext.getReaderContext().generateBeanName(cacheResolver);
|
||||
parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
|
||||
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the registered user service bean has an associated cache and, if so, sets it on the
|
||||
* authentication provider.
|
||||
*/
|
||||
static class AuthenticationProviderCacheResolver implements BeanFactoryPostProcessor, Ordered {
|
||||
private String providerId;
|
||||
private String userServiceId;
|
||||
|
||||
public AuthenticationProviderCacheResolver(String providerId, String userServiceId) {
|
||||
this.providerId = providerId;
|
||||
this.userServiceId = userServiceId;
|
||||
}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
RootBeanDefinition provider = (RootBeanDefinition) beanFactory.getBeanDefinition(providerId);
|
||||
|
||||
String cachingId = userServiceId + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
RootBeanDefinition cachingUserService = (RootBeanDefinition) beanFactory.getBeanDefinition(cachingId);
|
||||
|
||||
PropertyValue userCacheProperty = cachingUserService.getPropertyValues().getPropertyValue("userCache");
|
||||
|
||||
provider.getPropertyValues().addPropertyValue(userCacheProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilterEntryPoint;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Creates a {@link BasicProcessingFilter} and {@link BasicProcessingFilterEntryPoint} and
|
||||
* registers them in the application context.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private String realmName;
|
||||
|
||||
public BasicAuthenticationBeanDefinitionParser(String realmName) {
|
||||
this.realmName = realmName;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class);
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class);
|
||||
entryPoint.setSource(parserContext.extractSource(elt));
|
||||
entryPoint.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realmName);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, entryPoint);
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.BASIC_AUTHENTICATION_FILTER,
|
||||
filterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.BASIC_AUTHENTICATION_FILTER));
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(),
|
||||
BeanIds.BASIC_AUTHENTICATION_FILTER));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* Contains globally used default Bean IDs for beans created by the namespace support in Spring Security 2.
|
||||
* <p>
|
||||
* These are intended for internal use.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class BeanIds {
|
||||
|
||||
/** External alias for FilterChainProxy bean, for use in web.xml files */
|
||||
public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";
|
||||
|
||||
/** Package protected as end users shouldn't really be using this BFPP directly */
|
||||
static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
|
||||
static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
|
||||
static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
|
||||
static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
|
||||
static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";
|
||||
static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
|
||||
static final String FILTER_LIST = "_filterChainList";
|
||||
|
||||
public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
|
||||
public static final String USER_DETAILS_SERVICE = "_userDetailsService";
|
||||
public static final String ANONYMOUS_PROCESSING_FILTER = "_anonymousProcessingFilter";
|
||||
public static final String ANONYMOUS_AUTHENTICATION_PROVIDER = "_anonymousAuthenticationProvider";
|
||||
public static final String BASIC_AUTHENTICATION_FILTER = "_basicAuthenticationFilter";
|
||||
public static final String BASIC_AUTHENTICATION_ENTRY_POINT = "_basicAuthenticationEntryPoint";
|
||||
public static final String SESSION_REGISTRY = "_sessionRegistry";
|
||||
public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
|
||||
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
|
||||
public static final String METHOD_ACCESS_MANAGER = "_defaultMethodAccessManager";
|
||||
public static final String WEB_ACCESS_MANAGER = "_webAccessManager";
|
||||
public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
|
||||
public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";
|
||||
public static final String FORM_LOGIN_FILTER = "_formLoginFilter";
|
||||
public static final String FORM_LOGIN_ENTRY_POINT = "_formLoginEntryPoint";
|
||||
public static final String OPEN_ID_FILTER = "_openIDFilter";
|
||||
public static final String OPEN_ID_ENTRY_POINT = "_openIDFilterEntryPoint";
|
||||
public static final String OPEN_ID_PROVIDER = "_openIDAuthenticationProvider";
|
||||
public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";
|
||||
public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
|
||||
public static final String SECURITY_CONTEXT_PERSISTENCE_FILTER = "_securityContextPersistenceFilter";
|
||||
public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
|
||||
public static final String LOGOUT_FILTER = "_logoutFilter";
|
||||
public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
|
||||
public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
|
||||
public static final String CHANNEL_PROCESSING_FILTER = "_channelProcessingFilter";
|
||||
public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
|
||||
public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
|
||||
public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
|
||||
public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
|
||||
public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
|
||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = "_methodSecurityMetadataSourceAdvisor";
|
||||
public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
|
||||
public static final String SECURED_METHOD_SECURITY_METADATA_SOURCE = "_securedSecurityMetadataSource";
|
||||
public static final String JSR_250_METHOD_SECURITY_METADATA_SOURCE = "_jsr250SecurityMetadataSource";
|
||||
public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";
|
||||
public static final String CONTEXT_SOURCE = "_securityContextSource";
|
||||
public static final String PORT_MAPPER = "_portMapper";
|
||||
public static final String X509_FILTER = "_x509ProcessingFilter";
|
||||
public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider";
|
||||
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
|
||||
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.providers.dao.UserCache;
|
||||
import org.springframework.security.providers.dao.cache.NullUserCache;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0
|
||||
*/
|
||||
class CachingUserDetailsService implements UserDetailsService {
|
||||
private UserCache userCache = new NullUserCache();
|
||||
private UserDetailsService delegate;
|
||||
|
||||
CachingUserDetailsService(UserDetailsService delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public UserCache getUserCache() {
|
||||
return userCache;
|
||||
}
|
||||
|
||||
public void setUserCache(UserCache userCache) {
|
||||
this.userCache = userCache;
|
||||
}
|
||||
|
||||
public UserDetails loadUserByUsername(String username) {
|
||||
UserDetails user = userCache.getUserFromCache(username);
|
||||
|
||||
if (user == null) {
|
||||
user = delegate.loadUserByUsername(username);
|
||||
}
|
||||
|
||||
Assert.notNull(user, "UserDetailsService " + delegate + " returned null for username " + username + ". " +
|
||||
"This is an interface contract violation");
|
||||
|
||||
userCache.putUserInCache(user);
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionFilter;
|
||||
import org.springframework.security.concurrent.SessionRegistryImpl;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Sets up support for concurrent session support control, creating {@link ConcurrentSessionFilter},
|
||||
* {@link SessionRegistryImpl} and {@link ConcurrentSessionControllerImpl}. The session controller is also registered
|
||||
* with the default {@link ProviderManager} (which is automatically registered during namespace configuration).
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
static final String ATT_EXPIRY_URL = "expired-url";
|
||||
static final String ATT_MAX_SESSIONS = "max-sessions";
|
||||
static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded";
|
||||
static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
|
||||
static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
CompositeComponentDefinition compositeDef =
|
||||
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
|
||||
parserContext.pushContainingComponent(compositeDef);
|
||||
|
||||
BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
|
||||
|
||||
String sessionRegistryId = element.getAttribute(ATT_SESSION_REGISTRY_REF);
|
||||
|
||||
if (!StringUtils.hasText(sessionRegistryId)) {
|
||||
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
|
||||
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
|
||||
sessionRegistryId = BeanIds.SESSION_REGISTRY;
|
||||
} else {
|
||||
// Register the default ID as an alias so that things like session fixation filter can access it
|
||||
beanRegistry.registerAlias(sessionRegistryId, BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
|
||||
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
|
||||
if (StringUtils.hasText(registryAlias)) {
|
||||
beanRegistry.registerAlias(sessionRegistryId, registryAlias);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
|
||||
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
|
||||
|
||||
Object source = parserContext.extractSource(element);
|
||||
filterBuilder.getRawBeanDefinition().setSource(source);
|
||||
filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
String expiryUrl = element.getAttribute(ATT_EXPIRY_URL);
|
||||
|
||||
if (StringUtils.hasText(expiryUrl)) {
|
||||
ConfigUtils.validateHttpRedirect(expiryUrl, parserContext, source);
|
||||
filterBuilder.addPropertyValue("expiredUrl", expiryUrl);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder controllerBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
|
||||
controllerBuilder.getRawBeanDefinition().setSource(source);
|
||||
controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
|
||||
|
||||
String maxSessions = element.getAttribute(ATT_MAX_SESSIONS);
|
||||
|
||||
if (StringUtils.hasText(maxSessions)) {
|
||||
controllerBuilder.addPropertyValue("maximumSessions", maxSessions);
|
||||
}
|
||||
|
||||
String exceptionIfMaximumExceeded = element.getAttribute(ATT_EXCEPTION_IF_MAX_EXCEEDED);
|
||||
|
||||
if (StringUtils.hasText(exceptionIfMaximumExceeded)) {
|
||||
controllerBuilder.addPropertyValue("exceptionIfMaximumExceeded", exceptionIfMaximumExceeded);
|
||||
}
|
||||
|
||||
BeanDefinition controller = controllerBuilder.getBeanDefinition();
|
||||
|
||||
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_CONTROLLER, controller);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER));
|
||||
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_FILTER, filterBuilder.getBeanDefinition());
|
||||
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER));
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
|
||||
|
||||
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
|
||||
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||
import org.springframework.security.expression.method.MethodExpressionVoter;
|
||||
import org.springframework.security.util.UrlUtils;
|
||||
import org.springframework.security.vote.AccessDecisionVoter;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Utility methods used internally by the Spring Security namespace configuration code.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
abstract class ConfigUtils {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static void registerDefaultMethodAccessManagerIfNecessary(ParserContext parserContext) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER)) {
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER,
|
||||
createAccessManagerBean(MethodExpressionVoter.class, RoleVoter.class, AuthenticatedVoter.class));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static BeanDefinition createAccessManagerBean(Class<? extends AccessDecisionVoter>... voters) {
|
||||
ManagedList defaultVoters = new ManagedList(voters.length);
|
||||
|
||||
for(Class<? extends AccessDecisionVoter> voter : voters) {
|
||||
defaultVoters.add(new RootBeanDefinition(voter));
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
|
||||
accessMgrBuilder.addPropertyValue("decisionVoters", defaultVoters);
|
||||
return accessMgrBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
public static int countNonEmpty(String[] objects) {
|
||||
int nonNulls = 0;
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (StringUtils.hasText(objects[i])) {
|
||||
nonNulls++;
|
||||
}
|
||||
}
|
||||
|
||||
return nonNulls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and registers the bean definition for the default ProviderManager instance and returns
|
||||
* the BeanDefinition for it. This method will typically be called when registering authentication providers
|
||||
* using the <security:provider /> tag or by other beans which have a dependency on the
|
||||
* authentication manager.
|
||||
*/
|
||||
static void registerProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
|
||||
authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList<String>());
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static void addAuthenticationProvider(ParserContext parserContext, String beanName) {
|
||||
registerProviderManagerIfNecessary(parserContext);
|
||||
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
|
||||
BeanDefinition manager = registerAfterInvocationProviderManagerIfNecessary(parserContext);
|
||||
return (ManagedList) manager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static BeanDefinition registerAfterInvocationProviderManagerIfNecessary(ParserContext parserContext) {
|
||||
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
return parserContext.getRegistry().getBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER);
|
||||
}
|
||||
|
||||
BeanDefinition manager = new RootBeanDefinition(AfterInvocationProviderManager.class);
|
||||
manager.getPropertyValues().addPropertyValue("providers", new ManagedList());
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.AFTER_INVOCATION_MANAGER, manager);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
private static void registerFilterChainPostProcessorIfNecessary(ParserContext pc) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR)) {
|
||||
return;
|
||||
}
|
||||
// Post processor specifically to assemble and order the filter chain immediately before the FilterChainProxy is initialized.
|
||||
RootBeanDefinition filterChainPostProcessor = new RootBeanDefinition(FilterChainProxyPostProcessor.class);
|
||||
filterChainPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_POST_PROCESSOR, filterChainPostProcessor);
|
||||
RootBeanDefinition filterList = new RootBeanDefinition(FilterChainList.class);
|
||||
filterList.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_LIST, filterList);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static void addHttpFilter(ParserContext pc, BeanMetadataElement filter) {
|
||||
registerFilterChainPostProcessorIfNecessary(pc);
|
||||
|
||||
RootBeanDefinition filterList = (RootBeanDefinition) pc.getRegistry().getBeanDefinition(BeanIds.FILTER_LIST);
|
||||
|
||||
ManagedList filters;
|
||||
MutablePropertyValues pvs = filterList.getPropertyValues();
|
||||
if (pvs.contains("filters")) {
|
||||
filters = (ManagedList) pvs.getPropertyValue("filters").getValue();
|
||||
} else {
|
||||
filters = new ManagedList();
|
||||
pvs.addPropertyValue("filters", filters);
|
||||
}
|
||||
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which holds the list of filters which are maintained in the context and modified by calls to
|
||||
* addHttpFilter. The post processor retrieves these before injecting the list into the FilterChainProxy.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static class FilterChainList {
|
||||
List filters;
|
||||
|
||||
public List getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public void setFilters(List filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the value of an XML attribute which represents a redirect URL.
|
||||
* If not empty or starting with "$" (potential placeholder), "/" or "http" it will raise an error.
|
||||
*/
|
||||
static void validateHttpRedirect(String url, ParserContext pc, Object source) {
|
||||
if (!StringUtils.hasText(url) || UrlUtils.isValidRedirectUrl(url) || url.startsWith("$")) {
|
||||
return;
|
||||
}
|
||||
pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
|
||||
}
|
||||
|
||||
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
|
||||
registerProviderManagerIfNecessary(pc);
|
||||
BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
|
||||
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
|
||||
|
||||
if (pv != null && pv.getValue() != null) {
|
||||
pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
|
||||
"The <concurrent-session-control> element isn't compatible with a custom session controller",
|
||||
pc.extractSource(sourceElt));
|
||||
}
|
||||
|
||||
authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName));
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated {@link org.springframework.security.afterinvocation.AfterInvocationProvider} to the
|
||||
* AfterInvocationProviderManager's list.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class CustomAfterInvocationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(holder.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated {@link org.springframework.security.providers.AuthenticationProvider} to the ProviderManager's
|
||||
* list.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CustomAuthenticationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, holder.getBeanName());
|
||||
|
||||
return holder;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* Contains all the element names used by Spring Security 2 namespace support.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class Elements {
|
||||
|
||||
public static final String AUTHENTICATION_MANAGER = "authentication-manager";
|
||||
public static final String USER_SERVICE = "user-service";
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
public static final String LDAP_SERVER = "ldap-server";
|
||||
public static final String LDAP_USER_SERVICE = "ldap-user-service";
|
||||
public static final String PROTECT_POINTCUT = "protect-pointcut";
|
||||
public static final String EXPRESSION_HANDLER = "expression-handler";
|
||||
public static final String PROTECT = "protect";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
|
||||
public static final String LOGOUT = "logout";
|
||||
public static final String FORM_LOGIN = "form-login";
|
||||
public static final String OPENID_LOGIN = "openid-login";
|
||||
public static final String BASIC_AUTH = "http-basic";
|
||||
public static final String REMEMBER_ME = "remember-me";
|
||||
public static final String ANONYMOUS = "anonymous";
|
||||
public static final String FILTER_CHAIN = "filter-chain";
|
||||
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
|
||||
public static final String PASSWORD_ENCODER = "password-encoder";
|
||||
public static final String SALT_SOURCE = "salt-source";
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String PORT_MAPPING = "port-mapping";
|
||||
public static final String CUSTOM_FILTER = "custom-filter";
|
||||
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String X509 = "x509";
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class EntryPointInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (!BeanIds.EXCEPTION_TRANSLATION_FILTER.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
|
||||
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
Object entryPoint = null;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.MAIN_ENTRY_POINT)) {
|
||||
entryPoint = beanFactory.getBean(BeanIds.MAIN_ENTRY_POINT);
|
||||
logger.info("Using main configured AuthenticationEntryPoint.");
|
||||
} else {
|
||||
Map entryPoints = beanFactory.getBeansOfType(AuthenticationEntryPoint.class);
|
||||
Assert.isTrue(entryPoints.size() != 0, "No AuthenticationEntryPoint instances defined");
|
||||
Assert.isTrue(entryPoints.size() == 1, "More than one AuthenticationEntryPoint defined in context");
|
||||
entryPoint = entryPoints.values().toArray()[0];
|
||||
}
|
||||
|
||||
logger.info("Using bean '" + entryPoint + "' as the entry point.");
|
||||
etf.setAuthenticationEntryPoint((AuthenticationEntryPoint) entryPoint);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Sets the filter chain Map for a FilterChainProxy bean declaration.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
BeanDefinition filterChainProxy = holder.getBeanDefinition();
|
||||
|
||||
Map filterChainMap = new LinkedHashMap();
|
||||
Element elt = (Element)node;
|
||||
|
||||
String pathType = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_TYPE);
|
||||
|
||||
if (HttpSecurityBeanDefinitionParser.OPT_PATH_TYPE_REGEX.equals(pathType)) {
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", new RegexUrlPathMatcher());
|
||||
}
|
||||
|
||||
List<Element> filterChainElts = DomUtils.getChildElementsByTagName(elt, Elements.FILTER_CHAIN);
|
||||
|
||||
for (Element chain : filterChainElts) {
|
||||
String path = chain.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_PATTERN);
|
||||
String filters = chain.getAttribute(HttpSecurityBeanDefinitionParser.ATT_FILTERS);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
parserContext.getReaderContext().error("The attribute '" + HttpSecurityBeanDefinitionParser.ATT_PATH_PATTERN +
|
||||
"' must not be empty", elt);
|
||||
}
|
||||
|
||||
if(!StringUtils.hasText(filters)) {
|
||||
parserContext.getReaderContext().error("The attribute '" + HttpSecurityBeanDefinitionParser.ATT_FILTERS +
|
||||
"'must not be empty", elt);
|
||||
}
|
||||
|
||||
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
|
||||
filterChainMap.put(path, Collections.EMPTY_LIST);
|
||||
} else {
|
||||
String[] filterBeanNames = StringUtils.tokenizeToStringArray(filters, ",");
|
||||
ManagedList filterChain = new ManagedList(filterBeanNames.length);
|
||||
|
||||
for (int i=0; i < filterBeanNames.length; i++) {
|
||||
filterChain.add(new RuntimeBeanReference(filterBeanNames[i]));
|
||||
}
|
||||
|
||||
filterChainMap.put(path, filterChain);
|
||||
}
|
||||
}
|
||||
|
||||
ManagedMap map = new ManagedMap(filterChainMap.size());
|
||||
map.putAll(filterChainMap);
|
||||
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", map);
|
||||
|
||||
return holder;
|
||||
}
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.config.ConfigUtils.FilterChainList;
|
||||
import org.springframework.security.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.intercept.web.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.providers.anonymous.AnonymousProcessingFilter;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) bean;
|
||||
FilterChainList filterList = (FilterChainList) beanFactory.getBean(BeanIds.FILTER_LIST);
|
||||
|
||||
List<Filter> filters = new ArrayList<Filter>(filterList.getFilters());
|
||||
Collections.sort(filters, new OrderComparator());
|
||||
|
||||
logger.info("Checking sorted filter chain: " + filters);
|
||||
|
||||
for(int i=0; i < filters.size(); i++) {
|
||||
Ordered filter = (Ordered)filters.get(i);
|
||||
|
||||
if (i > 0) {
|
||||
Ordered previous = (Ordered)filters.get(i-1);
|
||||
if (filter.getOrder() == previous.getOrder()) {
|
||||
throw new SecurityConfigurationException("Filters '" + unwrapFilter(filter) + "' and '" +
|
||||
unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " +
|
||||
"please make sure the positions do not conflict with default filters. " +
|
||||
"Alternatively you can disable the default filters by removing the corresponding " +
|
||||
"child elements from <http> and avoiding the use of <http auto-config='true'>.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Filter chain...");
|
||||
for (int i=0; i < filters.size(); i++) {
|
||||
// Remove the ordered wrapper from the filter and put it back in the chain at the same position.
|
||||
Filter filter = unwrapFilter(filters.get(i));
|
||||
logger.info("[" + i + "] - " + filter);
|
||||
filters.set(i, filter);
|
||||
}
|
||||
|
||||
checkFilterStack(filters);
|
||||
|
||||
// Note that this returns a copy
|
||||
Map<String, List<Filter>> filterMap = filterChainProxy.getFilterChainMap();
|
||||
filterMap.put(filterChainProxy.getMatcher().getUniversalMatchPattern(), filters);
|
||||
filterChainProxy.setFilterChainMap(filterMap);
|
||||
|
||||
checkLoginPageIsntProtected(filterChainProxy);
|
||||
|
||||
logger.info("FilterChainProxy: " + filterChainProxy);
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the filter list for possible errors and logs them
|
||||
*/
|
||||
private void checkFilterStack(List<Filter> filters) {
|
||||
checkForDuplicates(SecurityContextPersistenceFilter.class, filters);
|
||||
checkForDuplicates(AuthenticationProcessingFilter.class, filters);
|
||||
checkForDuplicates(SessionFixationProtectionFilter.class, filters);
|
||||
checkForDuplicates(BasicProcessingFilter.class, filters);
|
||||
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
|
||||
checkForDuplicates(ExceptionTranslationFilter.class, filters);
|
||||
checkForDuplicates(FilterSecurityInterceptor.class, filters);
|
||||
}
|
||||
|
||||
private void checkForDuplicates(Class<? extends Filter> clazz, List<Filter> filters) {
|
||||
for (int i=0; i < filters.size(); i++) {
|
||||
Filter f1 = filters.get(i);
|
||||
if (clazz.isAssignableFrom(f1.getClass())) {
|
||||
// Found the first one, check remaining for another
|
||||
for (int j=i+1; j < filters.size(); j++) {
|
||||
Filter f2 = filters.get(j);
|
||||
if (clazz.isAssignableFrom(f2.getClass())) {
|
||||
logger.warn("Possible error: Filters at position " + i + " and " + j + " are both " +
|
||||
"instances of " + clazz.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks for the common error of having a login page URL protected by the security interceptor */
|
||||
private void checkLoginPageIsntProtected(FilterChainProxy fcp) {
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) beanFactory.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
|
||||
if (etf.getAuthenticationEntryPoint() instanceof AuthenticationProcessingFilterEntryPoint) {
|
||||
String loginPage =
|
||||
((AuthenticationProcessingFilterEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
|
||||
List<Filter> filters = fcp.getFilters(loginPage);
|
||||
logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
|
||||
|
||||
if (filters == null || filters.isEmpty()) {
|
||||
logger.debug("Filter chain is empty for the login page");
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginPage.equals(DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL) &&
|
||||
beanFactory.containsBean(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER)) {
|
||||
logger.debug("Default generated login page is in use");
|
||||
return;
|
||||
}
|
||||
|
||||
FilterSecurityInterceptor fsi =
|
||||
((FilterSecurityInterceptor)beanFactory.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
DefaultFilterInvocationSecurityMetadataSource fids =
|
||||
(DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
|
||||
List<ConfigAttribute> attributes = fids.lookupAttributes(loginPage, "POST");
|
||||
|
||||
if (attributes == null) {
|
||||
logger.debug("No access attributes defined for login page URL");
|
||||
if (fsi.isRejectPublicInvocations()) {
|
||||
logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
|
||||
" Your login page may not be accessible.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!beanFactory.containsBean(BeanIds.ANONYMOUS_PROCESSING_FILTER)) {
|
||||
logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
|
||||
" anonymous authentication enabled. This is almost certainly an error.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate an anonymous access with the supplied attributes.
|
||||
AnonymousProcessingFilter anonPF = (AnonymousProcessingFilter) beanFactory.getBean(BeanIds.ANONYMOUS_PROCESSING_FILTER);
|
||||
AnonymousAuthenticationToken token =
|
||||
new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
|
||||
anonPF.getUserAttribute().getAuthorities());
|
||||
try {
|
||||
fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST"));
|
||||
} catch (Exception e) {
|
||||
logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
|
||||
"an error. Please check your configuration allows unauthenticated access to the configured " +
|
||||
"login page. (Simulated access was rejected: " + e + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delegate filter of a wrapper, or the unchanged filter if it isn't wrapped.
|
||||
*/
|
||||
private Filter unwrapFilter(Object filter) {
|
||||
if (filter instanceof OrderedFilterBeanDefinitionDecorator.OrderedFilterDecorator) {
|
||||
return ((OrderedFilterBeanDefinitionDecorator.OrderedFilterDecorator)filter).getDelegate();
|
||||
}
|
||||
|
||||
return (Filter) filter;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.intercept.web.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.web.RequestKey;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.util.UrlMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Allows for convenient creation of a {@link FilterInvocationSecurityMetadataSource} bean for use with a FilterSecurityInterceptor.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterInvocationSecurityMetadataSourceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.intercept.web.DefaultFilterInvocationSecurityMetadataSource";
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
List<Element> interceptUrls = DomUtils.getChildElementsByTagName(element, "intercept-url");
|
||||
|
||||
// Check for attributes that aren't allowed in this context
|
||||
for(Element elt : interceptUrls) {
|
||||
if (StringUtils.hasLength(elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUIRES_CHANNEL))) {
|
||||
parserContext.getReaderContext().error("The attribute '" + HttpSecurityBeanDefinitionParser.ATT_REQUIRES_CHANNEL + "' isn't allowed here.", elt);
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_FILTERS))) {
|
||||
parserContext.getReaderContext().error("The attribute '" + HttpSecurityBeanDefinitionParser.ATT_FILTERS + "' isn't allowed here.", elt);
|
||||
}
|
||||
}
|
||||
|
||||
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(element);
|
||||
boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
LinkedHashMap<RequestKey, List<ConfigAttribute>> requestMap =
|
||||
HttpSecurityBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(interceptUrls,
|
||||
convertPathsToLowerCase, false, parserContext);
|
||||
|
||||
builder.addConstructorArgValue(matcher);
|
||||
builder.addConstructorArgValue(requestMap);
|
||||
}
|
||||
}
|
||||
-180
@@ -1,180 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ui.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_LOGIN_URL = "login-processing-url";
|
||||
|
||||
static final String ATT_LOGIN_PAGE = "login-page";
|
||||
private static final String DEF_LOGIN_PAGE = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
|
||||
|
||||
private static final String ATT_FORM_LOGIN_TARGET_URL = "default-target-url";
|
||||
private static final String ATT_ALWAYS_USE_DEFAULT_TARGET_URL = "always-use-default-target";
|
||||
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
|
||||
|
||||
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
|
||||
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
|
||||
|
||||
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
|
||||
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
|
||||
|
||||
private String defaultLoginProcessingUrl;
|
||||
private String filterClassName;
|
||||
|
||||
private RootBeanDefinition filterBean;
|
||||
private RootBeanDefinition entryPointBean;
|
||||
private String loginPage;
|
||||
|
||||
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName) {
|
||||
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
|
||||
this.filterClassName = filterClassName;
|
||||
}
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext pc) {
|
||||
String loginUrl = null;
|
||||
String defaultTargetUrl = null;
|
||||
String authenticationFailureUrl = null;
|
||||
String alwaysUseDefault = null;
|
||||
String successHandlerRef = null;
|
||||
String failureHandlerRef = null;
|
||||
|
||||
Object source = null;
|
||||
|
||||
// Copy values from the session fixation protection filter
|
||||
final Boolean sessionFixationProtectionEnabled =
|
||||
new Boolean(pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
Boolean migrateSessionAttributes = Boolean.FALSE;
|
||||
|
||||
if (sessionFixationProtectionEnabled.booleanValue()) {
|
||||
PropertyValue pv =
|
||||
pc.getRegistry().getBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER)
|
||||
.getPropertyValues().getPropertyValue("migrateSessionAttributes");
|
||||
migrateSessionAttributes = (Boolean)pv.getValue();
|
||||
}
|
||||
|
||||
if (elt != null) {
|
||||
source = pc.extractSource(elt);
|
||||
loginUrl = elt.getAttribute(ATT_LOGIN_URL);
|
||||
ConfigUtils.validateHttpRedirect(loginUrl, pc, source);
|
||||
defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL);
|
||||
ConfigUtils.validateHttpRedirect(defaultTargetUrl, pc, source);
|
||||
authenticationFailureUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL);
|
||||
ConfigUtils.validateHttpRedirect(authenticationFailureUrl, pc, source);
|
||||
alwaysUseDefault = elt.getAttribute(ATT_ALWAYS_USE_DEFAULT_TARGET_URL);
|
||||
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
|
||||
successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
|
||||
failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF);
|
||||
|
||||
if (!StringUtils.hasText(loginPage)) {
|
||||
loginPage = null;
|
||||
}
|
||||
ConfigUtils.validateHttpRedirect(loginPage, pc, source);
|
||||
}
|
||||
|
||||
ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
|
||||
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl,
|
||||
successHandlerRef, failureHandlerRef);
|
||||
filterBean.setSource(source);
|
||||
filterBean.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
filterBean.getPropertyValues().addPropertyValue("invalidateSessionOnSuccessfulAuthentication",
|
||||
sessionFixationProtectionEnabled);
|
||||
filterBean.getPropertyValues().addPropertyValue("migrateInvalidatedSessionAttributes",
|
||||
migrateSessionAttributes);
|
||||
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES) );
|
||||
}
|
||||
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.SESSION_REGISTRY)) {
|
||||
filterBean.getPropertyValues().addPropertyValue("sessionRegistry",
|
||||
new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder entryPointBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
|
||||
entryPointBuilder.getRawBeanDefinition().setSource(source);
|
||||
entryPointBuilder.addPropertyValue("loginFormUrl", loginPage != null ? loginPage : DEF_LOGIN_PAGE);
|
||||
entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault,
|
||||
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef) {
|
||||
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
|
||||
|
||||
if (!StringUtils.hasText(loginUrl)) {
|
||||
loginUrl = defaultLoginProcessingUrl;
|
||||
}
|
||||
|
||||
filterBuilder.addPropertyValue("filterProcessesUrl", loginUrl);
|
||||
|
||||
if (StringUtils.hasText(successHandlerRef)) {
|
||||
filterBuilder.addPropertyReference("authenticationSuccessHandler", successHandlerRef);
|
||||
} else {
|
||||
BeanDefinitionBuilder successHandler = BeanDefinitionBuilder.rootBeanDefinition(SavedRequestAwareAuthenticationSuccessHandler.class);
|
||||
if ("true".equals(alwaysUseDefault)) {
|
||||
successHandler.addPropertyValue("alwaysUseDefaultTargetUrl", Boolean.TRUE);
|
||||
}
|
||||
successHandler.addPropertyValue("defaultTargetUrl", StringUtils.hasText(defaultTargetUrl) ? defaultTargetUrl : DEF_FORM_LOGIN_TARGET_URL);
|
||||
filterBuilder.addPropertyValue("authenticationSuccessHandler", successHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(failureHandlerRef)) {
|
||||
filterBuilder.addPropertyReference("authenticationFailureHandler", failureHandlerRef);
|
||||
} else {
|
||||
BeanDefinitionBuilder failureHandler = BeanDefinitionBuilder.rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class);
|
||||
if (!StringUtils.hasText(authenticationFailureUrl)) {
|
||||
// Fall back to redisplaying the custom login page, if one was specified.
|
||||
if (StringUtils.hasText(loginPage)) {
|
||||
authenticationFailureUrl = loginPage;
|
||||
} else {
|
||||
authenticationFailureUrl = DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL;
|
||||
}
|
||||
}
|
||||
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
|
||||
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
|
||||
}
|
||||
|
||||
return (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
RootBeanDefinition getFilterBean() {
|
||||
return filterBean;
|
||||
}
|
||||
|
||||
RootBeanDefinition getEntryPointBean() {
|
||||
return entryPointBean;
|
||||
}
|
||||
|
||||
String getLoginPage() {
|
||||
return loginPage;
|
||||
}
|
||||
}
|
||||
-244
@@ -1,244 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.expression.method.MethodExpressionAfterInvocationProvider;
|
||||
import org.springframework.security.expression.method.MethodExpressionVoter;
|
||||
import org.springframework.security.expression.support.DefaultSecurityExpressionHandler;
|
||||
import org.springframework.security.intercept.method.DelegatingMethodSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.method.MapBasedMethodSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityMetadataSourceAdvisor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Processes the top-level "global-method-security" element.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodSecurityMetadataSource";
|
||||
private static final String EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.expression.method.ExpressionAnnotationMethodSecurityMetadataSource";
|
||||
private static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.Jsr250MethodSecurityMetadataSource";
|
||||
private static final String JSR_250_VOTER_CLASS = "org.springframework.security.annotation.Jsr250Voter";
|
||||
|
||||
/*
|
||||
* Internal Bean IDs which are only used within this class
|
||||
*/
|
||||
static final String SECURITY_INTERCEPTOR_ID = "_globalMethodSecurityInterceptor";
|
||||
static final String INTERCEPTOR_POST_PROCESSOR_ID = "_globalMethodSecurityInterceptorPostProcessor";
|
||||
static final String ACCESS_MANAGER_ID = "_globalMethodSecurityAccessManager";
|
||||
private static final String DELEGATING_METHOD_DEFINITION_SOURCE_ID = "_delegatingMethodSecurityMetadataSource";
|
||||
private static final String EXPRESSION_HANDLER_ID = "_methodExpressionHandler";
|
||||
|
||||
private static final String ATT_ACCESS = "access";
|
||||
private static final String ATT_EXPRESSION = "expression";
|
||||
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
private static final String ATT_USE_JSR250 = "jsr250-annotations";
|
||||
private static final String ATT_USE_SECURED = "secured-annotations";
|
||||
private static final String ATT_USE_EXPRESSIONS = "expression-annotations";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
// The list of method metadata delegates
|
||||
ManagedList delegates = new ManagedList();
|
||||
|
||||
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
boolean expressionsEnabled = "enabled".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
|
||||
BeanDefinition expressionVoter = null;
|
||||
|
||||
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
|
||||
Map<String, List<ConfigAttribute>> pointcutMap = parseProtectPointcuts(parserContext,
|
||||
DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
|
||||
|
||||
if (pointcutMap.size() > 0) {
|
||||
// SEC-1016: Put the pointcut MDS first, but only add it if there are actually any pointcuts defined.
|
||||
MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource = new MapBasedMethodSecurityMetadataSource();
|
||||
delegates.add(mapBasedMethodSecurityMetadataSource);
|
||||
registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodSecurityMetadataSource, source);
|
||||
}
|
||||
|
||||
if (expressionsEnabled) {
|
||||
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
|
||||
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
|
||||
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
logger.info("Using bean '" + expressionHandlerRef + "' as method SecurityExpressionHandler implementation");
|
||||
} else {
|
||||
parserContext.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultSecurityExpressionHandler.class));
|
||||
logger.warn("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " +
|
||||
"All hasPermision() expressions will evaluate to false.");
|
||||
expressionHandlerRef = EXPRESSION_HANDLER_ID;
|
||||
}
|
||||
BeanDefinitionBuilder expressionVoterBldr = BeanDefinitionBuilder.rootBeanDefinition(MethodExpressionVoter.class);
|
||||
BeanDefinitionBuilder afterInvocationProvider = BeanDefinitionBuilder.rootBeanDefinition(MethodExpressionAfterInvocationProvider.class);
|
||||
expressionVoterBldr.addPropertyReference("expressionHandler", expressionHandlerRef);
|
||||
expressionVoter = expressionVoterBldr.getBeanDefinition();
|
||||
// After-invocation provider to handle post-invocation filtering and authorization expression annotations.
|
||||
afterInvocationProvider.addPropertyReference("expressionHandler", expressionHandlerRef);
|
||||
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(afterInvocationProvider.getBeanDefinition());
|
||||
// Add the expression method definition source, which will obtain its parser from the registered expression
|
||||
// handler
|
||||
BeanDefinitionBuilder mds = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS);
|
||||
mds.addConstructorArgReference(expressionHandlerRef);
|
||||
|
||||
delegates.add(mds.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useSecured) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (jsr250Enabled) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
registerDelegatingMethodSecurityMetadataSource(parserContext, delegates, source);
|
||||
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
registerAccessManager(parserContext, jsr250Enabled, expressionVoter);
|
||||
accessManagerId = ACCESS_MANAGER_ID;
|
||||
}
|
||||
|
||||
registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
|
||||
|
||||
registerAdvisor(parserContext, source);
|
||||
|
||||
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the default AccessDecisionManager. Adds the special JSR 250 voter jsr-250 is enabled and an
|
||||
* expression voter if expression-based access control is enabled.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerAccessManager(ParserContext pc, boolean jsr250Enabled, BeanDefinition expressionVoter) {
|
||||
|
||||
BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
|
||||
ManagedList voters = new ManagedList(4);
|
||||
|
||||
if (expressionVoter != null) {
|
||||
voters.add(expressionVoter);
|
||||
}
|
||||
voters.add(new RootBeanDefinition(RoleVoter.class));
|
||||
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
|
||||
|
||||
if (jsr250Enabled) {
|
||||
voters.add(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null));
|
||||
}
|
||||
|
||||
accessMgrBuilder.addPropertyValue("decisionVoters", voters);
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(ACCESS_MANAGER_ID, accessMgrBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerDelegatingMethodSecurityMetadataSource(ParserContext parserContext, ManagedList delegates, Object source) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(DELEGATING_METHOD_DEFINITION_SOURCE_ID)) {
|
||||
parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
|
||||
}
|
||||
RootBeanDefinition delegatingMethodSecurityMetadataSource = new RootBeanDefinition(DelegatingMethodSecurityMetadataSource.class);
|
||||
delegatingMethodSecurityMetadataSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodSecurityMetadataSource.setSource(source);
|
||||
delegatingMethodSecurityMetadataSource.getPropertyValues().addPropertyValue("methodSecurityMetadataSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(DELEGATING_METHOD_DEFINITION_SOURCE_ID, delegatingMethodSecurityMetadataSource);
|
||||
}
|
||||
|
||||
private void registerProtectPointcutPostProcessor(ParserContext parserContext,
|
||||
Map<String, List<ConfigAttribute>> pointcutMap,
|
||||
MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource, Object source) {
|
||||
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
|
||||
ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
ppbp.setSource(source);
|
||||
ppbp.getConstructorArgumentValues().addGenericArgumentValue(mapBasedMethodSecurityMetadataSource);
|
||||
ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.PROTECT_POINTCUT_POST_PROCESSOR, ppbp);
|
||||
}
|
||||
|
||||
private Map<String, List<ConfigAttribute>> parseProtectPointcuts(ParserContext parserContext, List<Element> protectPointcutElts) {
|
||||
Map<String, List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String, List<ConfigAttribute>>();
|
||||
|
||||
for (Element childElt : protectPointcutElts) {
|
||||
String accessConfig = childElt.getAttribute(ATT_ACCESS);
|
||||
String expression = childElt.getAttribute(ATT_EXPRESSION);
|
||||
|
||||
if (!StringUtils.hasText(accessConfig)) {
|
||||
parserContext.getReaderContext().error("Access configuration required", parserContext.extractSource(childElt));
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(expression)) {
|
||||
parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt));
|
||||
}
|
||||
|
||||
String[] attributeTokens = StringUtils.commaDelimitedListToStringArray(accessConfig);
|
||||
List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(attributeTokens.length);
|
||||
|
||||
for(String token : attributeTokens) {
|
||||
attributes.add(new SecurityConfig(token));
|
||||
}
|
||||
|
||||
pointcutMap.put(expression, attributes);
|
||||
}
|
||||
|
||||
return pointcutMap;
|
||||
}
|
||||
|
||||
private void registerMethodSecurityInterceptor(ParserContext parserContext, String accessManagerId, Object source) {
|
||||
RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
interceptor.setSource(source);
|
||||
|
||||
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
|
||||
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
interceptor.getPropertyValues().addPropertyValue("securityMetadataSource", new RuntimeBeanReference(DELEGATING_METHOD_DEFINITION_SOURCE_ID));
|
||||
parserContext.getRegistry().registerBeanDefinition(SECURITY_INTERCEPTOR_ID, interceptor);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, SECURITY_INTERCEPTOR_ID));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(INTERCEPTOR_POST_PROCESSOR_ID,
|
||||
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
|
||||
}
|
||||
|
||||
private void registerAdvisor(ParserContext parserContext, Object source) {
|
||||
RootBeanDefinition advisor = new RootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
|
||||
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisor.setSource(source);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(SECURITY_INTERCEPTOR_ID);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(DELEGATING_METHOD_DEFINITION_SOURCE_ID));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR, advisor);
|
||||
}
|
||||
}
|
||||
-697
@@ -1,697 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeEditor;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.expression.web.WebExpressionVoter;
|
||||
import org.springframework.security.intercept.web.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.intercept.web.RequestKey;
|
||||
import org.springframework.security.securechannel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.securechannel.ChannelProcessingFilter;
|
||||
import org.springframework.security.securechannel.InsecureChannelProcessor;
|
||||
import org.springframework.security.securechannel.RetryWithHttpEntryPoint;
|
||||
import org.springframework.security.securechannel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.securechannel.SecureChannelProcessor;
|
||||
import org.springframework.security.ui.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.util.RegexUrlPathMatcher;
|
||||
import org.springframework.security.util.UrlMatcher;
|
||||
import org.springframework.security.vote.AccessDecisionVoter;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Sets up HTTP security: filter stack and protected URLs.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @since 2.0
|
||||
* @version $Id$
|
||||
*/
|
||||
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
|
||||
|
||||
static final String ATT_PATH_PATTERN = "pattern";
|
||||
static final String ATT_PATH_TYPE = "path-type";
|
||||
static final String OPT_PATH_TYPE_REGEX = "regex";
|
||||
private static final String DEF_PATH_TYPE_ANT = "ant";
|
||||
|
||||
static final String ATT_FILTERS = "filters";
|
||||
static final String OPT_FILTERS_NONE = "none";
|
||||
|
||||
private static final String ATT_REALM = "realm";
|
||||
private static final String DEF_REALM = "Spring Security Application";
|
||||
|
||||
private static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
|
||||
private static final String OPT_SESSION_FIXATION_NO_PROTECTION = "none";
|
||||
private static final String OPT_SESSION_FIXATION_MIGRATE_SESSION = "migrateSession";
|
||||
|
||||
private static final String ATT_ACCESS_CONFIG = "access";
|
||||
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
|
||||
private static final String OPT_REQUIRES_HTTP = "http";
|
||||
private static final String OPT_REQUIRES_HTTPS = "https";
|
||||
private static final String OPT_ANY_CHANNEL = "any";
|
||||
|
||||
private static final String ATT_HTTP_METHOD = "method";
|
||||
|
||||
private static final String ATT_CREATE_SESSION = "create-session";
|
||||
private static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
|
||||
private static final String OPT_CREATE_SESSION_ALWAYS = "always";
|
||||
private static final String OPT_CREATE_SESSION_NEVER = "never";
|
||||
|
||||
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
|
||||
|
||||
private static final String ATT_AUTO_CONFIG = "auto-config";
|
||||
|
||||
private static final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
|
||||
private static final String DEF_SERVLET_API_PROVISION = "true";
|
||||
|
||||
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
private static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
|
||||
private static final String ATT_USE_EXPRESSIONS = "use-expressions";
|
||||
|
||||
private static final String ATT_SECURITY_CONTEXT_REPOSITORY = "security-context-repository-ref";
|
||||
|
||||
private static final String ATT_DISABLE_URL_REWRITING = "disable-url-rewriting";
|
||||
|
||||
private static final String EXPRESSION_FIDS_CLASS = "org.springframework.security.expression.web.ExpressionBasedFilterInvocationSecurityMetadataSource";
|
||||
private static final String EXPRESSION_HANDLER_CLASS = "org.springframework.security.expression.support.DefaultSecurityExpressionHandler";
|
||||
private static final String EXPRESSION_HANDLER_ID = "_webExpressionHandler";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
final BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
final UrlMatcher matcher = createUrlMatcher(element);
|
||||
final Object source = parserContext.extractSource(element);
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
|
||||
final List<Element> interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
final Map filterChainMap = new LinkedHashMap();
|
||||
final LinkedHashMap channelRequestMap = new LinkedHashMap();
|
||||
|
||||
registerFilterChainProxy(parserContext, filterChainMap, matcher, source);
|
||||
|
||||
// filterChainMap and channelRequestMap are populated by this call
|
||||
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
|
||||
convertPathsToLowerCase, parserContext);
|
||||
|
||||
boolean allowSessionCreation = registerSecurityContextPersistenceFilter(element, parserContext);
|
||||
|
||||
registerServletApiFilter(element, parserContext);
|
||||
|
||||
// Register the portMapper. A default will always be created, even if no element exists.
|
||||
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
|
||||
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
|
||||
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
|
||||
|
||||
registerExceptionTranslationFilter(element, parserContext, allowSessionCreation);
|
||||
|
||||
if (channelRequestMap.size() > 0) {
|
||||
// At least one channel requirement has been specified
|
||||
registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
|
||||
}
|
||||
|
||||
boolean useExpressions = "true".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
|
||||
|
||||
LinkedHashMap<RequestKey, List<ConfigAttribute>> requestToAttributesMap =
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, useExpressions, parserContext);
|
||||
|
||||
BeanDefinitionBuilder fidsBuilder;
|
||||
Class<? extends AccessDecisionVoter>[] voters;
|
||||
|
||||
if (useExpressions) {
|
||||
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
|
||||
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
|
||||
|
||||
if (StringUtils.hasText(expressionHandlerRef)) {
|
||||
logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation");
|
||||
} else {
|
||||
parserContext.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID,
|
||||
BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_HANDLER_CLASS).getBeanDefinition());
|
||||
expressionHandlerRef = EXPRESSION_HANDLER_ID;
|
||||
}
|
||||
|
||||
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_FIDS_CLASS);
|
||||
fidsBuilder.addConstructorArgValue(matcher);
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
fidsBuilder.addConstructorArgReference(expressionHandlerRef);
|
||||
voters = new Class[] {WebExpressionVoter.class};
|
||||
} else {
|
||||
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
|
||||
fidsBuilder.addConstructorArgValue(matcher);
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
voters = new Class[] {RoleVoter.class, AuthenticatedVoter.class};
|
||||
}
|
||||
fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
// Set up the access manager reference for http
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.WEB_ACCESS_MANAGER,
|
||||
ConfigUtils.createAccessManagerBean(voters));
|
||||
accessManagerId = BeanIds.WEB_ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
registerFilterSecurityInterceptor(element, parserContext, accessManagerId, fidsBuilder.getBeanDefinition());
|
||||
|
||||
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
|
||||
|
||||
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
|
||||
sessionControlEnabled);
|
||||
|
||||
boolean autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||
|
||||
Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
|
||||
if (anonymousElt != null || autoConfig) {
|
||||
new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext);
|
||||
}
|
||||
|
||||
parseRememberMeAndLogout(element, autoConfig, parserContext);
|
||||
|
||||
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation);
|
||||
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
|
||||
if (x509Elt != null) {
|
||||
new X509BeanDefinitionParser().parse(x509Elt, parserContext);
|
||||
}
|
||||
|
||||
// Register the post processors which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
|
||||
RootBeanDefinition postProcessor = new RootBeanDefinition(EntryPointInjectionBeanPostProcessor.class);
|
||||
postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.ENTRY_POINT_INJECTION_POST_PROCESSOR, postProcessor);
|
||||
RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) {
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME);
|
||||
String rememberMeServices = null;
|
||||
|
||||
if (rememberMeElt != null) {
|
||||
RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser();
|
||||
rmbdp.parse(rememberMeElt, pc);
|
||||
rememberMeServices = rmbdp.getServicesName();
|
||||
// Post processor to inject RememberMeServices into filters which need it
|
||||
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
|
||||
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
|
||||
}
|
||||
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) {
|
||||
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
|
||||
pc.getReaderContext().error("Duplicate <http> element detected", source);
|
||||
}
|
||||
|
||||
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
|
||||
filterChainProxy.setSource(source);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
|
||||
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
|
||||
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
}
|
||||
|
||||
private boolean registerSecurityContextPersistenceFilter(Element element, ParserContext pc) {
|
||||
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
|
||||
boolean sessionCreationAllowed = true;
|
||||
|
||||
String repoRef = element.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
|
||||
String createSession = element.getAttribute(ATT_CREATE_SESSION);
|
||||
String disableUrlRewriting = element.getAttribute(ATT_DISABLE_URL_REWRITING);
|
||||
|
||||
if (StringUtils.hasText(repoRef)) {
|
||||
scpf.addPropertyReference("securityContextRepository", repoRef);
|
||||
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (StringUtils.hasText(createSession)) {
|
||||
pc.getReaderContext().error("If using security-context-repository-ref, the only value you can set for " +
|
||||
"'create-session' is 'always'. Other session creation logic should be handled by the " +
|
||||
"SecurityContextRepository", element);
|
||||
}
|
||||
} else {
|
||||
BeanDefinitionBuilder contextRepo = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
|
||||
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
sessionCreationAllowed = false;
|
||||
} else {
|
||||
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
|
||||
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
|
||||
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
|
||||
}
|
||||
|
||||
if ("true".equals(disableUrlRewriting)) {
|
||||
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
|
||||
}
|
||||
|
||||
scpf.addPropertyValue("securityContextRepository", contextRepo.getBeanDefinition());
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER, scpf.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER));
|
||||
|
||||
return sessionCreationAllowed;
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
private void registerServletApiFilter(Element element, ParserContext pc) {
|
||||
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
provideServletApi = DEF_SERVLET_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER,
|
||||
new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class));
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean registerConcurrentSessionControlBeansIfRequired(Element element, ParserContext parserContext) {
|
||||
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
|
||||
if (sessionControlElt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
|
||||
sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void registerExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
BeanDefinition accessDeniedHandler = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
|
||||
accessDeniedHandler.getPropertyValues().addPropertyValue("errorPage", accessDeniedPage);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
|
||||
}
|
||||
|
||||
private void registerFilterSecurityInterceptor(Element element, ParserContext pc, String accessManagerId,
|
||||
BeanDefinition fids) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
builder.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
builder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
if ("false".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
|
||||
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
|
||||
}
|
||||
|
||||
builder.addPropertyValue("securityMetadataSource", fids);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
|
||||
new RuntimeBeanReference(BeanIds.CHANNEL_DECISION_MANAGER));
|
||||
DefaultFilterInvocationSecurityMetadataSource channelFilterInvDefSource =
|
||||
new DefaultFilterInvocationSecurityMetadataSource(matcher, channelRequestMap);
|
||||
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("filterInvocationSecurityMetadataSource",
|
||||
channelFilterInvDefSource);
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
ManagedList channelProcessors = new ManagedList(3);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
RuntimeBeanReference portMapper = new RuntimeBeanReference(BeanIds.PORT_MAPPER);
|
||||
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
secureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttps);
|
||||
RootBeanDefinition inSecureChannelProcessor = new RootBeanDefinition(InsecureChannelProcessor.class);
|
||||
inSecureChannelProcessor.getPropertyValues().addPropertyValue("entryPoint", retryWithHttp);
|
||||
channelProcessors.add(secureChannelProcessor);
|
||||
channelProcessors.add(inSecureChannelProcessor);
|
||||
channelDecisionManager.getPropertyValues().addPropertyValue("channelProcessors", channelProcessors);
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
|
||||
|
||||
}
|
||||
|
||||
private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
|
||||
if(!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
|
||||
BeanDefinitionBuilder sessionFixationFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
|
||||
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
if (sessionControlEnabled) {
|
||||
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
|
||||
}
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
|
||||
sessionFixationFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) {
|
||||
RootBeanDefinition formLoginFilter = null;
|
||||
RootBeanDefinition formLoginEntryPoint = null;
|
||||
String formLoginPage = null;
|
||||
RootBeanDefinition openIDFilter = null;
|
||||
RootBeanDefinition openIDEntryPoint = null;
|
||||
String openIDLoginPage = null;
|
||||
|
||||
String realm = element.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
|
||||
}
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(formLoginElt, pc);
|
||||
formLoginFilter = parser.getFilterBean();
|
||||
formLoginEntryPoint = parser.getEntryPointBean();
|
||||
formLoginPage = parser.getLoginPage();
|
||||
}
|
||||
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN);
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
|
||||
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
openIDLoginPage = parser.getLoginPage();
|
||||
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.providers.openid.OpenIDAuthenticationProvider");
|
||||
|
||||
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
if (StringUtils.hasText(userService)) {
|
||||
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
|
||||
}
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
|
||||
ConfigUtils.addAuthenticationProvider(pc, BeanIds.OPEN_ID_PROVIDER);
|
||||
}
|
||||
|
||||
boolean needLoginPage = false;
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
needLoginPage = true;
|
||||
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
needLoginPage = true;
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
|
||||
}
|
||||
|
||||
// If no login page has been defined, add in the default page generator.
|
||||
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
|
||||
logger.info("No login page configured. The default internal one will be used. Use the '"
|
||||
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page.");
|
||||
BeanDefinitionBuilder loginPageFilter =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
|
||||
|
||||
if (formLoginFilter != null) {
|
||||
loginPageFilter.addConstructorArgValue(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
loginPageFilter.addConstructorArgValue(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
|
||||
loginPageFilter.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
|
||||
}
|
||||
|
||||
// We need to establish the main entry point.
|
||||
// First check if a custom entry point bean is set
|
||||
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
|
||||
|
||||
if (StringUtils.hasText(customEntryPoint)) {
|
||||
pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic takes precedence if explicit element is used and no others are configured
|
||||
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
|
||||
// has been set
|
||||
if (formLoginFilter != null && openIDLoginPage == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null && formLoginFilter == null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
// If X.509 has been enabled, use the preauth entry point.
|
||||
if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
|
||||
pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
|
||||
return;
|
||||
}
|
||||
|
||||
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
|
||||
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
|
||||
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
|
||||
pc.extractSource(element));
|
||||
}
|
||||
|
||||
static UrlMatcher createUrlMatcher(Element element) {
|
||||
String patternType = element.getAttribute(ATT_PATH_TYPE);
|
||||
if (!StringUtils.hasText(patternType)) {
|
||||
patternType = DEF_PATH_TYPE_ANT;
|
||||
}
|
||||
|
||||
boolean useRegex = patternType.equals(OPT_PATH_TYPE_REGEX);
|
||||
|
||||
UrlMatcher matcher = new AntUrlPathMatcher();
|
||||
|
||||
if (useRegex) {
|
||||
matcher = new RegexUrlPathMatcher();
|
||||
}
|
||||
|
||||
// Deal with lowercase conversion requests
|
||||
String lowercaseComparisons = element.getAttribute(ATT_LOWERCASE_COMPARISONS);
|
||||
if (!StringUtils.hasText(lowercaseComparisons)) {
|
||||
lowercaseComparisons = null;
|
||||
}
|
||||
|
||||
|
||||
// Only change from the defaults if the attribute has been set
|
||||
if ("true".equals(lowercaseComparisons)) {
|
||||
if (useRegex) {
|
||||
((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(true);
|
||||
}
|
||||
// Default for ant is already to force lower case
|
||||
} else if ("false".equals(lowercaseComparisons)) {
|
||||
if (!useRegex) {
|
||||
((AntUrlPathMatcher)matcher).setRequiresLowerCaseUrl(false);
|
||||
}
|
||||
// Default for regex is no change
|
||||
}
|
||||
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the intercept-url elements and populates the FilterChainProxy's filter chain Map and the
|
||||
* map used to create the FilterInvocationDefintionSource for the FilterSecurityInterceptor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
void parseInterceptUrlsForChannelSecurityAndFilterChain(List<Element> urlElts, Map filterChainMap, Map channelRequestMap,
|
||||
boolean useLowerCasePaths, ParserContext parserContext) {
|
||||
|
||||
ConfigAttributeEditor editor = new ConfigAttributeEditor();
|
||||
|
||||
for (Element urlElt : urlElts) {
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||
}
|
||||
|
||||
if (useLowerCasePaths) {
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
||||
if (StringUtils.hasText(requiredChannel)) {
|
||||
String channelConfigAttribute = null;
|
||||
|
||||
if (requiredChannel.equals(OPT_REQUIRES_HTTPS)) {
|
||||
channelConfigAttribute = "REQUIRES_SECURE_CHANNEL";
|
||||
} else if (requiredChannel.equals(OPT_REQUIRES_HTTP)) {
|
||||
channelConfigAttribute = "REQUIRES_INSECURE_CHANNEL";
|
||||
} else if (requiredChannel.equals(OPT_ANY_CHANNEL)) {
|
||||
channelConfigAttribute = ChannelDecisionManagerImpl.ANY_CHANNEL;
|
||||
} else {
|
||||
parserContext.getReaderContext().error("Unsupported channel " + requiredChannel, urlElt);
|
||||
}
|
||||
|
||||
editor.setAsText(channelConfigAttribute);
|
||||
channelRequestMap.put(new RequestKey(path), editor.getValue());
|
||||
}
|
||||
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
|
||||
if (StringUtils.hasText(filters)) {
|
||||
if (!filters.equals(OPT_FILTERS_NONE)) {
|
||||
parserContext.getReaderContext().error("Currently only 'none' is supported as the custom " +
|
||||
"filters attribute", urlElt);
|
||||
}
|
||||
|
||||
filterChainMap.put(path, Collections.EMPTY_LIST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the filter invocation map which will be used to configure the FilterInvocationSecurityMetadataSource
|
||||
* used in the security interceptor.
|
||||
*/
|
||||
static LinkedHashMap<RequestKey, List<ConfigAttribute>>
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(List<Element> urlElts, boolean useLowerCasePaths,
|
||||
boolean useExpressions, ParserContext parserContext) {
|
||||
|
||||
LinkedHashMap<RequestKey, List<ConfigAttribute>> filterInvocationDefinitionMap = new LinkedHashMap<RequestKey, List<ConfigAttribute>>();
|
||||
|
||||
for (Element urlElt : urlElts) {
|
||||
String access = urlElt.getAttribute(ATT_ACCESS_CONFIG);
|
||||
if (!StringUtils.hasText(access)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
parserContext.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||
}
|
||||
|
||||
if (useLowerCasePaths) {
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
|
||||
if (!StringUtils.hasText(method)) {
|
||||
method = null;
|
||||
}
|
||||
|
||||
// Convert the comma-separated list of access attributes to a List<ConfigAttribute>
|
||||
|
||||
RequestKey key = new RequestKey(path, method);
|
||||
List<ConfigAttribute> attributes = null;
|
||||
|
||||
if (useExpressions) {
|
||||
logger.info("Creating access control expression attribute '" + access + "' for " + key);
|
||||
attributes = new ArrayList<ConfigAttribute>(1);
|
||||
// The expression will be parsed later by the ExpressionFilterInvocationSecurityMetadataSource
|
||||
attributes.add(new SecurityConfig(access));
|
||||
|
||||
} else {
|
||||
attributes = SecurityConfig.createList(StringUtils.commaDelimitedListToStringArray(access));
|
||||
}
|
||||
|
||||
if (filterInvocationDefinitionMap.containsKey(key)) {
|
||||
logger.warn("Duplicate URL defined: " + key + ". The original attribute values will be overwritten");
|
||||
}
|
||||
|
||||
filterInvocationDefinitionMap.put(key, attributes);
|
||||
}
|
||||
|
||||
return filterInvocationDefinitionMap;
|
||||
}
|
||||
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
private BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator();
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
ConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
|
||||
|
||||
return delegate.decorate(node, definition, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the real class which does the work. We need access to the ParserContext in order to do bean
|
||||
* registration.
|
||||
*/
|
||||
class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator {
|
||||
static final String ATT_METHOD = "method";
|
||||
static final String ATT_ACCESS = "access";
|
||||
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
|
||||
protected BeanDefinition createInterceptorDefinition(Node node) {
|
||||
Element interceptMethodsElt = (Element)node;
|
||||
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class);
|
||||
|
||||
// Default to autowiring to pick up after invocation mgr
|
||||
interceptor.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
|
||||
String accessManagerId = interceptMethodsElt.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
accessManagerId = BeanIds.METHOD_ACCESS_MANAGER;
|
||||
}
|
||||
|
||||
interceptor.addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
|
||||
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
// Lookup parent bean information
|
||||
Element parent = (Element) node.getParentNode();
|
||||
String parentBeanClass = parent.getAttribute("class");
|
||||
parent = null;
|
||||
|
||||
// Parse the included methods
|
||||
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (Element protectmethodElt : methods) {
|
||||
String accessConfig = protectmethodElt.getAttribute(ATT_ACCESS);
|
||||
|
||||
// Support inference of class names
|
||||
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
|
||||
|
||||
if (methodName.lastIndexOf(".") == -1) {
|
||||
if (parentBeanClass != null && !"".equals(parentBeanClass)) {
|
||||
methodName = parentBeanClass + "." + methodName;
|
||||
}
|
||||
}
|
||||
|
||||
// Rely on the default property editor for MethodSecurityInterceptor.setSecurityMetadataSource to setup the MethodSecurityMetadataSource
|
||||
sb.append(methodName + "=" + accessConfig).append("\r\n");
|
||||
}
|
||||
|
||||
interceptor.addPropertyValue("securityMetadataSource", sb.toString());
|
||||
|
||||
return interceptor.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
static final String ATT_DATA_SOURCE = "data-source-ref";
|
||||
static final String ATT_USERS_BY_USERNAME_QUERY = "users-by-username-query";
|
||||
static final String ATT_AUTHORITIES_BY_USERNAME_QUERY = "authorities-by-username-query";
|
||||
static final String ATT_GROUP_AUTHORITIES_QUERY = "group-authorities-by-username-query";
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager";
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
|
||||
if (dataSource != null) {
|
||||
builder.addPropertyReference("dataSource", dataSource);
|
||||
} else {
|
||||
parserContext.getReaderContext().error(ATT_DATA_SOURCE + " is required for "
|
||||
+ Elements.JDBC_USER_SERVICE, parserContext.extractSource(element));
|
||||
}
|
||||
|
||||
String usersQuery = element.getAttribute(ATT_USERS_BY_USERNAME_QUERY);
|
||||
String authoritiesQuery = element.getAttribute(ATT_AUTHORITIES_BY_USERNAME_QUERY);
|
||||
String groupAuthoritiesQuery = element.getAttribute(ATT_GROUP_AUTHORITIES_QUERY);
|
||||
String rolePrefix = element.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
builder.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(usersQuery)) {
|
||||
builder.addPropertyValue("usersByUsernameQuery", usersQuery);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(authoritiesQuery)) {
|
||||
builder.addPropertyValue("authoritiesByUsernameQuery", authoritiesQuery);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(groupAuthoritiesQuery)) {
|
||||
builder.addPropertyValue("enableGroups", Boolean.TRUE);
|
||||
builder.addPropertyValue("groupAuthoritiesByUsernameQuery", groupAuthoritiesQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Ldap authentication provider namespace configuration.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_USER_DN_PATTERN = "user-dn-pattern";
|
||||
private static final String ATT_USER_PASSWORD = "password-attribute";
|
||||
private static final String ATT_HASH = PasswordEncoderParser.ATT_HASH;
|
||||
|
||||
private static final String DEF_USER_SEARCH_FILTER = "uid={0}";
|
||||
|
||||
private static final String PROVIDER_CLASS = "org.springframework.security.providers.ldap.LdapAuthenticationProvider";
|
||||
private static final String BIND_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.BindAuthenticator";
|
||||
private static final String PASSWD_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator";
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
RuntimeBeanReference contextSource = LdapUserServiceBeanDefinitionParser.parseServerReference(elt, parserContext);
|
||||
|
||||
BeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext);
|
||||
String userDnPattern = elt.getAttribute(ATT_USER_DN_PATTERN);
|
||||
|
||||
String[] userDnPatternArray = new String[0];
|
||||
|
||||
if (StringUtils.hasText(userDnPattern)) {
|
||||
userDnPatternArray = new String[] {userDnPattern};
|
||||
// TODO: Validate the pattern and make sure it is a valid DN.
|
||||
} else if (searchBean == null) {
|
||||
logger.info("No search information or DN pattern specified. Using default search filter '" + DEF_USER_SEARCH_FILTER + "'");
|
||||
BeanDefinitionBuilder searchBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(LdapUserServiceBeanDefinitionParser.LDAP_SEARCH_CLASS);
|
||||
searchBeanBuilder.getRawBeanDefinition().setSource(elt);
|
||||
searchBeanBuilder.addConstructorArgValue("");
|
||||
searchBeanBuilder.addConstructorArgValue(DEF_USER_SEARCH_FILTER);
|
||||
searchBeanBuilder.addConstructorArgValue(contextSource);
|
||||
searchBean = searchBeanBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder authenticatorBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(BIND_AUTH_CLASS);
|
||||
Element passwordCompareElt = DomUtils.getChildElementByTagName(elt, Elements.LDAP_PASSWORD_COMPARE);
|
||||
|
||||
if (passwordCompareElt != null) {
|
||||
authenticatorBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(PASSWD_AUTH_CLASS);
|
||||
|
||||
String passwordAttribute = passwordCompareElt.getAttribute(ATT_USER_PASSWORD);
|
||||
if (StringUtils.hasText(passwordAttribute)) {
|
||||
authenticatorBuilder.addPropertyValue("passwordAttributeName", passwordAttribute);
|
||||
}
|
||||
|
||||
Element passwordEncoderElement = DomUtils.getChildElementByTagName(passwordCompareElt, Elements.PASSWORD_ENCODER);
|
||||
String hash = passwordCompareElt.getAttribute(ATT_HASH);
|
||||
|
||||
if (passwordEncoderElement != null) {
|
||||
if (StringUtils.hasText(hash)) {
|
||||
parserContext.getReaderContext().warning("Attribute 'hash' cannot be used with 'password-encoder' and " +
|
||||
"will be ignored.", parserContext.extractSource(elt));
|
||||
}
|
||||
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElement, parserContext);
|
||||
authenticatorBuilder.addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
|
||||
|
||||
if (pep.getSaltSource() != null) {
|
||||
parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP",
|
||||
passwordEncoderElement);
|
||||
}
|
||||
} else if (StringUtils.hasText(hash)) {;
|
||||
authenticatorBuilder.addPropertyValue("passwordEncoder",
|
||||
PasswordEncoderParser.createPasswordEncoderBeanDefinition(hash, false));
|
||||
}
|
||||
}
|
||||
|
||||
authenticatorBuilder.addConstructorArgValue(contextSource);
|
||||
authenticatorBuilder.addPropertyValue("userDnPatterns", userDnPatternArray);
|
||||
|
||||
if (searchBean != null) {
|
||||
authenticatorBuilder.addPropertyValue("userSearch", searchBean);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder ldapProvider = BeanDefinitionBuilder.rootBeanDefinition(PROVIDER_CLASS);
|
||||
ldapProvider.addConstructorArgValue(authenticatorBuilder.getBeanDefinition());
|
||||
ldapProvider.addConstructorArgValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
ldapProvider.addPropertyValue("userDetailsContextMapper",
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LDAP_AUTHENTICATION_PROVIDER, ldapProvider.getBeanDefinition());
|
||||
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.LDAP_AUTHENTICATION_PROVIDER);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String CONTEXT_SOURCE_CLASS="org.springframework.security.ldap.DefaultSpringSecurityContextSource";
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Defines the Url of the ldap server to use. If not specified, an embedded apache DS instance will be created */
|
||||
private static final String ATT_URL = "url";
|
||||
|
||||
private static final String ATT_PRINCIPAL = "manager-dn";
|
||||
private static final String ATT_PASSWORD = "manager-password";
|
||||
|
||||
// Properties which apply to embedded server only - when no Url is set
|
||||
|
||||
/** sets the configuration suffix (default is "dc=springframework,dc=org"). */
|
||||
public static final String ATT_ROOT_SUFFIX = "root";
|
||||
private static final String OPT_DEFAULT_ROOT_SUFFIX = "dc=springframework,dc=org";
|
||||
/**
|
||||
* Optionally defines an ldif resource to be loaded. Otherwise an attempt will be made to load all ldif files
|
||||
* found on the classpath.
|
||||
*/
|
||||
public static final String ATT_LDIF_FILE = "ldif";
|
||||
private static final String OPT_DEFAULT_LDIF_FILE = "classpath*:*.ldif";
|
||||
|
||||
/** Defines the port the LDAP_PROVIDER server should run on */
|
||||
public static final String ATT_PORT = "port";
|
||||
public static final String OPT_DEFAULT_PORT = "33389";
|
||||
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
String url = elt.getAttribute(ATT_URL);
|
||||
|
||||
RootBeanDefinition contextSource;
|
||||
|
||||
if (!StringUtils.hasText(url)) {
|
||||
contextSource = createEmbeddedServer(elt, parserContext);
|
||||
} else {
|
||||
contextSource = new RootBeanDefinition();
|
||||
contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
|
||||
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
|
||||
}
|
||||
|
||||
contextSource.setSource(parserContext.extractSource(elt));
|
||||
|
||||
String managerDn = elt.getAttribute(ATT_PRINCIPAL);
|
||||
String managerPassword = elt.getAttribute(ATT_PASSWORD);
|
||||
|
||||
if (StringUtils.hasText(managerDn)) {
|
||||
if(!StringUtils.hasText(managerPassword)) {
|
||||
parserContext.getReaderContext().error("You must specify the " + ATT_PASSWORD +
|
||||
" if you supply a " + managerDn, elt);
|
||||
}
|
||||
|
||||
contextSource.getPropertyValues().addPropertyValue("userDn", managerDn);
|
||||
contextSource.getPropertyValues().addPropertyValue("password", managerPassword);
|
||||
}
|
||||
|
||||
String id = elt.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
|
||||
|
||||
String contextSourceId = StringUtils.hasText(id) ? id : BeanIds.CONTEXT_SOURCE;
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(contextSourceId, contextSource);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called if no url attribute is supplied.
|
||||
*
|
||||
* Registers beans to create an embedded apache directory server.
|
||||
*
|
||||
* @return the BeanDefinition for the ContextSource for the embedded server.
|
||||
*
|
||||
* @see ApacheDSContainer
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
BeanDefinitionBuilder configuration =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
|
||||
BeanDefinitionBuilder partition =
|
||||
BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
|
||||
configuration.getRawBeanDefinition().setSource(source);
|
||||
partition.getRawBeanDefinition().setSource(source);
|
||||
|
||||
Attributes rootAttributes = new BasicAttributes("dc", "springsecurity");
|
||||
Attribute a = new BasicAttribute("objectClass");
|
||||
a.add("top");
|
||||
a.add("domain");
|
||||
a.add("extensibleObject");
|
||||
rootAttributes.put(a);
|
||||
|
||||
partition.addPropertyValue("name", "springsecurity");
|
||||
partition.addPropertyValue("contextEntry", rootAttributes);
|
||||
|
||||
String suffix = element.getAttribute(ATT_ROOT_SUFFIX);
|
||||
|
||||
if (!StringUtils.hasText(suffix)) {
|
||||
suffix = OPT_DEFAULT_ROOT_SUFFIX;
|
||||
}
|
||||
|
||||
partition.addPropertyValue("suffix", suffix);
|
||||
|
||||
ManagedSet partitions = new ManagedSet(1);
|
||||
partitions.add(partition.getBeanDefinition());
|
||||
|
||||
String port = element.getAttribute(ATT_PORT);
|
||||
|
||||
if (!StringUtils.hasText(port)) {
|
||||
port = OPT_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
configuration.addPropertyValue("ldapPort", port);
|
||||
|
||||
// We shut down the server ourself when the app context is closed so we don't need
|
||||
// the extra shutdown hook from apache DS itself.
|
||||
configuration.addPropertyValue("shutdownHookEnabled", Boolean.FALSE);
|
||||
configuration.addPropertyValue("exitVmOnShutdown", Boolean.FALSE);
|
||||
configuration.addPropertyValue("contextPartitionConfigurations", partitions);
|
||||
|
||||
String url = "ldap://127.0.0.1:" + port + "/" + suffix;
|
||||
|
||||
BeanDefinitionBuilder contextSource = BeanDefinitionBuilder.rootBeanDefinition(CONTEXT_SOURCE_CLASS);
|
||||
contextSource.addConstructorArgValue(url);
|
||||
contextSource.addPropertyValue("userDn", "uid=admin,ou=system");
|
||||
contextSource.addPropertyValue("password", "secret");
|
||||
|
||||
RootBeanDefinition apacheContainer = new RootBeanDefinition("org.springframework.security.config.ldap.ApacheDSContainer", null, null);
|
||||
apacheContainer.setSource(source);
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(configuration.getBeanDefinition());
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource.getBeanDefinition());
|
||||
|
||||
String ldifs = element.getAttribute(ATT_LDIF_FILE);
|
||||
if (!StringUtils.hasText(ldifs)) {
|
||||
ldifs = OPT_DEFAULT_LDIF_FILE;
|
||||
}
|
||||
|
||||
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
|
||||
|
||||
logger.info("Embedded LDAP server bean created for URL: " + url);
|
||||
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_APACHE_DS)) {
|
||||
parserContext.getReaderContext().error("Only one embedded server bean is allowed per application context",
|
||||
element);
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.EMBEDDED_APACHE_DS, apacheContainer);
|
||||
|
||||
return (RootBeanDefinition) contextSource.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
-157
@@ -1,157 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
public static final String ATT_SERVER = "server-ref";
|
||||
public static final String ATT_USER_SEARCH_FILTER = "user-search-filter";
|
||||
public static final String ATT_USER_SEARCH_BASE = "user-search-base";
|
||||
public static final String DEF_USER_SEARCH_BASE = "";
|
||||
|
||||
public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter";
|
||||
public static final String ATT_GROUP_SEARCH_BASE = "group-search-base";
|
||||
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
|
||||
public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})";
|
||||
public static final String DEF_GROUP_SEARCH_BASE = "";
|
||||
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
static final String ATT_USER_CLASS = "user-details-class";
|
||||
static final String OPT_PERSON = "person";
|
||||
static final String OPT_INETORGPERSON = "inetOrgPerson";
|
||||
|
||||
public static final String LDAP_SEARCH_CLASS = "org.springframework.security.ldap.search.FilterBasedLdapUserSearch";
|
||||
public static final String PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.PersonContextMapper";
|
||||
public static final String INET_ORG_PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper";
|
||||
public static final String LDAP_USER_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.LdapUserDetailsMapper";
|
||||
public static final String LDAP_AUTHORITIES_POPULATOR_CLASS = "org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator";
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.ldap.LdapUserDetailsService";
|
||||
}
|
||||
|
||||
protected void doParse(Element elt, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
if (!StringUtils.hasText(elt.getAttribute(ATT_USER_SEARCH_FILTER))) {
|
||||
parserContext.getReaderContext().error("User search filter must be supplied", elt);
|
||||
}
|
||||
|
||||
builder.addConstructorArgValue(parseSearchBean(elt, parserContext));
|
||||
builder.addConstructorArgValue(parseAuthoritiesPopulator(elt, parserContext));
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
|
||||
String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER);
|
||||
String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE);
|
||||
Object source = parserContext.extractSource(elt);
|
||||
|
||||
if (StringUtils.hasText(userSearchBase)) {
|
||||
if(!StringUtils.hasText(userSearchFilter)) {
|
||||
parserContext.getReaderContext().error(ATT_USER_SEARCH_BASE + " cannot be used without a " + ATT_USER_SEARCH_FILTER, source);
|
||||
}
|
||||
} else {
|
||||
userSearchBase = DEF_USER_SEARCH_BASE;
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(userSearchFilter)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
|
||||
searchBuilder.getRawBeanDefinition().setSource(source);
|
||||
searchBuilder.addConstructorArgValue(userSearchBase);
|
||||
searchBuilder.addConstructorArgValue(userSearchFilter);
|
||||
searchBuilder.addConstructorArgValue(parseServerReference(elt, parserContext));
|
||||
|
||||
return (RootBeanDefinition) searchBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) {
|
||||
String server = elt.getAttribute(ATT_SERVER);
|
||||
boolean requiresDefaultName = false;
|
||||
|
||||
if (!StringUtils.hasText(server)) {
|
||||
server = BeanIds.CONTEXT_SOURCE;
|
||||
requiresDefaultName = true;
|
||||
}
|
||||
|
||||
RuntimeBeanReference contextSource = new RuntimeBeanReference(server);
|
||||
contextSource.setSource(parserContext.extractSource(elt));
|
||||
registerPostProcessorIfNecessary(parserContext.getRegistry(), requiresDefaultName);
|
||||
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
private static void registerPostProcessorIfNecessary(BeanDefinitionRegistry registry, boolean defaultNameRequired) {
|
||||
if (registry.containsBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR)) {
|
||||
if (defaultNameRequired) {
|
||||
BeanDefinition bd = registry.getBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR);
|
||||
bd.getPropertyValues().addPropertyValue("defaultNameRequired", Boolean.valueOf(defaultNameRequired));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.ldap.ContextSourceSettingPostProcessor");
|
||||
bdb.addPropertyValue("defaultNameRequired", Boolean.valueOf(defaultNameRequired));
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR, bdb.getBeanDefinition());
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
|
||||
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
|
||||
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);
|
||||
String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE);
|
||||
String rolePrefix = elt.getAttribute(ATT_ROLE_PREFIX);
|
||||
|
||||
if (!StringUtils.hasText(groupSearchFilter)) {
|
||||
groupSearchFilter = DEF_GROUP_SEARCH_FILTER;
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(groupSearchBase)) {
|
||||
groupSearchBase = DEF_GROUP_SEARCH_BASE;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
|
||||
populator.getRawBeanDefinition().setSource(parserContext.extractSource(elt));
|
||||
populator.addConstructorArgValue(parseServerReference(elt, parserContext));
|
||||
populator.addConstructorArgValue(groupSearchBase);
|
||||
populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
|
||||
populator.addPropertyValue("searchSubtree", Boolean.TRUE);
|
||||
|
||||
if (StringUtils.hasText(rolePrefix)) {
|
||||
if ("none".equals(rolePrefix)) {
|
||||
rolePrefix = "";
|
||||
}
|
||||
populator.addPropertyValue("rolePrefix", rolePrefix);
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(groupRoleAttribute)) {
|
||||
populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
|
||||
}
|
||||
|
||||
return (RootBeanDefinition) populator.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ui.logout.LogoutFilter;
|
||||
import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_LOGOUT_SUCCESS_URL = "logout-success-url";
|
||||
static final String DEF_LOGOUT_SUCCESS_URL = "/";
|
||||
|
||||
static final String ATT_INVALIDATE_SESSION = "invalidate-session";
|
||||
static final String DEF_INVALIDATE_SESSION = "true";
|
||||
|
||||
static final String ATT_LOGOUT_URL = "logout-url";
|
||||
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
|
||||
|
||||
String rememberMeServices;
|
||||
|
||||
public LogoutBeanDefinitionParser(String rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String logoutUrl = null;
|
||||
String logoutSuccessUrl = null;
|
||||
String invalidateSession = null;
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
|
||||
|
||||
if (element != null) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
builder.getRawBeanDefinition().setSource(source);
|
||||
logoutUrl = element.getAttribute(ATT_LOGOUT_URL);
|
||||
ConfigUtils.validateHttpRedirect(logoutUrl, parserContext, source);
|
||||
logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
|
||||
ConfigUtils.validateHttpRedirect(logoutSuccessUrl, parserContext, source);
|
||||
invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(logoutUrl)) {
|
||||
logoutUrl = DEF_LOGOUT_URL;
|
||||
}
|
||||
builder.addPropertyValue("filterProcessesUrl", logoutUrl);
|
||||
|
||||
if (!StringUtils.hasText(logoutSuccessUrl)) {
|
||||
logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL;
|
||||
}
|
||||
builder.addConstructorArgValue(logoutSuccessUrl);
|
||||
|
||||
if (!StringUtils.hasText(invalidateSession)) {
|
||||
invalidateSession = DEF_INVALIDATE_SESSION;
|
||||
}
|
||||
|
||||
ManagedList handlers = new ManagedList();
|
||||
SecurityContextLogoutHandler sclh = new SecurityContextLogoutHandler();
|
||||
if ("true".equals(invalidateSession)) {
|
||||
sclh.setInvalidateHttpSession(true);
|
||||
} else {
|
||||
sclh.setInvalidateHttpSession(false);
|
||||
}
|
||||
handlers.add(sclh);
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
handlers.add(new RuntimeBeanReference(rememberMeServices));
|
||||
}
|
||||
|
||||
builder.addConstructorArgValue(handlers);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.LOGOUT_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.AfterInvocationManager;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor which sets the AfterInvocationManager on the global MethodSecurityInterceptor,
|
||||
* if one has been configured.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public class MethodSecurityInterceptorPostProcessor implements BeanPostProcessor, BeanFactoryAware{
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!GlobalMethodSecurityBeanDefinitionParser.SECURITY_INTERCEPTOR_ID.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
MethodSecurityInterceptor interceptor = (MethodSecurityInterceptor) bean;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
logger.debug("Setting AfterInvocationManaer on MethodSecurityInterceptor");
|
||||
interceptor.setAfterInvocationManager((AfterInvocationManager)
|
||||
beanFactory.getBean(BeanIds.AFTER_INVOCATION_MANAGER));
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.security.providers.AuthenticationProvider;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Extended version of {@link ProviderManager the default authentication manager} which lazily initializes
|
||||
* the list of {@link AuthenticationProvider}s. This prevents some of the issues that have occurred with
|
||||
* namespace configuration where early instantiation of a security interceptor has caused the AuthenticationManager
|
||||
* and thus dependent beans (typically UserDetailsService implementations or DAOs) to be initialized too early.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class NamespaceAuthenticationManager extends ProviderManager implements BeanFactoryAware {
|
||||
BeanFactory beanFactory;
|
||||
List<String> providerBeanNames;
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(providerBeanNames, "provideBeanNames has not been set");
|
||||
Assert.notEmpty(providerBeanNames, "No authentication providers were found in the application context");
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to lazily-initialize the list of providers on first use.
|
||||
*/
|
||||
public List<AuthenticationProvider> getProviders() {
|
||||
// We use the names array to determine whether the list has been set yet.
|
||||
if (providerBeanNames != null) {
|
||||
ArrayList<AuthenticationProvider> providers = new ArrayList<AuthenticationProvider>();
|
||||
Iterator<String> beanNames = providerBeanNames.iterator();
|
||||
|
||||
while (beanNames.hasNext()) {
|
||||
providers.add((AuthenticationProvider) beanFactory.getBean(beanNames.next()));
|
||||
}
|
||||
providerBeanNames = null;
|
||||
providers.trimToSize();
|
||||
|
||||
setProviders(providers);
|
||||
}
|
||||
|
||||
return super.getProviders();
|
||||
}
|
||||
|
||||
public void setProviderBeanNames(List<String> provideBeanNames) {
|
||||
this.providerBeanNames = provideBeanNames;
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.ui.FilterChainOrder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
|
||||
* This allows user to add their own custom filters to the security chain. If the user's filter
|
||||
* already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
public static final String ATT_AFTER = "after";
|
||||
public static final String ATT_BEFORE = "before";
|
||||
public static final String ATT_POSITION = "position";
|
||||
|
||||
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
|
||||
Element elt = (Element)node;
|
||||
String order = getOrder(elt, parserContext);
|
||||
|
||||
BeanDefinitionBuilder wrapper = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.config.OrderedFilterBeanDefinitionDecorator$OrderedFilterDecorator");
|
||||
wrapper.addConstructorArgValue(holder.getBeanName());
|
||||
wrapper.addConstructorArgValue(new RuntimeBeanReference(holder.getBeanName()));
|
||||
|
||||
if (StringUtils.hasText(order)) {
|
||||
wrapper.addPropertyValue("order", order);
|
||||
}
|
||||
|
||||
ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the order of the filter by parsing the 'before' or 'after' attributes.
|
||||
*/
|
||||
private String getOrder(Element elt, ParserContext pc) {
|
||||
String after = elt.getAttribute(ATT_AFTER);
|
||||
String before = elt.getAttribute(ATT_BEFORE);
|
||||
String position = elt.getAttribute(ATT_POSITION);
|
||||
|
||||
if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
|
||||
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
|
||||
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(position)) {
|
||||
return Integer.toString(FilterChainOrder.getOrder(position));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(after)) {
|
||||
int order = FilterChainOrder.getOrder(after);
|
||||
|
||||
return Integer.toString(order == Integer.MAX_VALUE ? order : order + 1);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(before)) {
|
||||
int order = FilterChainOrder.getOrder(before);
|
||||
|
||||
return Integer.toString(order == Integer.MIN_VALUE ? order : order - 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static class OrderedFilterDecorator implements Filter, Ordered {
|
||||
private Integer order = null;
|
||||
private Filter delegate;
|
||||
private String beanName;
|
||||
|
||||
OrderedFilterDecorator(String beanName, Filter delegate) {
|
||||
this.delegate = delegate;
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
delegate.doFilter(request, response, chain);
|
||||
}
|
||||
|
||||
public final void init(FilterConfig filterConfig) throws ServletException {
|
||||
delegate.init(filterConfig);
|
||||
}
|
||||
|
||||
public final void destroy() {
|
||||
delegate.destroy();
|
||||
}
|
||||
|
||||
public final int getOrder() {
|
||||
if(order == null) {
|
||||
Assert.isInstanceOf(Ordered.class, delegate, "Filter '"+ beanName +"' must implement the 'Ordered' interface " +
|
||||
" or you must specify one of the attributes '" + ATT_AFTER + "' or '" +
|
||||
ATT_BEFORE + "' in <" + Elements.CUSTOM_FILTER +">");
|
||||
|
||||
return ((Ordered)delegate).getOrder();
|
||||
}
|
||||
return order.intValue();
|
||||
}
|
||||
|
||||
public final void setOrder(int order) {
|
||||
this.order = new Integer(order);
|
||||
}
|
||||
|
||||
public String getBeanName() {
|
||||
return beanName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
|
||||
}
|
||||
|
||||
Filter getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.providers.encoding.BaseDigestPasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.LdapShaPasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.Md4PasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.Md5PasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.PasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.ShaPasswordEncoder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Stateful parser for the <password-encoder> element.
|
||||
*
|
||||
* Will produce a PasswordEncoder and (optionally) a SaltSource.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
class PasswordEncoderParser {
|
||||
static final String ATT_REF = "ref";
|
||||
static final String ATT_HASH = "hash";
|
||||
static final String ATT_BASE_64 = "base64";
|
||||
static final String OPT_HASH_PLAINTEXT = "plaintext";
|
||||
static final String OPT_HASH_SHA = "sha";
|
||||
static final String OPT_HASH_SHA256 = "sha-256";
|
||||
static final String OPT_HASH_MD4 = "md4";
|
||||
static final String OPT_HASH_MD5 = "md5";
|
||||
static final String OPT_HASH_LDAP_SHA = "{sha}";
|
||||
|
||||
private static final Map<String, Class<? extends PasswordEncoder>> ENCODER_CLASSES;
|
||||
|
||||
static {
|
||||
ENCODER_CLASSES = new HashMap<String, Class<? extends PasswordEncoder>>();
|
||||
ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_SHA256, ShaPasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_MD5, Md5PasswordEncoder.class);
|
||||
ENCODER_CLASSES.put(OPT_HASH_LDAP_SHA, LdapShaPasswordEncoder.class);
|
||||
}
|
||||
|
||||
private static Log logger = LogFactory.getLog(PasswordEncoderParser.class);
|
||||
|
||||
private BeanMetadataElement passwordEncoder;
|
||||
private BeanMetadataElement saltSource;
|
||||
|
||||
public PasswordEncoderParser(Element element, ParserContext parserContext) {
|
||||
parse(element, parserContext);
|
||||
}
|
||||
|
||||
private void parse(Element element, ParserContext parserContext) {
|
||||
String hash = element.getAttribute(ATT_HASH);
|
||||
boolean useBase64 = false;
|
||||
|
||||
if (StringUtils.hasText(element.getAttribute(ATT_BASE_64))) {
|
||||
useBase64 = new Boolean(element.getAttribute(ATT_BASE_64)).booleanValue();
|
||||
}
|
||||
|
||||
String ref = element.getAttribute(ATT_REF);
|
||||
|
||||
if (StringUtils.hasText(ref)) {
|
||||
passwordEncoder = new RuntimeBeanReference(ref);
|
||||
} else {
|
||||
passwordEncoder = createPasswordEncoderBeanDefinition(hash, useBase64);
|
||||
((RootBeanDefinition)passwordEncoder).setSource(parserContext.extractSource(element));
|
||||
}
|
||||
|
||||
Element saltSourceElt = DomUtils.getChildElementByTagName(element, Elements.SALT_SOURCE);
|
||||
|
||||
if (saltSourceElt != null) {
|
||||
saltSource = new SaltSourceBeanDefinitionParser().parse(saltSourceElt, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
static BeanDefinition createPasswordEncoderBeanDefinition(String hash, boolean useBase64) {
|
||||
Class<? extends PasswordEncoder> beanClass = ENCODER_CLASSES.get(hash);
|
||||
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
|
||||
|
||||
if (OPT_HASH_SHA256.equals(hash)) {
|
||||
beanBldr.addConstructorArgValue(new Integer(256));
|
||||
}
|
||||
|
||||
if (useBase64) {
|
||||
if (BaseDigestPasswordEncoder.class.isAssignableFrom(beanClass)) {
|
||||
beanBldr.addPropertyValue("encodeHashAsBase64", "true");
|
||||
} else {
|
||||
logger.warn(ATT_BASE_64 + " isn't compatible with " + hash + " and will be ignored");
|
||||
}
|
||||
}
|
||||
return beanBldr.getBeanDefinition();
|
||||
}
|
||||
|
||||
public BeanMetadataElement getPasswordEncoder() {
|
||||
return passwordEncoder;
|
||||
}
|
||||
|
||||
public BeanMetadataElement getSaltSource() {
|
||||
return saltSource;
|
||||
}
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.util.PortMapperImpl;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Parses a port-mappings element, producing a single {@link org.springframework.security.util.PortMapperImpl}
|
||||
* bean.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PortMappingsBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public static final String ATT_HTTP_PORT = "http";
|
||||
public static final String ATT_HTTPS_PORT = "https";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
RootBeanDefinition portMapper = new RootBeanDefinition(PortMapperImpl.class);
|
||||
portMapper.setSource(parserContext.extractSource(element));
|
||||
|
||||
if (element != null) {
|
||||
List<Element> mappingElts = DomUtils.getChildElementsByTagName(element, Elements.PORT_MAPPING);
|
||||
if(mappingElts.isEmpty()) {
|
||||
parserContext.getReaderContext().error("No port-mapping child elements specified", element);
|
||||
}
|
||||
|
||||
Map mappings = new HashMap();
|
||||
|
||||
for (Element elt : mappingElts) {
|
||||
String httpPort = elt.getAttribute(ATT_HTTP_PORT);
|
||||
String httpsPort = elt.getAttribute(ATT_HTTPS_PORT);
|
||||
|
||||
if (!StringUtils.hasText(httpPort)) {
|
||||
parserContext.getReaderContext().error("No http port supplied in port mapping", elt);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(httpsPort)) {
|
||||
parserContext.getReaderContext().error("No https port supplied in port mapping", elt);
|
||||
}
|
||||
|
||||
mappings.put(httpPort, httpsPort);
|
||||
}
|
||||
|
||||
portMapper.getPropertyValues().addPropertyValue("portMappings", mappings);
|
||||
}
|
||||
|
||||
return portMapper;
|
||||
}
|
||||
}
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ui.rememberme.JdbcTokenRepositoryImpl;
|
||||
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.RememberMeProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
static final String ATT_KEY = "key";
|
||||
static final String DEF_KEY = "SpringSecured";
|
||||
|
||||
static final String ATT_DATA_SOURCE = "data-source-ref";
|
||||
static final String ATT_SERVICES_REF = "services-ref";
|
||||
static final String ATT_TOKEN_REPOSITORY = "token-repository-ref";
|
||||
static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
private String servicesName;
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
String tokenRepository = null;
|
||||
String dataSource = null;
|
||||
String key = null;
|
||||
Object source = null;
|
||||
String userServiceRef = null;
|
||||
String rememberMeServicesRef = null;
|
||||
String tokenValiditySeconds = null;
|
||||
|
||||
if (element != null) {
|
||||
tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
|
||||
dataSource = element.getAttribute(ATT_DATA_SOURCE);
|
||||
key = element.getAttribute(ATT_KEY);
|
||||
userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
rememberMeServicesRef = element.getAttribute(ATT_SERVICES_REF);
|
||||
tokenValiditySeconds = element.getAttribute(ATT_TOKEN_VALIDITY);
|
||||
source = parserContext.extractSource(element);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
key = DEF_KEY;
|
||||
}
|
||||
|
||||
RootBeanDefinition services = null;
|
||||
|
||||
boolean dataSourceSet = StringUtils.hasText(dataSource);
|
||||
boolean tokenRepoSet = StringUtils.hasText(tokenRepository);
|
||||
boolean servicesRefSet = StringUtils.hasText(rememberMeServicesRef);
|
||||
boolean userServiceSet = StringUtils.hasText(userServiceRef);
|
||||
boolean tokenValiditySet = StringUtils.hasText(tokenValiditySeconds);
|
||||
|
||||
if (servicesRefSet && (dataSourceSet || tokenRepoSet || userServiceSet || tokenValiditySet)) {
|
||||
parserContext.getReaderContext().error(ATT_SERVICES_REF + " can't be used in combination with attributes "
|
||||
+ ATT_TOKEN_REPOSITORY + "," + ATT_DATA_SOURCE + ", " + ATT_USER_SERVICE_REF + " or " + ATT_TOKEN_VALIDITY, source);
|
||||
}
|
||||
|
||||
if (dataSourceSet && tokenRepoSet) {
|
||||
parserContext.getReaderContext().error("Specify " + ATT_TOKEN_REPOSITORY + " or " +
|
||||
ATT_DATA_SOURCE +" but not both", source);
|
||||
}
|
||||
|
||||
boolean isPersistent = dataSourceSet | tokenRepoSet;
|
||||
|
||||
if (isPersistent) {
|
||||
Object tokenRepo;
|
||||
services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
|
||||
|
||||
if (tokenRepoSet) {
|
||||
tokenRepo = new RuntimeBeanReference(tokenRepository);
|
||||
} else {
|
||||
tokenRepo = new RootBeanDefinition(JdbcTokenRepositoryImpl.class);
|
||||
((BeanDefinition)tokenRepo).getPropertyValues().addPropertyValue("dataSource",
|
||||
new RuntimeBeanReference(dataSource));
|
||||
}
|
||||
services.getPropertyValues().addPropertyValue("tokenRepository", tokenRepo);
|
||||
} else if (!servicesRefSet) {
|
||||
services = new RootBeanDefinition(TokenBasedRememberMeServices.class);
|
||||
}
|
||||
|
||||
if (services != null) {
|
||||
if (userServiceSet) {
|
||||
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
}
|
||||
|
||||
if (tokenValiditySet) {
|
||||
Integer tokenValidity = new Integer(tokenValiditySeconds);
|
||||
if (tokenValidity.intValue() < 0 && isPersistent) {
|
||||
parserContext.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
|
||||
" a persistent remember-me token repository", source);
|
||||
}
|
||||
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValidity);
|
||||
}
|
||||
services.setSource(source);
|
||||
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
|
||||
servicesName = BeanIds.REMEMBER_ME_SERVICES;
|
||||
} else {
|
||||
servicesName = rememberMeServicesRef;
|
||||
parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
|
||||
}
|
||||
|
||||
registerProvider(parserContext, source, key);
|
||||
|
||||
registerFilter(parserContext, source);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String getServicesName() {
|
||||
return servicesName;
|
||||
}
|
||||
|
||||
private void registerProvider(ParserContext pc, Object source, String key) {
|
||||
//BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
|
||||
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
provider.setSource(source);
|
||||
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(pc, BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER);
|
||||
}
|
||||
|
||||
private void registerFilter(ParserContext pc, Object source) {
|
||||
RootBeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
filter.setSource(source);
|
||||
filter.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_FILTER, filter);
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.REMEMBER_ME_FILTER));
|
||||
}
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.RememberMeServices;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof AbstractProcessingFilter) {
|
||||
AbstractProcessingFilter pf = (AbstractProcessingFilter) bean;
|
||||
|
||||
if (pf.getRememberMeServices() == null) {
|
||||
logger.info("Setting RememberMeServices on bean " + beanName);
|
||||
pf.setRememberMeServices(getRememberMeServices());
|
||||
}
|
||||
} else if (BeanIds.BASIC_AUTHENTICATION_FILTER.equals(beanName)) {
|
||||
// NB: For remember-me to be sent back, a user must submit a "_spring_security_remember_me" with their login request.
|
||||
// Most of the time a user won't present such a parameter with their BASIC authentication request.
|
||||
// In the future we might support setting the AbstractRememberMeServices.alwaysRemember = true, but I am reluctant to
|
||||
// do so because it seems likely to lead to lower security for 99.99% of users if they set the property to true.
|
||||
|
||||
BasicProcessingFilter bf = (BasicProcessingFilter) bean;
|
||||
logger.info("Setting RememberMeServices on bean " + beanName);
|
||||
bf.setRememberMeServices(getRememberMeServices());
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private RememberMeServices getRememberMeServices() {
|
||||
Map<?,?> beans = beanFactory.getBeansOfType(RememberMeServices.class);
|
||||
|
||||
Assert.isTrue(beans.size() > 0, "No RememberMeServices configured");
|
||||
Assert.isTrue(beans.size() == 1, "Use of '<remember-me />' requires a single instance of RememberMeServices " +
|
||||
"in the application context, but more than one was found.");
|
||||
|
||||
return (RememberMeServices) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.providers.dao.salt.ReflectionSaltSource;
|
||||
import org.springframework.security.providers.dao.salt.SystemWideSaltSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
class SaltSourceBeanDefinitionParser {
|
||||
private static final String ATT_USER_PROPERTY = "user-property";
|
||||
private static final String ATT_REF = "ref";
|
||||
private static final String ATT_SYSTEM_WIDE = "system-wide";
|
||||
|
||||
public BeanMetadataElement parse(Element element, ParserContext parserContext) {
|
||||
String ref = element.getAttribute(ATT_REF);
|
||||
|
||||
if (StringUtils.hasText(ref)) {
|
||||
return new RuntimeBeanReference(ref);
|
||||
}
|
||||
|
||||
String userProperty = element.getAttribute(ATT_USER_PROPERTY);
|
||||
RootBeanDefinition saltSource;
|
||||
|
||||
if (StringUtils.hasText(userProperty)) {
|
||||
saltSource = new RootBeanDefinition(ReflectionSaltSource.class);
|
||||
saltSource.getPropertyValues().addPropertyValue("userPropertyToUse", userProperty);
|
||||
saltSource.setSource(parserContext.extractSource(element));
|
||||
saltSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
return saltSource;
|
||||
}
|
||||
|
||||
String systemWideSalt = element.getAttribute(ATT_SYSTEM_WIDE);
|
||||
|
||||
if (StringUtils.hasText(systemWideSalt)) {
|
||||
saltSource = new RootBeanDefinition(SystemWideSaltSource.class);
|
||||
saltSource.getPropertyValues().addPropertyValue("systemWideSalt", systemWideSalt);
|
||||
saltSource.setSource(parserContext.extractSource(element));
|
||||
saltSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
return saltSource;
|
||||
}
|
||||
|
||||
parserContext.getReaderContext().error(Elements.SALT_SOURCE + " requires an attribute", element);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecurityConfigurationException extends SpringSecurityException {
|
||||
public SecurityConfigurationException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public SecurityConfigurationException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
/**
|
||||
* Registers the bean definition parsers for the "security" namespace (http://www.springframework.org/schema/security).
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @since 2.0
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
// Parsers
|
||||
registerBeanDefinitionParser(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
|
||||
registerBeanDefinitionParser(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceBeanDefinitionParser());
|
||||
|
||||
// Decorators
|
||||
registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
|
||||
registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
|
||||
}
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionController;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
|
||||
import org.springframework.security.concurrent.SessionRegistry;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Registered by the <tt>AuthenticationManagerBeanDefinitionParser</tt> if an external
|
||||
* ConcurrentSessionController is set (and hence an external SessionRegistry).
|
||||
* Its responsibility is to set the SessionRegistry on namespace-registered beans which require access
|
||||
* to it.
|
||||
* <p>
|
||||
* It will attempt to read the registry directly from the registered controller. If that fails, it will look in
|
||||
* the application context for a registered SessionRegistry bean.
|
||||
*
|
||||
* See SEC-879.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.3
|
||||
*/
|
||||
class SessionRegistryInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
private ListableBeanFactory beanFactory;
|
||||
private SessionRegistry sessionRegistry;
|
||||
private final String controllerBeanName;
|
||||
|
||||
SessionRegistryInjectionBeanPostProcessor(String controllerBeanName) {
|
||||
this.controllerBeanName = controllerBeanName;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.FORM_LOGIN_FILTER.equals(beanName) ||
|
||||
BeanIds.OPEN_ID_FILTER.equals(beanName)) {
|
||||
((AbstractProcessingFilter) bean).setSessionRegistry(getSessionRegistry());
|
||||
} else if (BeanIds.SESSION_FIXATION_PROTECTION_FILTER.equals(beanName)) {
|
||||
((SessionFixationProtectionFilter)bean).setSessionRegistry(getSessionRegistry());
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private SessionRegistry getSessionRegistry() {
|
||||
if (sessionRegistry != null) {
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
logger.info("Attempting to read SessionRegistry from registered ConcurrentSessionController bean");
|
||||
|
||||
ConcurrentSessionController controller = (ConcurrentSessionController) beanFactory.getBean(controllerBeanName);
|
||||
|
||||
if (controller instanceof ConcurrentSessionControllerImpl) {
|
||||
sessionRegistry = ((ConcurrentSessionControllerImpl)controller).getSessionRegistry();
|
||||
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
logger.info("ConcurrentSessionController is not a standard implementation. SessionRegistry could not be read from it. Looking for it in the context.");
|
||||
|
||||
List<SessionRegistry> sessionRegs = new ArrayList<SessionRegistry>(beanFactory.getBeansOfType(SessionRegistry.class).values());
|
||||
|
||||
if (sessionRegs.size() == 0) {
|
||||
throw new SecurityConfigurationException("concurrent-session-controller-ref was set but no SessionRegistry could be obtained from the application context.");
|
||||
}
|
||||
|
||||
if (sessionRegs.size() > 1) {
|
||||
logger.warn("More than one SessionRegistry instance in application context. Possible configuration errors may result.");
|
||||
}
|
||||
|
||||
sessionRegistry = sessionRegs.get(0);
|
||||
|
||||
return sessionRegistry;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.ui.rememberme.AbstractRememberMeServices;
|
||||
import org.springframework.security.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Registered by {@link HttpSecurityBeanDefinitionParser} to inject a UserDetailsService into
|
||||
* the X509Provider, RememberMeServices and OpenIDAuthenticationProvider instances created by
|
||||
* the namespace.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
|
||||
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
|
||||
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
|
||||
injectUserDetailsServiceIntoOpenIDProvider(bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoRememberMeServices(AbstractRememberMeServices services) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
services.setUserDetailsService(getUserDetailsService());
|
||||
} else {
|
||||
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
|
||||
|
||||
if (cachingUserService != null) {
|
||||
services.setUserDetailsService(cachingUserService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoX509Provider(PreAuthenticatedAuthenticationProvider provider) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
|
||||
UserDetailsByNameServiceWrapper wrapper = new UserDetailsByNameServiceWrapper();
|
||||
|
||||
if (pv == null) {
|
||||
wrapper.setUserDetailsService(getUserDetailsService());
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
} else {
|
||||
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
|
||||
Object userService =
|
||||
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
|
||||
|
||||
UserDetailsService cachingUserService = getCachingUserService(userService);
|
||||
|
||||
if (cachingUserService != null) {
|
||||
wrapper.setUserDetailsService(cachingUserService);
|
||||
provider.setPreAuthenticatedUserDetailsService(wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void injectUserDetailsServiceIntoOpenIDProvider(Object bean) {
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
|
||||
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
|
||||
|
||||
if (pv == null) {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
|
||||
beanWrapper.setPropertyValue("userDetailsService", getUserDetailsService());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version
|
||||
* if available so should not be used for beans which need to separate the two.
|
||||
*/
|
||||
UserDetailsService getUserDetailsService() {
|
||||
Map<?,?> beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
beans = beanFactory.getBeansOfType(UserDetailsService.class);
|
||||
}
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new SecurityConfigurationException("No UserDetailsService registered.");
|
||||
|
||||
} else if (beans.size() > 1) {
|
||||
throw new SecurityConfigurationException("More than one UserDetailsService registered. Please " +
|
||||
"use a specific Id reference in <remember-me/> <openid-login/> or <x509 /> elements.");
|
||||
}
|
||||
|
||||
return (UserDetailsService) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
private UserDetailsService getCachingUserService(Object userServiceRef) {
|
||||
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
|
||||
"userDetailsService property value must be a RuntimeBeanReference");
|
||||
|
||||
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
|
||||
// Overwrite with the caching version if available
|
||||
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
|
||||
|
||||
if (beanFactory.containsBeanDefinition(cachingId)) {
|
||||
return (UserDetailsService) beanFactory.getBean(cachingId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.security.userdetails.memory.UserMap;
|
||||
import org.springframework.security.userdetails.User;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
|
||||
|
||||
static final String ATT_PASSWORD = "password";
|
||||
static final String ATT_NAME = "name";
|
||||
static final String ELT_USER = "user";
|
||||
static final String ATT_AUTHORITIES = "authorities";
|
||||
static final String ATT_PROPERTIES = "properties";
|
||||
static final String ATT_DISABLED = "disabled";
|
||||
static final String ATT_LOCKED = "locked";
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.security.userdetails.memory.InMemoryDaoImpl";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String userProperties = element.getAttribute(ATT_PROPERTIES);
|
||||
List<Element> userElts = DomUtils.getChildElementsByTagName(element, ELT_USER);
|
||||
|
||||
if (StringUtils.hasText(userProperties)) {
|
||||
|
||||
if(!CollectionUtils.isEmpty(userElts)) {
|
||||
throw new BeanDefinitionStoreException("Use of a properties file and user elements are mutually exclusive");
|
||||
}
|
||||
|
||||
BeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);
|
||||
bd.getPropertyValues().addPropertyValue("location", userProperties);
|
||||
builder.addPropertyValue("userProperties", bd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(CollectionUtils.isEmpty(userElts)) {
|
||||
throw new BeanDefinitionStoreException("You must supply user definitions, either with <" + ELT_USER + "> child elements or a " +
|
||||
"properties file (using the '" + ATT_PROPERTIES + "' attribute)" );
|
||||
}
|
||||
|
||||
UserMap users = new UserMap();
|
||||
|
||||
for (Iterator i = userElts.iterator(); i.hasNext();) {
|
||||
Element userElt = (Element) i.next();
|
||||
String userName = userElt.getAttribute(ATT_NAME);
|
||||
String password = userElt.getAttribute(ATT_PASSWORD);
|
||||
boolean locked = "true".equals(userElt.getAttribute(ATT_LOCKED));
|
||||
boolean disabled = "true".equals(userElt.getAttribute(ATT_DISABLED));
|
||||
|
||||
users.addUser(new User(userName, password, !disabled, true, true, !locked,
|
||||
AuthorityUtils.commaSeparatedStringToAuthorityList(userElt.getAttribute(ATT_AUTHORITIES))));
|
||||
}
|
||||
|
||||
builder.addPropertyValue("userMap", users);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.security.ui.preauth.PreAuthenticatedProcessingFilterEntryPoint;
|
||||
import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.ui.preauth.x509.SubjectDnX509PrincipalExtractor;
|
||||
import org.springframework.security.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parses x509 element in namespace, registering an {@link X509PreAuthenticatedProcessingFilter} instance and a
|
||||
* {@link PreAuthenticatedProcessingFilterEntryPoint}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
public class X509BeanDefinitionParser implements BeanDefinitionParser {
|
||||
public static final String ATT_REGEX = "subject-principal-regex";
|
||||
public static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509PreAuthenticatedProcessingFilter.class);
|
||||
RootBeanDefinition entryPoint = new RootBeanDefinition(PreAuthenticatedProcessingFilterEntryPoint.class);
|
||||
|
||||
Object source = parserContext.extractSource(element);
|
||||
filterBuilder.getRawBeanDefinition().setSource(source);
|
||||
entryPoint.setSource(source);
|
||||
|
||||
String regex = element.getAttribute(ATT_REGEX);
|
||||
|
||||
if (StringUtils.hasText(regex)) {
|
||||
SubjectDnX509PrincipalExtractor extractor = new SubjectDnX509PrincipalExtractor();
|
||||
extractor.setSubjectDnRegex(regex);
|
||||
|
||||
filterBuilder.addPropertyValue("principalExtractor", extractor);
|
||||
}
|
||||
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider);
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.X509_AUTH_PROVIDER);
|
||||
|
||||
String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
if (StringUtils.hasText(userServiceRef)) {
|
||||
RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class);
|
||||
preAuthUserService.setSource(source);
|
||||
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService);
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.PRE_AUTH_ENTRY_POINT, entryPoint);
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_FILTER, filterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.X509_FILTER));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -12,7 +12,6 @@ import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.config.SecurityConfigurationException;
|
||||
import org.springframework.security.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.expression.annotation.PostAuthorize;
|
||||
import org.springframework.security.expression.annotation.PostFilter;
|
||||
@@ -144,7 +143,7 @@ public class ExpressionAnnotationMethodSecurityMetadataSource extends AbstractMe
|
||||
post = new PostInvocationExpressionAttribute(postFilterExpression, postAuthorizeExpression);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new SecurityConfigurationException("Failed to parse expression '" + e.getExpressionString() + "'", e);
|
||||
throw new IllegalArgumentException("Failed to parse expression '" + e.getExpressionString() + "'", e);
|
||||
}
|
||||
|
||||
List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>(2);
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
package org.springframework.security.util;
|
||||
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext {
|
||||
private static final String BEANS_OPENING =
|
||||
"<b:beans xmlns='http://www.springframework.org/schema/security'\n" +
|
||||
" xmlns:b='http://www.springframework.org/schema/beans'\n" +
|
||||
" xmlns:aop='http://www.springframework.org/schema/aop'\n" +
|
||||
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
|
||||
" xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd'>\n";
|
||||
private static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
|
||||
Resource inMemoryXml;
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml) {
|
||||
this(xml, true);
|
||||
}
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml, boolean addBeansTags) {
|
||||
String fullXml = addBeansTags ? BEANS_OPENING + xml + BEANS_CLOSE : xml;
|
||||
inMemoryXml = new InMemoryResource(fullXml);
|
||||
refresh();
|
||||
}
|
||||
|
||||
protected Resource[] getConfigResources() {
|
||||
return new Resource[] {inMemoryXml};
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
|
||||
@@ -1,6 +0,0 @@
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.5.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.5.xsd=org/springframework/security/config/spring-security-2.5.xsd
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
|
||||
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
|
||||
<system systemId="http://www.springframework.org/schema/security/spring-security-2.0.xsd" uri="spring-security-2.0.xsd"/>
|
||||
</catalog>
|
||||
-1335
File diff suppressed because it is too large
Load Diff
-1422
File diff suppressed because it is too large
Load Diff
-506
@@ -1,506 +0,0 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
|
||||
|
||||
default namespace = "http://www.springframework.org/schema/security"
|
||||
|
||||
start = http | ldap-server | authentication-provider | ldap-authentication-provider | any-user-service | ldap-server | ldap-authentication-provider
|
||||
|
||||
hash =
|
||||
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
|
||||
attribute hash {"plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
|
||||
base64 =
|
||||
## Whether a string should be base64 encoded
|
||||
attribute base64 {"true" | "false"}
|
||||
path-type =
|
||||
## Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified.
|
||||
attribute path-type {"ant" | "regex"}
|
||||
port =
|
||||
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
|
||||
attribute port { xsd:integer }
|
||||
url =
|
||||
## Specifies a URL.
|
||||
attribute url { xsd:string }
|
||||
id =
|
||||
## A bean identifier, used for referring to the bean elsewhere in the context.
|
||||
attribute id {xsd:ID}
|
||||
ref =
|
||||
## Defines a reference to a Spring bean Id.
|
||||
attribute ref {xsd:string}
|
||||
|
||||
cache-ref =
|
||||
## Defines a reference to a cache for use with a UserDetailsService.
|
||||
attribute cache-ref {xsd:string}
|
||||
|
||||
user-service-ref =
|
||||
## A reference to a user-service (or UserDetailsService bean) Id
|
||||
attribute user-service-ref {xsd:string}
|
||||
|
||||
data-source-ref =
|
||||
## A reference to a DataSource bean
|
||||
attribute data-source-ref {xsd:string}
|
||||
|
||||
password-encoder =
|
||||
## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.
|
||||
element password-encoder {password-encoder.attlist, salt-source?}
|
||||
password-encoder.attlist &=
|
||||
ref | (hash? & base64?)
|
||||
|
||||
salt-source =
|
||||
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
|
||||
element salt-source {user-property | system-wide}
|
||||
user-property =
|
||||
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
|
||||
attribute user-property {xsd:string}
|
||||
system-wide =
|
||||
## A single value that will be used as the salt for a password encoder.
|
||||
attribute system-wide {xsd:string}
|
||||
|
||||
boolean = "true" | "false"
|
||||
|
||||
role-prefix =
|
||||
## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.
|
||||
attribute role-prefix {xsd:string}
|
||||
|
||||
|
||||
ldap-server =
|
||||
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
|
||||
element ldap-server {ldap-server.attlist}
|
||||
ldap-server.attlist &= id?
|
||||
ldap-server.attlist &= (url | port)?
|
||||
ldap-server.attlist &=
|
||||
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
|
||||
attribute manager-dn {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## The password for the manager DN.
|
||||
attribute manager-password {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## Explicitly specifies an ldif file resource to load into an embedded LDAP server
|
||||
attribute ldif { xsd:string }?
|
||||
ldap-server.attlist &=
|
||||
## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org"
|
||||
attribute root { xsd:string }?
|
||||
|
||||
ldap-server-ref-attribute =
|
||||
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
|
||||
attribute server-ref {xsd:string}
|
||||
|
||||
|
||||
group-search-filter-attribute =
|
||||
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
||||
attribute group-search-filter {xsd:string}
|
||||
group-search-base-attribute =
|
||||
## Search base for group membership searches. Defaults to "" (searching from the root).
|
||||
attribute group-search-base {xsd:string}
|
||||
user-search-filter-attribute =
|
||||
## The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.
|
||||
attribute user-search-filter {xsd:string}
|
||||
user-search-base-attribute =
|
||||
## Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.
|
||||
attribute user-search-base {xsd:string}
|
||||
group-role-attribute-attribute =
|
||||
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
|
||||
attribute group-role-attribute {xsd:string}
|
||||
user-details-class-attribute =
|
||||
## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object
|
||||
attribute user-details-class {"person" | "inetOrgPerson"}
|
||||
|
||||
|
||||
ldap-user-service =
|
||||
element ldap-user-service {ldap-us.attlist}
|
||||
ldap-us.attlist &= id?
|
||||
ldap-us.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-us.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-us.attlist &=
|
||||
user-search-base-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
ldap-us.attlist &=
|
||||
cache-ref?
|
||||
ldap-us.attlist &=
|
||||
role-prefix?
|
||||
ldap-us.attlist &=
|
||||
user-details-class-attribute?
|
||||
|
||||
ldap-authentication-provider =
|
||||
## Sets up an ldap authentication provider
|
||||
element ldap-authentication-provider {ldap-ap.attlist, password-compare-element?}
|
||||
ldap-ap.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-ap.attlist &=
|
||||
user-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
ldap-ap.attlist &=
|
||||
## A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username.
|
||||
attribute user-dn-pattern {xsd:string}?
|
||||
ldap-ap.attlist &=
|
||||
role-prefix?
|
||||
ldap-ap.attlist &=
|
||||
user-details-class-attribute?
|
||||
|
||||
password-compare-element =
|
||||
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
|
||||
element password-compare {password-compare.attlist, password-encoder?}
|
||||
|
||||
password-compare.attlist &=
|
||||
## The attribute in the directory which contains the user password. Defaults to "userPassword".
|
||||
attribute password-attribute {xsd:string}?
|
||||
password-compare.attlist &=
|
||||
hash?
|
||||
|
||||
intercept-methods =
|
||||
## Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods
|
||||
element intercept-methods {intercept-methods.attlist, protect+}
|
||||
intercept-methods.attlist &=
|
||||
## Optional AccessDecisionManager bean ID to be used by the created method security interceptor.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
|
||||
|
||||
protect =
|
||||
## Defines a protected method and the access control configuration attributes that apply to it. We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security".
|
||||
element protect {protect.attlist, empty}
|
||||
protect.attlist &=
|
||||
## A method name
|
||||
attribute method {xsd:string}
|
||||
protect.attlist &=
|
||||
## Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B".
|
||||
attribute access {xsd:string}
|
||||
|
||||
|
||||
global-method-security =
|
||||
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for Spring Security annotations and/or matches with the ordered list of "protect-pointcut" sub-elements. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all three sources of method security metadata (ie "protect-pointcut" declarations, @Secured and also JSR 250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed by way of @Secured annotations, with @Secured annotations overriding method security metadata expressed by JSR 250 annotations. It is perfectly acceptable to mix and match, with a given Java type using a combination of XML, @Secured and JSR 250 to express method security metadata (albeit on different methods).
|
||||
element global-method-security {global-method-security.attlist, protect-pointcut*}
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Please ensure you have the spring-security-tiger-xxx.jar on the classpath. Defaults to "disabled".
|
||||
attribute secured-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "disabled".
|
||||
attribute jsr250-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Optional AccessDecisionManager bean ID to override the default used for method security.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
|
||||
custom-after-invocation-provider =
|
||||
## Used to decorate an AfterInvocationProvider to specify that it should be used with method security.
|
||||
element custom-after-invocation-provider {empty}
|
||||
|
||||
protect-pointcut =
|
||||
## Defines a protected pointcut and the access control configuration attributes that apply to it. Every bean registered in the Spring application context that provides a method that matches the pointcut will receive security authorization.
|
||||
element protect-pointcut {protect-pointcut.attlist, empty}
|
||||
protect-pointcut.attlist &=
|
||||
## An AspectJ expression, including the 'execution' keyword. For example, 'execution(int com.foo.TargetObject.countLength(String))' (without the quotes).
|
||||
attribute expression {xsd:string}
|
||||
protect-pointcut.attlist &=
|
||||
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
||||
attribute access {xsd:string}
|
||||
|
||||
|
||||
http =
|
||||
## Container element for HTTP security configuration
|
||||
element http {http.attlist, (intercept-url+ & form-login? & openid-login & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) }
|
||||
http.attlist &=
|
||||
## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".
|
||||
attribute auto-config {boolean}?
|
||||
http.attlist &=
|
||||
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired".
|
||||
attribute create-session {"ifRequired" | "always" | "never" }?
|
||||
http.attlist &=
|
||||
## The path format used to define the paths in child elements.
|
||||
path-type?
|
||||
http.attlist &=
|
||||
## Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true".
|
||||
attribute lowercase-comparisons {boolean}?
|
||||
http.attlist &=
|
||||
## Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".
|
||||
attribute servlet-api-provision {boolean}?
|
||||
http.attlist &=
|
||||
## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
http.attlist &=
|
||||
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
||||
attribute realm {xsd:string}?
|
||||
http.attlist &=
|
||||
## Indicates whether an existing session should be invalidated when a user authenticates and a new session started. If set to "none" no change will be made. "newSession" will create a new empty session. "migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession".
|
||||
attribute session-fixation-protection {"none" | "newSession" | "migrateSession" }?
|
||||
http.attlist &=
|
||||
## Allows a customized AuthenticationEntryPoint to be used.
|
||||
attribute entry-point-ref {xsd:string}?
|
||||
http.attlist &=
|
||||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||
attribute once-per-request {boolean}?
|
||||
http.attlist &=
|
||||
## Allows the access denied page to be set (the user will be redirected here if an AccessDeniedException is raised).
|
||||
attribute access-denied-page {xsd:string}?
|
||||
|
||||
intercept-url =
|
||||
## Specifies the access attributes and/or filter list for a particular set of URLs.
|
||||
element intercept-url {intercept-url.attlist, empty}
|
||||
intercept-url.attlist &=
|
||||
## The pattern which defines the URL path. The content will depend on the type set in the containing http element, so will default to ant path syntax.
|
||||
attribute pattern {xsd:string}
|
||||
intercept-url.attlist &=
|
||||
## The access configuration attributes that apply for the configured path.
|
||||
attribute access {xsd:string}?
|
||||
intercept-url.attlist &=
|
||||
## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.
|
||||
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "TRACE"}?
|
||||
|
||||
intercept-url.attlist &=
|
||||
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
|
||||
attribute filters {"none"}?
|
||||
intercept-url.attlist &=
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference.
|
||||
attribute requires-channel {"http" | "https" | "any"}?
|
||||
|
||||
logout =
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
element logout {logout.attlist, empty}
|
||||
logout.attlist &=
|
||||
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
|
||||
attribute logout-url {xsd:string}?
|
||||
logout.attlist &=
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
|
||||
attribute logout-success-url {xsd:string}?
|
||||
logout.attlist &=
|
||||
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
|
||||
attribute invalidate-session {boolean}?
|
||||
|
||||
form-login =
|
||||
## Sets up a form login configuration for authentication with a username and password
|
||||
element form-login {form-login.attlist, empty}
|
||||
form-login.attlist &=
|
||||
## The URL that the login form is posted to. If unspecified, it defaults to /j_spring_security_check.
|
||||
attribute login-processing-url {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.
|
||||
attribute default-target-url {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## Whether the user should always be redirected to the default-target-url after login.
|
||||
attribute always-use-default-target {boolean}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.
|
||||
attribute login-page {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /spring_security_login?login_error and a corresponding filter to render that login failure URL when requested.
|
||||
attribute authentication-failure-url {xsd:string}?
|
||||
|
||||
openid-login =
|
||||
## Sets up form login for authentication with an Open ID identity
|
||||
element openid-login {form-login.attlist, user-service-ref?, empty}
|
||||
|
||||
|
||||
filter-chain-map =
|
||||
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
|
||||
element filter-chain-map {filter-chain-map.attlist, filter-chain+}
|
||||
filter-chain-map.attlist &=
|
||||
path-type
|
||||
|
||||
filter-chain =
|
||||
## Used within filter-chain-map to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. When multiple filter-chain elements are used within a filter-chain-map element, the most specific patterns must be placed at the top of the list, with most general ones at the bottom.
|
||||
element filter-chain {filter-chain.attlist, empty}
|
||||
filter-chain.attlist &=
|
||||
attribute pattern {xsd:string}
|
||||
filter-chain.attlist &=
|
||||
attribute filters {xsd:string}
|
||||
|
||||
filter-invocation-definition-source =
|
||||
## Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
|
||||
element filter-invocation-definition-source {fids.attlist, intercept-url+}
|
||||
fids.attlist &=
|
||||
id?
|
||||
fids.attlist &=
|
||||
## as for http element
|
||||
attribute lowercase-comparisons {boolean}?
|
||||
fids.attlist &=
|
||||
## as for http element
|
||||
path-type?
|
||||
|
||||
http-basic =
|
||||
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
|
||||
element http-basic {empty}
|
||||
|
||||
|
||||
concurrent-session-control =
|
||||
## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have.
|
||||
element concurrent-session-control {concurrent-sessions.attlist, empty}
|
||||
concurrent-sessions.attlist &=
|
||||
## The maximum number of sessions a single user can have open at the same time. Defaults to "1".
|
||||
attribute max-sessions {xsd:positiveInteger}?
|
||||
concurrent-sessions.attlist &=
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because they have logged in again.
|
||||
attribute expired-url {xsd:string}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Specifies that an exception should be raised when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session.
|
||||
attribute exception-if-maximum-exceeded {boolean}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration
|
||||
attribute session-registry-alias {xsd:string}?
|
||||
concurrent-sessions.attlist &=
|
||||
## A reference to an external SessionRegistry implementation which will be used in place of the standard one.
|
||||
attribute session-registry-ref {xsd:string}?
|
||||
|
||||
remember-me =
|
||||
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
|
||||
element remember-me {remember-me.attlist}
|
||||
remember-me.attlist &=
|
||||
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
|
||||
attribute key {xsd:string}?
|
||||
|
||||
remember-me.attlist &=
|
||||
(token-repository-ref | remember-me-data-source-ref | remember-me-services-ref)
|
||||
|
||||
remember-me.attlist &=
|
||||
user-service-ref?
|
||||
|
||||
remember-me.attlist &=
|
||||
## The period (in seconds) for which the remember-me cookie should be valid.
|
||||
attribute token-validity-seconds {xsd:positiveInteger}?
|
||||
|
||||
token-repository-ref =
|
||||
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
|
||||
attribute token-repository-ref {xsd:string}
|
||||
remember-me-services-ref =
|
||||
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
|
||||
attribute services-ref {xsd:string}?
|
||||
remember-me-data-source-ref =
|
||||
## DataSource bean for the database that contains the token repository schema.
|
||||
data-source-ref
|
||||
|
||||
anonymous =
|
||||
## Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority.
|
||||
element anonymous {anonymous.attlist}
|
||||
anonymous.attlist &=
|
||||
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
|
||||
attribute key {xsd:string}?
|
||||
anonymous.attlist &=
|
||||
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
|
||||
attribute username {xsd:string}?
|
||||
anonymous.attlist &=
|
||||
## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".
|
||||
attribute granted-authority {xsd:string}?
|
||||
|
||||
port-mappings =
|
||||
## Defines the list of mappings between http and https ports for use in redirects
|
||||
element port-mappings {port-mappings.attlist, port-mapping+}
|
||||
|
||||
port-mappings.attlist &= empty
|
||||
|
||||
port-mapping =
|
||||
element port-mapping {http-port, https-port}
|
||||
|
||||
http-port = attribute http {xsd:string}
|
||||
|
||||
https-port = attribute https {xsd:string}
|
||||
|
||||
|
||||
x509 =
|
||||
## Adds support for X.509 client authentication.
|
||||
element x509 {x509.attlist}
|
||||
x509.attlist &=
|
||||
## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".
|
||||
attribute subject-principal-regex {xsd:string}?
|
||||
x509.attlist &=
|
||||
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
|
||||
user-service-ref?
|
||||
|
||||
authentication-manager =
|
||||
## If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans.
|
||||
element authentication-manager {authman.attlist}
|
||||
authman.attlist &=
|
||||
## The alias you wish to use for the AuthenticationManager bean
|
||||
attribute alias {xsd:ID}
|
||||
authman.attlist &=
|
||||
## Allows the session controller to be set on the internal AuthenticationManager. This should not be used with the <concurrent-session-control /> element
|
||||
attribute session-controller-ref {xsd:string}?
|
||||
|
||||
|
||||
authentication-provider =
|
||||
## Indicates that the contained user-service should be used as an authentication source.
|
||||
element authentication-provider {ap.attlist & any-user-service & password-encoder?}
|
||||
ap.attlist &=
|
||||
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
|
||||
user-service-ref?
|
||||
|
||||
custom-authentication-provider =
|
||||
## Element used to decorate an AuthenticationProvider bean to add it to the internal AuthenticationManager maintained by the namespace.
|
||||
element custom-authentication-provider {cap.attlist}
|
||||
cap.attlist &= empty
|
||||
|
||||
user-service =
|
||||
## Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements.
|
||||
element user-service {id? & (properties-file | (user*))}
|
||||
properties-file =
|
||||
attribute properties {xsd:string}?
|
||||
|
||||
user =
|
||||
## Represents a user in the application.
|
||||
element user {user.attlist, empty}
|
||||
user.attlist &=
|
||||
## The username assigned to the user.
|
||||
attribute name {xsd:string}
|
||||
user.attlist &=
|
||||
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element).
|
||||
attribute password {xsd:string}
|
||||
user.attlist &=
|
||||
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
|
||||
attribute authorities {xsd:string}
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as locked and unusable.
|
||||
attribute locked {boolean}?
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
attribute disabled {boolean}?
|
||||
|
||||
jdbc-user-service =
|
||||
## Causes creation of a JDBC-based UserDetailsService.
|
||||
element jdbc-user-service {id? & jdbc-user-service.attlist}
|
||||
jdbc-user-service.attlist &=
|
||||
## The bean ID of the DataSource which provides the required tables.
|
||||
attribute data-source-ref {xsd:string}
|
||||
jdbc-user-service.attlist &=
|
||||
cache-ref?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query a username, password, and enabled status given a username
|
||||
attribute users-by-username-query {xsd:string}?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query for a user's granted authorities given a username.
|
||||
attribute authorities-by-username-query {xsd:string}?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query user's group authorities given a username.
|
||||
attribute group-authorities-by-username-query {xsd:string}?
|
||||
jdbc-user-service.attlist &=
|
||||
role-prefix?
|
||||
|
||||
|
||||
any-user-service = user-service | jdbc-user-service | ldap-user-service
|
||||
|
||||
custom-filter =
|
||||
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly.
|
||||
element custom-filter {after | before | position}?
|
||||
after =
|
||||
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
|
||||
attribute after {named-security-filter}
|
||||
before =
|
||||
## The filter immediately before which the custom-filter should be placed in the chain
|
||||
attribute before {named-security-filter}
|
||||
position =
|
||||
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
|
||||
attribute position {named-security-filter}
|
||||
|
||||
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "OPENID_PROCESSING_FILTER" |"BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
|
||||
|
||||
-1468
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,534 +0,0 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
|
||||
|
||||
default namespace = "http://www.springframework.org/schema/security"
|
||||
|
||||
start = http | ldap-server | authentication-provider | ldap-authentication-provider | any-user-service | ldap-server | ldap-authentication-provider
|
||||
|
||||
hash =
|
||||
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
|
||||
attribute hash {"plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
|
||||
base64 =
|
||||
## Whether a string should be base64 encoded
|
||||
attribute base64 {"true" | "false"}
|
||||
path-type =
|
||||
## Defines the type of pattern used to specify URL paths (either JDK 1.4-compatible regular expressions, or Apache Ant expressions). Defaults to "ant" if unspecified.
|
||||
attribute path-type {"ant" | "regex"}
|
||||
port =
|
||||
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
|
||||
attribute port { xsd:positiveInteger }
|
||||
url =
|
||||
## Specifies a URL.
|
||||
attribute url { xsd:string }
|
||||
id =
|
||||
## A bean identifier, used for referring to the bean elsewhere in the context.
|
||||
attribute id {xsd:ID}
|
||||
ref =
|
||||
## Defines a reference to a Spring bean Id.
|
||||
attribute ref {xsd:string}
|
||||
|
||||
cache-ref =
|
||||
## Defines a reference to a cache for use with a UserDetailsService.
|
||||
attribute cache-ref {xsd:string}
|
||||
|
||||
user-service-ref =
|
||||
## A reference to a user-service (or UserDetailsService bean) Id
|
||||
attribute user-service-ref {xsd:string}
|
||||
|
||||
data-source-ref =
|
||||
## A reference to a DataSource bean
|
||||
attribute data-source-ref {xsd:string}
|
||||
|
||||
password-encoder =
|
||||
## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.
|
||||
element password-encoder {password-encoder.attlist, salt-source?}
|
||||
password-encoder.attlist &=
|
||||
ref | (hash? & base64?)
|
||||
|
||||
salt-source =
|
||||
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
|
||||
element salt-source {user-property | system-wide | ref}
|
||||
user-property =
|
||||
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
|
||||
attribute user-property {xsd:string}
|
||||
system-wide =
|
||||
## A single value that will be used as the salt for a password encoder.
|
||||
attribute system-wide {xsd:string}
|
||||
|
||||
boolean = "true" | "false"
|
||||
|
||||
role-prefix =
|
||||
## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.
|
||||
attribute role-prefix {xsd:string}
|
||||
|
||||
use-expressions =
|
||||
## Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
|
||||
attribute use-expressions {boolean}
|
||||
|
||||
ldap-server =
|
||||
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
|
||||
element ldap-server {ldap-server.attlist}
|
||||
ldap-server.attlist &= id?
|
||||
ldap-server.attlist &= (url | port)?
|
||||
ldap-server.attlist &=
|
||||
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
|
||||
attribute manager-dn {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## The password for the manager DN.
|
||||
attribute manager-password {xsd:string}?
|
||||
ldap-server.attlist &=
|
||||
## Explicitly specifies an ldif file resource to load into an embedded LDAP server
|
||||
attribute ldif { xsd:string }?
|
||||
ldap-server.attlist &=
|
||||
## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org"
|
||||
attribute root { xsd:string }?
|
||||
|
||||
ldap-server-ref-attribute =
|
||||
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
|
||||
attribute server-ref {xsd:string}
|
||||
|
||||
|
||||
group-search-filter-attribute =
|
||||
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
|
||||
attribute group-search-filter {xsd:string}
|
||||
group-search-base-attribute =
|
||||
## Search base for group membership searches. Defaults to "" (searching from the root).
|
||||
attribute group-search-base {xsd:string}
|
||||
user-search-filter-attribute =
|
||||
## The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.
|
||||
attribute user-search-filter {xsd:string}
|
||||
user-search-base-attribute =
|
||||
## Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.
|
||||
attribute user-search-base {xsd:string}
|
||||
group-role-attribute-attribute =
|
||||
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
|
||||
attribute group-role-attribute {xsd:string}
|
||||
user-details-class-attribute =
|
||||
## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object
|
||||
attribute user-details-class {"person" | "inetOrgPerson"}
|
||||
|
||||
|
||||
ldap-user-service =
|
||||
element ldap-user-service {ldap-us.attlist}
|
||||
ldap-us.attlist &= id?
|
||||
ldap-us.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-us.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-us.attlist &=
|
||||
user-search-base-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-us.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
ldap-us.attlist &=
|
||||
cache-ref?
|
||||
ldap-us.attlist &=
|
||||
role-prefix?
|
||||
ldap-us.attlist &=
|
||||
user-details-class-attribute?
|
||||
|
||||
ldap-authentication-provider =
|
||||
## Sets up an ldap authentication provider
|
||||
element ldap-authentication-provider {ldap-ap.attlist, password-compare-element?}
|
||||
ldap-ap.attlist &=
|
||||
ldap-server-ref-attribute?
|
||||
ldap-ap.attlist &=
|
||||
user-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
user-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-base-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-search-filter-attribute?
|
||||
ldap-ap.attlist &=
|
||||
group-role-attribute-attribute?
|
||||
ldap-ap.attlist &=
|
||||
## A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username.
|
||||
attribute user-dn-pattern {xsd:string}?
|
||||
ldap-ap.attlist &=
|
||||
role-prefix?
|
||||
ldap-ap.attlist &=
|
||||
user-details-class-attribute?
|
||||
|
||||
password-compare-element =
|
||||
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
|
||||
element password-compare {password-compare.attlist, password-encoder?}
|
||||
|
||||
password-compare.attlist &=
|
||||
## The attribute in the directory which contains the user password. Defaults to "userPassword".
|
||||
attribute password-attribute {xsd:string}?
|
||||
password-compare.attlist &=
|
||||
hash?
|
||||
|
||||
intercept-methods =
|
||||
## Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods
|
||||
element intercept-methods {intercept-methods.attlist, protect+}
|
||||
intercept-methods.attlist &=
|
||||
## Optional AccessDecisionManager bean ID to be used by the created method security interceptor.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
|
||||
|
||||
protect =
|
||||
## Defines a protected method and the access control configuration attributes that apply to it. We strongly advise you NOT to mix "protect" declarations with any services provided "global-method-security".
|
||||
element protect {protect.attlist, empty}
|
||||
protect.attlist &=
|
||||
## A method name
|
||||
attribute method {xsd:string}
|
||||
protect.attlist &=
|
||||
## Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B".
|
||||
attribute access {xsd:string}
|
||||
|
||||
|
||||
global-method-security =
|
||||
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.
|
||||
element global-method-security {global-method-security.attlist, expression-handler?, protect-pointcut*}
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether the use of Spring Security's expression-based annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".
|
||||
attribute expression-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "disabled".
|
||||
attribute secured-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Specifies whether JSR-250 style attributes are to be used (for example "RolesAllowed"). This will require the javax.annotation.security classes on the classpath. Defaults to "disabled".
|
||||
attribute jsr250-annotations {"disabled" | "enabled" }?
|
||||
global-method-security.attlist &=
|
||||
## Optional AccessDecisionManager bean ID to override the default used for method security.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
|
||||
expression-handler =
|
||||
## Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied.
|
||||
element expression-handler {ref}
|
||||
|
||||
custom-after-invocation-provider =
|
||||
## Used to decorate an AfterInvocationProvider to specify that it should be used with method security.
|
||||
element custom-after-invocation-provider {empty}
|
||||
|
||||
protect-pointcut =
|
||||
## Defines a protected pointcut and the access control configuration attributes that apply to it. Every bean registered in the Spring application context that provides a method that matches the pointcut will receive security authorization.
|
||||
element protect-pointcut {protect-pointcut.attlist, empty}
|
||||
protect-pointcut.attlist &=
|
||||
## An AspectJ expression, including the 'execution' keyword. For example, 'execution(int com.foo.TargetObject.countLength(String))' (without the quotes).
|
||||
attribute expression {xsd:string}
|
||||
protect-pointcut.attlist &=
|
||||
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
|
||||
attribute access {xsd:string}
|
||||
|
||||
|
||||
http =
|
||||
## Container element for HTTP security configuration
|
||||
element http {http.attlist, (intercept-url+ & form-login? & openid-login & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) }
|
||||
http.attlist &=
|
||||
## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".
|
||||
attribute auto-config {boolean}?
|
||||
http.attlist &=
|
||||
use-expressions?
|
||||
http.attlist &=
|
||||
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set using security-context-repository-ref, then the only value which can be set is "always". Otherwise the session creation behaviour will be determined by the repository bean implementation.
|
||||
attribute create-session {"ifRequired" | "always" | "never" }?
|
||||
http.attlist &=
|
||||
## A reference to a SecurityContextRepository bean. This can be used to customize the way the SecurityContext is stored between requests.
|
||||
attribute security-context-repository-ref {xsd:string}?
|
||||
http.attlist &=
|
||||
## The path format used to define the paths in child elements.
|
||||
path-type?
|
||||
http.attlist &=
|
||||
## Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true".
|
||||
attribute lowercase-comparisons {boolean}?
|
||||
http.attlist &=
|
||||
## Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".
|
||||
attribute servlet-api-provision {boolean}?
|
||||
http.attlist &=
|
||||
## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
http.attlist &=
|
||||
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
|
||||
attribute realm {xsd:string}?
|
||||
http.attlist &=
|
||||
## Indicates whether an existing session should be invalidated when a user authenticates and a new session started. If set to "none" no change will be made. "newSession" will create a new empty session. "migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession".
|
||||
attribute session-fixation-protection {"none" | "newSession" | "migrateSession" }?
|
||||
http.attlist &=
|
||||
## Allows a customized AuthenticationEntryPoint to be used.
|
||||
attribute entry-point-ref {xsd:string}?
|
||||
http.attlist &=
|
||||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||
attribute once-per-request {boolean}?
|
||||
http.attlist &=
|
||||
## Allows the access denied page to be set (the user will be redirected here if an AccessDeniedException is raised).
|
||||
attribute access-denied-page {xsd:string}?
|
||||
http.attlist &=
|
||||
##
|
||||
attribute disable-url-rewriting {boolean}?
|
||||
|
||||
|
||||
intercept-url =
|
||||
## Specifies the access attributes and/or filter list for a particular set of URLs.
|
||||
element intercept-url {intercept-url.attlist, empty}
|
||||
intercept-url.attlist &=
|
||||
## The pattern which defines the URL path. The content will depend on the type set in the containing http element, so will default to ant path syntax.
|
||||
attribute pattern {xsd:string}
|
||||
intercept-url.attlist &=
|
||||
## The access configuration attributes that apply for the configured path.
|
||||
attribute access {xsd:string}?
|
||||
intercept-url.attlist &=
|
||||
## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.
|
||||
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "TRACE"}?
|
||||
|
||||
intercept-url.attlist &=
|
||||
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
|
||||
attribute filters {"none"}?
|
||||
intercept-url.attlist &=
|
||||
## Used to specify that a URL must be accessed over http or https, or that there is no preference.
|
||||
attribute requires-channel {"http" | "https" | "any"}?
|
||||
|
||||
logout =
|
||||
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
|
||||
element logout {logout.attlist, empty}
|
||||
logout.attlist &=
|
||||
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
|
||||
attribute logout-url {xsd:string}?
|
||||
logout.attlist &=
|
||||
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
|
||||
attribute logout-success-url {xsd:string}?
|
||||
logout.attlist &=
|
||||
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
|
||||
attribute invalidate-session {boolean}?
|
||||
|
||||
form-login =
|
||||
## Sets up a form login configuration for authentication with a username and password
|
||||
element form-login {form-login.attlist, empty}
|
||||
form-login.attlist &=
|
||||
## The URL that the login form is posted to. If unspecified, it defaults to /j_spring_security_check.
|
||||
attribute login-processing-url {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.
|
||||
attribute default-target-url {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## Whether the user should always be redirected to the default-target-url after login.
|
||||
attribute always-use-default-target {boolean}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.
|
||||
attribute login-page {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /spring_security_login?login_error and a corresponding filter to render that login failure URL when requested.
|
||||
attribute authentication-failure-url {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful authentication request. Should not be used in combination with default-target-url (or always-use-default-target-url) as the implementation should always deal with navigation to the subsequent destination
|
||||
attribute authentication-success-handler-ref {xsd:string}?
|
||||
form-login.attlist &=
|
||||
## Reference to an AuthenticationFailureHandler bean which should be used to handle a failed authentication request. Should not be used in combination with authentication-failure-url as the implementation should always deal with navigation to the subsequent destination
|
||||
attribute authentication-failure-handler-ref {xsd:string}?
|
||||
|
||||
|
||||
openid-login =
|
||||
## Sets up form login for authentication with an Open ID identity
|
||||
element openid-login {form-login.attlist, user-service-ref?, empty}
|
||||
|
||||
|
||||
filter-chain-map =
|
||||
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
|
||||
element filter-chain-map {filter-chain-map.attlist, filter-chain+}
|
||||
filter-chain-map.attlist &=
|
||||
path-type
|
||||
|
||||
filter-chain =
|
||||
## Used within filter-chain-map to define a specific URL pattern and the list of filters which apply to the URLs matching that pattern. When multiple filter-chain elements are used within a filter-chain-map element, the most specific patterns must be placed at the top of the list, with most general ones at the bottom.
|
||||
element filter-chain {filter-chain.attlist, empty}
|
||||
filter-chain.attlist &=
|
||||
attribute pattern {xsd:string}
|
||||
filter-chain.attlist &=
|
||||
attribute filters {xsd:string}
|
||||
|
||||
filter-invocation-definition-source =
|
||||
## Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
|
||||
element filter-invocation-definition-source {fids.attlist, intercept-url+}
|
||||
fids.attlist &=
|
||||
use-expressions?
|
||||
fids.attlist &=
|
||||
id?
|
||||
fids.attlist &=
|
||||
## as for http element
|
||||
attribute lowercase-comparisons {boolean}?
|
||||
fids.attlist &=
|
||||
## as for http element
|
||||
path-type?
|
||||
|
||||
http-basic =
|
||||
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
|
||||
element http-basic {empty}
|
||||
|
||||
|
||||
concurrent-session-control =
|
||||
## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have.
|
||||
element concurrent-session-control {concurrent-sessions.attlist, empty}
|
||||
concurrent-sessions.attlist &=
|
||||
## The maximum number of sessions a single user can have open at the same time. Defaults to "1".
|
||||
attribute max-sessions {xsd:positiveInteger}?
|
||||
concurrent-sessions.attlist &=
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because they have logged in again.
|
||||
attribute expired-url {xsd:string}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Specifies that an exception should be raised when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session.
|
||||
attribute exception-if-maximum-exceeded {boolean}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration
|
||||
attribute session-registry-alias {xsd:string}?
|
||||
concurrent-sessions.attlist &=
|
||||
## A reference to an external SessionRegistry implementation which will be used in place of the standard one.
|
||||
attribute session-registry-ref {xsd:string}?
|
||||
|
||||
remember-me =
|
||||
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
|
||||
element remember-me {remember-me.attlist}
|
||||
remember-me.attlist &=
|
||||
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
|
||||
attribute key {xsd:string}?
|
||||
|
||||
remember-me.attlist &=
|
||||
(token-repository-ref | remember-me-data-source-ref | remember-me-services-ref)
|
||||
|
||||
remember-me.attlist &=
|
||||
user-service-ref?
|
||||
|
||||
remember-me.attlist &=
|
||||
## The period (in seconds) for which the remember-me cookie should be valid. If set to a negative value
|
||||
attribute token-validity-seconds {xsd:integer}?
|
||||
|
||||
token-repository-ref =
|
||||
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
|
||||
attribute token-repository-ref {xsd:string}
|
||||
remember-me-services-ref =
|
||||
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
|
||||
attribute services-ref {xsd:string}?
|
||||
remember-me-data-source-ref =
|
||||
## DataSource bean for the database that contains the token repository schema.
|
||||
data-source-ref
|
||||
|
||||
anonymous =
|
||||
## Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority.
|
||||
element anonymous {anonymous.attlist}
|
||||
anonymous.attlist &=
|
||||
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
|
||||
attribute key {xsd:string}?
|
||||
anonymous.attlist &=
|
||||
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
|
||||
attribute username {xsd:string}?
|
||||
anonymous.attlist &=
|
||||
## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".
|
||||
attribute granted-authority {xsd:string}?
|
||||
|
||||
port-mappings =
|
||||
## Defines the list of mappings between http and https ports for use in redirects
|
||||
element port-mappings {port-mappings.attlist, port-mapping+}
|
||||
|
||||
port-mappings.attlist &= empty
|
||||
|
||||
port-mapping =
|
||||
element port-mapping {http-port, https-port}
|
||||
|
||||
http-port = attribute http {xsd:string}
|
||||
|
||||
https-port = attribute https {xsd:string}
|
||||
|
||||
|
||||
x509 =
|
||||
## Adds support for X.509 client authentication.
|
||||
element x509 {x509.attlist}
|
||||
x509.attlist &=
|
||||
## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".
|
||||
attribute subject-principal-regex {xsd:string}?
|
||||
x509.attlist &=
|
||||
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
|
||||
user-service-ref?
|
||||
|
||||
authentication-manager =
|
||||
## If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans.
|
||||
element authentication-manager {authman.attlist}
|
||||
authman.attlist &=
|
||||
## The alias you wish to use for the AuthenticationManager bean
|
||||
attribute alias {xsd:ID}
|
||||
authman.attlist &=
|
||||
## Allows the session controller to be set on the internal AuthenticationManager. This should not be used with the <concurrent-session-control /> element
|
||||
attribute session-controller-ref {xsd:string}?
|
||||
|
||||
|
||||
authentication-provider =
|
||||
## Indicates that the contained user-service should be used as an authentication source.
|
||||
element authentication-provider {ap.attlist & any-user-service & password-encoder?}
|
||||
ap.attlist &=
|
||||
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
|
||||
user-service-ref?
|
||||
|
||||
custom-authentication-provider =
|
||||
## Element used to decorate an AuthenticationProvider bean to add it to the internal AuthenticationManager maintained by the namespace.
|
||||
element custom-authentication-provider {cap.attlist}
|
||||
cap.attlist &= empty
|
||||
|
||||
user-service =
|
||||
## Creates an in-memory UserDetailsService from a properties file or a list of "user" child elements.
|
||||
element user-service {id? & (properties-file | (user*))}
|
||||
properties-file =
|
||||
attribute properties {xsd:string}?
|
||||
|
||||
user =
|
||||
## Represents a user in the application.
|
||||
element user {user.attlist, empty}
|
||||
user.attlist &=
|
||||
## The username assigned to the user.
|
||||
attribute name {xsd:string}
|
||||
user.attlist &=
|
||||
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element).
|
||||
attribute password {xsd:string}
|
||||
user.attlist &=
|
||||
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
|
||||
attribute authorities {xsd:string}
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as locked and unusable.
|
||||
attribute locked {boolean}?
|
||||
user.attlist &=
|
||||
## Can be set to "true" to mark an account as disabled and unusable.
|
||||
attribute disabled {boolean}?
|
||||
|
||||
jdbc-user-service =
|
||||
## Causes creation of a JDBC-based UserDetailsService.
|
||||
element jdbc-user-service {id? & jdbc-user-service.attlist}
|
||||
jdbc-user-service.attlist &=
|
||||
## The bean ID of the DataSource which provides the required tables.
|
||||
attribute data-source-ref {xsd:string}
|
||||
jdbc-user-service.attlist &=
|
||||
cache-ref?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query a username, password, and enabled status given a username
|
||||
attribute users-by-username-query {xsd:string}?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query for a user's granted authorities given a username.
|
||||
attribute authorities-by-username-query {xsd:string}?
|
||||
jdbc-user-service.attlist &=
|
||||
## An SQL statement to query user's group authorities given a username.
|
||||
attribute group-authorities-by-username-query {xsd:string}?
|
||||
jdbc-user-service.attlist &=
|
||||
role-prefix?
|
||||
|
||||
|
||||
any-user-service = user-service | jdbc-user-service | ldap-user-service
|
||||
|
||||
custom-filter =
|
||||
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly.
|
||||
element custom-filter {after | before | position}?
|
||||
after =
|
||||
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
|
||||
attribute after {named-security-filter}
|
||||
before =
|
||||
## The filter immediately before which the custom-filter should be placed in the chain
|
||||
attribute before {named-security-filter}
|
||||
position =
|
||||
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
|
||||
attribute position {named-security-filter}
|
||||
|
||||
|
||||
|
||||
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "OPENID_PROCESSING_FILTER" |"BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
XSL to manipulate trang's output XSD file. Contributed by Brian Ewins.
|
||||
|
||||
$Id$
|
||||
-->
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:variable name="elts-to-inline">
|
||||
<xsl:text>,anonymous,concurrent-session-control,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,remember-me,salt-source,x509,</xsl:text>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:template match="xs:element">
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains($elts-to-inline, concat(',',substring-after(current()/@ref, ':'),','))">
|
||||
<xsl:variable name="node" select="."/>
|
||||
<xsl:for-each select="/xs:schema/xs:element[@name=substring-after(current()/@ref, ':')]">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="$node/@*[local-name() != 'ref']"/>
|
||||
<xsl:apply-templates select="@*|*"/>
|
||||
</xsl:copy>
|
||||
</xsl:for-each>
|
||||
</xsl:when>
|
||||
<!-- Ignore global elements which have been inlined -->
|
||||
<xsl:when test="contains($elts-to-inline, concat(',',@name,','))">
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|*"/>
|
||||
</xsl:copy>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Copy any non-element content -->
|
||||
<xsl:template match="text()|@*|*">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="text()|@*|*"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
@@ -27,15 +27,6 @@ import java.util.Locale;
|
||||
* Tests {@link org.springframework.security.SpringSecurityMessageSource}.
|
||||
*/
|
||||
public class SpringSecurityMessageSourceTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public SpringSecurityMessageSourceTests() {
|
||||
}
|
||||
|
||||
public SpringSecurityMessageSourceTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testOperation() {
|
||||
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.providers.AuthenticationProvider;
|
||||
import org.springframework.security.providers.encoding.ShaPasswordEncoder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.After;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthenticationProviderBeanDefinitionParser}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AuthenticationProviderBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worksWithEmbeddedUserService() {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalUserServiceRefWorks() throws Exception {
|
||||
setContext(" <authentication-provider user-service-ref='myUserService' />" +
|
||||
" <user-service id='myUserService'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
|
||||
" </user-service>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerWithMd5PasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='md5'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='12b141f35d58b8b3a46eea65e6ac179e' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerWithShaPasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='{sha}'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='{SSHA}PpuEwfdj7M1rs0C2W4ssSM2XEN/Y6S5U' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerWithSha256PasswordEncoderIsSupported() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='sha-256'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='notused' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
|
||||
ShaPasswordEncoder encoder = (ShaPasswordEncoder) FieldUtils.getFieldValue(getProvider(), "passwordEncoder");
|
||||
assertEquals("SHA-256", encoder.getAlgorithm());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passwordIsBase64EncodedWhenBase64IsEnabled() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='md5' base64='true'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='ErFB811YuLOkbupl5qwXng==' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalUserServicePasswordEncoderAndSaltSourceWork() throws Exception {
|
||||
setContext(" <authentication-provider user-service-ref='customUserService'>" +
|
||||
" <password-encoder ref='customPasswordEncoder'>" +
|
||||
" <salt-source ref='saltSource'/>" +
|
||||
" </password-encoder>" +
|
||||
" </authentication-provider>" +
|
||||
|
||||
" <b:bean id='customPasswordEncoder' " +
|
||||
"class='org.springframework.security.providers.encoding.Md5PasswordEncoder'/>" +
|
||||
" <b:bean id='saltSource' " +
|
||||
" class='org.springframework.security.providers.dao.salt.ReflectionSaltSource'>" +
|
||||
" <b:property name='userPropertyToUse' value='username'/>" +
|
||||
" </b:bean>" +
|
||||
" <b:bean id='customUserService' " +
|
||||
" class='org.springframework.security.userdetails.memory.InMemoryDaoImpl'>" +
|
||||
" <b:property name='userMap' value='bob=f117f0862384e9497ff4f470e3522606,ROLE_A'/>" +
|
||||
" </b:bean>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
private AuthenticationProvider getProvider() {
|
||||
List<AuthenticationProvider> providers =
|
||||
((ProviderManager)appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)).getProviders();
|
||||
|
||||
return providers.get(0);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
public abstract class ConfigTestUtils {
|
||||
public static final String AUTH_PROVIDER_XML =
|
||||
" <authentication-provider>" +
|
||||
" <user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
" <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" +
|
||||
" <user name='admin' password='password' authorities='ROLE_ADMIN,ROLE_USER' />" +
|
||||
" <user name='user' password='password' authorities='ROLE_USER' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>";
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customAfterInvocationProviderIsAddedToInterceptor() {
|
||||
setContext(
|
||||
"<global-method-security />" +
|
||||
"<b:bean id='aip' class='org.springframework.security.config.MockAfterInvocationProvider'>" +
|
||||
" <custom-after-invocation-provider />" +
|
||||
"</b:bean>" +
|
||||
ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
|
||||
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(GlobalMethodSecurityBeanDefinitionParser.SECURITY_INTERCEPTOR_ID);
|
||||
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
|
||||
assertNotNull(apm);
|
||||
assertEquals(1, apm.getProviders().size());
|
||||
assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
|
||||
public class CustomAuthenticationProviderBeanDefinitionDecoratorTests {
|
||||
|
||||
@Test
|
||||
public void decoratedProviderParsesSuccessfully() {
|
||||
InMemoryXmlApplicationContext ctx = new InMemoryXmlApplicationContext(
|
||||
"<b:bean class='org.springframework.security.providers.dao.DaoAuthenticationProvider'>" +
|
||||
" <custom-authentication-provider />" +
|
||||
" <b:property name='userDetailsService' ref='us'/>" +
|
||||
"</b:bean>" +
|
||||
"<user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
"</user-service>"
|
||||
);
|
||||
ProviderManager authMgr = (ProviderManager) ctx.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
assertEquals(1, authMgr.getProviders().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void decoratedBeanAndRegisteredProviderAreTheSameObject() {
|
||||
InMemoryXmlApplicationContext ctx = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='myProvider' class='org.springframework.security.providers.dao.DaoAuthenticationProvider'>" +
|
||||
" <custom-authentication-provider />" +
|
||||
" <b:property name='userDetailsService' ref='us'/>" +
|
||||
"</b:bean>" +
|
||||
"<user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
"</user-service>"
|
||||
);
|
||||
|
||||
ProviderManager authMgr = (ProviderManager) ctx.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
assertEquals(1, authMgr.getProviders().size());
|
||||
assertSame(ctx.getBean("myProvider"), authMgr.getProviders().get(0));
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* 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;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Populates a database with test data for JDBC testing.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id: DataSourcePopulator.java 2291 2007-12-03 02:56:52Z benalex $
|
||||
*/
|
||||
public class DataSourcePopulator implements InitializingBean {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
JdbcTemplate template;
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(template, "dataSource required");
|
||||
|
||||
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
|
||||
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
|
||||
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
|
||||
|
||||
/*
|
||||
Passwords encoded using MD5, NOT in Base64 format, with null as salt
|
||||
Encoded password for rod is "koala"
|
||||
Encoded password for dianne is "emu"
|
||||
Encoded password for scott is "wombat"
|
||||
Encoded password for peter is "opal" (but user is disabled)
|
||||
Encoded password for bill is "wombat"
|
||||
Encoded password for bob is "wombat"
|
||||
Encoded password for jane is "wombat"
|
||||
|
||||
*/
|
||||
template.execute("INSERT INTO USERS VALUES('rod','koala',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('dianne','65d15fe9156f9c4bbffd98085992a44e',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('scott','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('peter','22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bill','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bob','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('jane','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_SUPERVISOR');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
|
||||
}
|
||||
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.template = new JdbcTemplate(dataSource);
|
||||
}
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.intercept.web.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.web.FilterInvocation;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterInvocationDefinitionSourceParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsingMinimalConfigurationIsSuccessful() {
|
||||
setContext(
|
||||
"<filter-invocation-definition-source id='fids'>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
"</filter-invocation-definition-source>");
|
||||
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext.getBean("fids");
|
||||
List<? extends ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
|
||||
assertNotNull(cad);
|
||||
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
|
||||
setContext(
|
||||
"<http auto-config='true'/>" +
|
||||
"<b:bean id='fsi' class='org.springframework.security.intercept.web.FilterSecurityInterceptor' autowire='byType'>" +
|
||||
" <b:property name='securityMetadataSource'>" +
|
||||
" <filter-invocation-definition-source>" +
|
||||
" <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>" +
|
||||
" <intercept-url pattern='/secure/**' access='ROLE_USER'/>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_USER'/>" +
|
||||
" </filter-invocation-definition-source>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(null);
|
||||
request.setMethod(method);
|
||||
|
||||
request.setServletPath(path);
|
||||
|
||||
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||
}
|
||||
}
|
||||
-255
@@ -1,255 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.expression.method.MethodExpressionAfterInvocationProvider;
|
||||
import org.springframework.security.expression.method.MethodExpressionVoter;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
public void loadContext() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>" +
|
||||
" <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
target = null;
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("Test", "Password", "ROLE_SOMEOTHERROLE");
|
||||
token.setAuthenticated(true);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntInterfereWithBeanPostProcessing() {
|
||||
setContext(
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<global-method-security />" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>" +
|
||||
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
||||
);
|
||||
|
||||
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithAspectJAutoproxy() {
|
||||
setContext(
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'" +
|
||||
" access='ROLE_SOMETHING' />" +
|
||||
"</global-method-security>" +
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<aop:aspectj-autoproxy />" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>"
|
||||
);
|
||||
|
||||
UserDetailsService service = (UserDetailsService) appContext.getBean("myUserService");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
service.loadUserByUsername("notused");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsMethodArgumentsInPointcut() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.*(..))' access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// someOther(int) should not be matched by someOther(String), but should require ROLE_USER
|
||||
target.someOther(0);
|
||||
|
||||
try {
|
||||
// String version should required admin role
|
||||
target.someOther("somestring");
|
||||
fail("Expected AccessDeniedException");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsBooleanPointcutExpressions() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression=" +
|
||||
" 'execution(* org.springframework.security.annotation.BusinessService.*(..)) " +
|
||||
" and not execution(* org.springframework.security.annotation.BusinessService.someOther(String)))' " +
|
||||
" access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// String method should not be protected
|
||||
target.someOther("somestring");
|
||||
|
||||
// All others should require ROLE_USER
|
||||
try {
|
||||
target.someOther(0);
|
||||
fail("Expected AuthenticationCredentialsNotFoundException");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext(
|
||||
"<global-method-security />" +
|
||||
"<global-method-security />"
|
||||
);
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithoutTargetOrClass() {
|
||||
setContext(
|
||||
"<global-method-security secured-annotations='enabled'/>" +
|
||||
"<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>" +
|
||||
" <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>" +
|
||||
" <b:property name='serviceInterface' value='org.springframework.security.annotation.BusinessService'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
target = (BusinessService) appContext.getBean("businessService");
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
// Expression configuration tests
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void expressionVoterAndAfterInvocationProviderUseSameExpressionHandlerInstance() throws Exception {
|
||||
setContext("<global-method-security expression-annotations='enabled'/>" + AUTH_PROVIDER_XML);
|
||||
AffirmativeBased adm = (AffirmativeBased) appContext.getBean(GlobalMethodSecurityBeanDefinitionParser.ACCESS_MANAGER_ID);
|
||||
List voters = (List) FieldUtils.getFieldValue(adm, "decisionVoters");
|
||||
MethodExpressionVoter mev = (MethodExpressionVoter) voters.get(0);
|
||||
AfterInvocationProviderManager pm = (AfterInvocationProviderManager) appContext.getBean(BeanIds.AFTER_INVOCATION_MANAGER);
|
||||
MethodExpressionAfterInvocationProvider aip = (MethodExpressionAfterInvocationProvider) pm.getProviders().get(0);
|
||||
assertTrue(FieldUtils.getFieldValue(mev, "expressionHandler") == FieldUtils.getFieldValue(aip, "expressionHandler"));
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void accessIsDeniedForHasRoleExpression() {
|
||||
setContext(
|
||||
"<global-method-security expression-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preAndPostFilterAnnotationsWorkWithLists() {
|
||||
setContext(
|
||||
"<global-method-security expression-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
List<String> arg = new ArrayList<String>();
|
||||
arg.add("joe");
|
||||
arg.add("bob");
|
||||
arg.add("sam");
|
||||
List<?> result = target.methodReturningAList(arg);
|
||||
// Expression is (filterObject == name or filterObject == 'sam'), so "joe" should be gone after pre-filter
|
||||
// PostFilter should remove sam from the return object
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("bob", result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prePostFilterAnnotationWorksWithArrays() {
|
||||
setContext(
|
||||
"<global-method-security expression-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
Object[] arg = new String[] {"joe", "bob", "sam"};
|
||||
Object[] result = target.methodReturningAnArray(arg);
|
||||
assertEquals(1, result.length);
|
||||
assertEquals("bob", result[0]);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-788
@@ -1,788 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.MockAuthenticationEntryPoint;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.concurrent.ConcurrentLoginException;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionFilter;
|
||||
import org.springframework.security.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.intercept.web.FilterInvocation;
|
||||
import org.springframework.security.intercept.web.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.providers.anonymous.AnonymousProcessingFilter;
|
||||
import org.springframework.security.securechannel.ChannelProcessingFilter;
|
||||
import org.springframework.security.ui.AuthenticationFailureHandler;
|
||||
import org.springframework.security.ui.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.SessionFixationProtectionFilter;
|
||||
import org.springframework.security.ui.WebAuthenticationDetails;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.logout.LogoutFilter;
|
||||
import org.springframework.security.ui.logout.LogoutHandler;
|
||||
import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.util.MockFilter;
|
||||
import org.springframework.security.util.PortMapperImpl;
|
||||
import org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class HttpSecurityBeanDefinitionParserTests {
|
||||
private static final int AUTO_CONFIG_FILTERS = 10;
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimalConfigurationParses() {
|
||||
setContext("<http><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpAutoConfigSetsUpCorrectFilterList() throws Exception {
|
||||
setContext("<http auto-config='true' />" + AUTH_PROVIDER_XML);
|
||||
|
||||
List<Filter> filterList = getFilters("/anyurl");
|
||||
|
||||
checkAutoConfigFilters(filterList);
|
||||
|
||||
assertEquals(true, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
|
||||
assertEquals(true, FieldUtils.getFieldValue(filterList.get(AUTO_CONFIG_FILTERS-1), "securityMetadataSource.stripQueryStringFromUrls"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() throws Exception {
|
||||
setContext("<http auto-config='true' /><http auto-config='true' />" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
private void checkAutoConfigFilters(List<Filter> filterList) throws Exception {
|
||||
assertEquals("Expected " + AUTO_CONFIG_FILTERS + " filters in chain", AUTO_CONFIG_FILTERS, filterList.size());
|
||||
|
||||
Iterator<Filter> filters = filterList.iterator();
|
||||
|
||||
assertTrue(filters.next() instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.next() instanceof LogoutFilter);
|
||||
Object authProcFilter = filters.next();
|
||||
assertTrue(authProcFilter instanceof AuthenticationProcessingFilter);
|
||||
// Check RememberMeServices has been set on AuthenticationProcessingFilter
|
||||
//Object rms = FieldUtils.getFieldValue(authProcFilter, "rememberMeServices");
|
||||
//assertNotNull(rms);
|
||||
//assertTrue(rms instanceof RememberMeServices);
|
||||
//assertFalse(rms instanceof NullRememberMeServices);
|
||||
assertTrue(filters.next() instanceof DefaultLoginPageGeneratingFilter);
|
||||
assertTrue(filters.next() instanceof BasicProcessingFilter);
|
||||
assertTrue(filters.next() instanceof SecurityContextHolderAwareRequestFilter);
|
||||
//assertTrue(filters.next() instanceof RememberMeProcessingFilter);
|
||||
assertTrue(filters.next() instanceof AnonymousProcessingFilter);
|
||||
assertTrue(filters.next() instanceof ExceptionTranslationFilter);
|
||||
assertTrue(filters.next() instanceof SessionFixationProtectionFilter);
|
||||
Object fsiObj = filters.next();
|
||||
assertTrue(fsiObj instanceof FilterSecurityInterceptor);
|
||||
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) fsiObj;
|
||||
assertTrue(fsi.isObserveOncePerRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterListShouldBeEmptyForUnprotectedUrl() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/unprotected' filters='none' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
List<Filter> filters = getFilters("/unprotected");
|
||||
|
||||
assertTrue(filters.size() == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regexPathsWorkCorrectly() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true' path-type='regex'>" +
|
||||
" <intercept-url pattern='\\A\\/[a-z]+' filters='none' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(0, getFilters("/imlowercase").size());
|
||||
// This will be matched by the default pattern ".*"
|
||||
List<Filter> allFilters = getFilters("/ImCaughtByTheUniversalMatchPattern");
|
||||
checkAutoConfigFilters(allFilters);
|
||||
assertEquals(false, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
|
||||
assertEquals(false, FieldUtils.getFieldValue(allFilters.get(AUTO_CONFIG_FILTERS-1), "securityMetadataSource.stripQueryStringFromUrls"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lowerCaseComparisonAttributeIsRespectedByFilterChainProxy() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true' path-type='ant' lowercase-comparisons='false'>" +
|
||||
" <intercept-url pattern='/Secure*' filters='none' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(0, getFilters("/Secure").size());
|
||||
// These will be matched by the default pattern "/**"
|
||||
checkAutoConfigFilters(getFilters("/secure"));
|
||||
checkAutoConfigFilters(getFilters("/ImCaughtByTheUniversalMatchPattern"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formLoginWithNoLoginPageAddsDefaultLoginPageFilter() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true' path-type='ant' lowercase-comparisons='false'>" +
|
||||
" <form-login />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
// These will be matched by the default pattern "/**"
|
||||
checkAutoConfigFilters(getFilters("/anything"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formLoginAlwaysUseDefaultSetsCorrectProperty() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <form-login default-target-url='/default' always-use-default-target='true' />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
// These will be matched by the default pattern "/**"
|
||||
AuthenticationProcessingFilter filter = (AuthenticationProcessingFilter) getFilters("/anything").get(1);
|
||||
assertEquals("/default", FieldUtils.getFieldValue(filter, "successHandler.defaultTargetUrl"));
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "successHandler.alwaysUseDefaultTargetUrl"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidLoginPageIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <form-login login-page='noLeadingSlash'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidDefaultTargetUrlIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <form-login default-target-url='noLeadingSlash'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidLogoutUrlIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <logout logout-url='noLeadingSlash'/>" +
|
||||
" <form-login />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidLogoutSuccessUrlIsDetected() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <logout logout-success-url='noLeadingSlash'/>" +
|
||||
" <form-login />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lowerCaseComparisonIsRespectedBySecurityFilterInvocationDefinitionSource() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true' path-type='ant' lowercase-comparisons='false'>" +
|
||||
" <intercept-url pattern='/Secure*' access='ROLE_A,ROLE_B' />" +
|
||||
" <intercept-url pattern='/**' access='ROLE_C' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
|
||||
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
||||
List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/Secure", null));
|
||||
assertEquals(2, attrDef.size());
|
||||
assertTrue(attrDef.contains(new SecurityConfig("ROLE_A")));
|
||||
assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
|
||||
attrDef = fids.getAttributes(createFilterinvocation("/secure", null));
|
||||
assertEquals(1, attrDef.size());
|
||||
assertTrue(attrDef.contains(new SecurityConfig("ROLE_C")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMethodMatchIsSupported() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_C' />" +
|
||||
" <intercept-url pattern='/secure*' method='DELETE' access='ROLE_SUPERVISOR' />" +
|
||||
" <intercept-url pattern='/secure*' method='POST' access='ROLE_A,ROLE_B' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
||||
List<? extends ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/secure", "POST"));
|
||||
assertEquals(2, attrs.size());
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_A")));
|
||||
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oncePerRequestAttributeIsSupported() throws Exception {
|
||||
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) filters.get(filters.size() - 1);
|
||||
|
||||
assertFalse(fsi.isObserveOncePerRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessDeniedPageAttributeIsSupported() throws Exception {
|
||||
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) filters.get(filters.size() - 3);
|
||||
|
||||
assertEquals("/access-denied", FieldUtils.getFieldValue(etf, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void invalidAccessDeniedUrlIsDetected() throws Exception {
|
||||
setContext("<http auto-config='true' access-denied-page='noLeadingSlash'/>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interceptUrlWithRequiresChannelAddsChannelFilterToStack() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <intercept-url pattern='/**' requires-channel='https' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
assertEquals("Expected " + (AUTO_CONFIG_FILTERS + 1) +" filters in chain", AUTO_CONFIG_FILTERS + 1, filters.size());
|
||||
|
||||
assertTrue(filters.get(0) instanceof ChannelProcessingFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void portMappingsAreParsedCorrectly() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <port-mappings>" +
|
||||
" <port-mapping http='9080' https='9443'/>" +
|
||||
" </port-mappings>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
|
||||
assertEquals(1, pm.getTranslatedPortMappings().size());
|
||||
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
|
||||
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void portMappingsWorkWithPlaceholders() throws Exception {
|
||||
System.setProperty("http", "9080");
|
||||
System.setProperty("https", "9443");
|
||||
setContext(
|
||||
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||
" <http auto-config='true'>" +
|
||||
" <port-mappings>" +
|
||||
" <port-mapping http='${http}' https='${https}'/>" +
|
||||
" </port-mappings>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
|
||||
assertEquals(1, pm.getTranslatedPortMappings().size());
|
||||
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
|
||||
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessDeniedPageWorkWithPlaceholders() throws Exception {
|
||||
System.setProperty("accessDenied", "/go-away");
|
||||
setContext(
|
||||
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||
" <http auto-config='true' access-denied-page='${accessDenied}'/>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalFiltersAreTreatedCorrectly() throws Exception {
|
||||
// Decorated user-filters should be added to stack. The others should be ignored.
|
||||
setContext(
|
||||
"<http auto-config='true'/>" + AUTH_PROVIDER_XML +
|
||||
"<b:bean id='userFilter' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
|
||||
" <custom-filter after='LOGOUT_FILTER'/>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='userFilter1' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
|
||||
" <custom-filter before='SESSION_CONTEXT_INTEGRATION_FILTER'/>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" +
|
||||
" <custom-filter position='FIRST'/>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>" +
|
||||
"<b:bean id='userFilter4' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'/>"
|
||||
);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
assertEquals(AUTO_CONFIG_FILTERS + 3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof MockFilter);
|
||||
assertTrue(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void twoFiltersWithSameOrderAreRejected() {
|
||||
setContext(
|
||||
"<http auto-config='true'/>" + AUTH_PROVIDER_XML +
|
||||
"<b:bean id='userFilter' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
|
||||
" <custom-filter position='LOGOUT_FILTER'/>" +
|
||||
"</b:bean>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeServiceWorksWithTokenRepoRef() {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me token-repository-ref='tokenRepo'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='tokenRepo' " +
|
||||
"class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " + AUTH_PROVIDER_XML);
|
||||
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
|
||||
|
||||
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeServiceWorksWithDataSourceRef() {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me data-source-ref='ds'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='ds' class='org.springframework.security.TestDataSource'> " +
|
||||
" <b:constructor-arg value='tokendb'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
|
||||
|
||||
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me key='ourkey' services-ref='rms'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='rms' class='org.springframework.security.ui.rememberme.TokenBasedRememberMeServices'> " +
|
||||
" <b:property name='userDetailsService' ref='us'/>" +
|
||||
" <b:property name='key' value='ourkey'/>" +
|
||||
" <b:property name='tokenValiditySeconds' value='5000'/>" +
|
||||
"</b:bean>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
|
||||
assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
// SEC-909
|
||||
List<LogoutHandler> logoutHandlers = (List<LogoutHandler>) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers");
|
||||
assertEquals(2, logoutHandlers.size());
|
||||
assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeTokenValidityIsParsedCorrectly() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me key='ourkey' token-validity-seconds='10000' />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeTokenValidityAllowsNegativeValueForNonPersistentImplementation() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me key='ourkey' token-validity-seconds='-1' />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
assertEquals(-1, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
|
||||
"tokenValiditySeconds"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void rememberMeTokenValidityRejectsNegativeValueForPersistentImplementation() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me token-validity-seconds='-1' token-repository-ref='tokenRepo'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='tokenRepo' class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " +
|
||||
AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rememberMeServiceConfigurationParsesWithCustomUserService() {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <remember-me key='somekey' user-service-ref='userService'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='userService' class='org.springframework.security.userdetails.MockUserDetailsService'/> " +
|
||||
AUTH_PROVIDER_XML);
|
||||
// AbstractRememberMeServices rememberMeServices = (AbstractRememberMeServices) appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void x509SupportAddsFilterAtExpectedPosition() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <x509 />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
assertTrue(filters.get(2) instanceof X509PreAuthenticatedProcessingFilter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void concurrentSessionSupportAddsFilterAndExpectedBeans() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
|
||||
assertNotNull(appContext.getBean("seshRegistry"));
|
||||
assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-ref='seshRegistry' />" +
|
||||
"</http>" +
|
||||
"<b:bean id='seshRegistry' class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
Object sessionRegistry = appContext.getBean("seshRegistry");
|
||||
Object sessionRegistryFromFilter = FieldUtils.getFieldValue(
|
||||
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
|
||||
Object sessionRegistryFromController = FieldUtils.getFieldValue(
|
||||
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
|
||||
Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue(
|
||||
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
|
||||
|
||||
assertSame(sessionRegistry, sessionRegistryFromFilter);
|
||||
assertSame(sessionRegistry, sessionRegistryFromController);
|
||||
assertSame(sessionRegistry, sessionRegistryFromFixationFilter);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean() throws Exception {
|
||||
setContext(
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
|
||||
" <b:property name='sessionRegistry'>" +
|
||||
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean2() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
|
||||
" <b:property name='sessionRegistry'>" +
|
||||
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" +
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test(expected=ConcurrentLoginException.class)
|
||||
public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control max-sessions='2' exception-if-maximum-exceeded='true' />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
ConcurrentSessionControllerImpl seshController = (ConcurrentSessionControllerImpl) appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER);
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("bob", "pass");
|
||||
// Register 2 sessions and then check a third
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
req.setSession(new MockHttpSession());
|
||||
auth.setDetails(new WebAuthenticationDetails(req));
|
||||
try {
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
} catch (ConcurrentLoginException e) {
|
||||
fail("First login should be allowed");
|
||||
}
|
||||
seshController.registerSuccessfulAuthentication(auth);
|
||||
req.setSession(new MockHttpSession());
|
||||
try {
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
} catch (ConcurrentLoginException e) {
|
||||
fail("Second login should be allowed");
|
||||
}
|
||||
auth.setDetails(new WebAuthenticationDetails(req));
|
||||
seshController.registerSuccessfulAuthentication(auth);
|
||||
req.setSession(new MockHttpSession());
|
||||
auth.setDetails(new WebAuthenticationDetails(req));
|
||||
seshController.checkAuthenticationAllowed(auth);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customEntryPointIsSupported() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true' entry-point-ref='entryPoint'/>" +
|
||||
"<b:bean id='entryPoint' class='org.springframework.security.MockAuthenticationEntryPoint'>" +
|
||||
" <b:constructor-arg value='/customlogin'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) getFilters("/someurl").get(AUTO_CONFIG_FILTERS-3);
|
||||
assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
|
||||
etf.getAuthenticationEntryPoint() instanceof MockAuthenticationEntryPoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
/** SEC-742 */
|
||||
public void rememberMeServicesWorksWithoutBasicProcessingFilter() {
|
||||
setContext(
|
||||
" <http>" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" <logout logout-success-url='/login.jsp'/>" +
|
||||
" <anonymous username='guest' granted-authority='guest'/>" +
|
||||
" <remember-me />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disablingSessionProtectionRemovesFilter() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true' session-fixation-protection='none'/>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
assertFalse(filters.get(1) instanceof SessionFixationProtectionFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* See SEC-750. If the http security post processor causes beans to be instantiated too eagerly, they way miss
|
||||
* additional processing. In this method we have a UserDetailsService which is referenced from the namespace
|
||||
* and also has a post processor registered which will modify it.
|
||||
*/
|
||||
@Test
|
||||
public void httpElementDoesntInterfereWithBeanPostProcessing() {
|
||||
setContext(
|
||||
"<http auto-config='true'/>" +
|
||||
"<authentication-provider user-service-ref='myUserService'/>" +
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
||||
);
|
||||
|
||||
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-795. Two methods that exercise the scenarios that will or won't result in a protected login page warning.
|
||||
* Check the log.
|
||||
*/
|
||||
@Test
|
||||
public void unprotectedLoginPageDoesntResultInWarning() {
|
||||
// Anonymous access configured
|
||||
setContext(
|
||||
" <http>" +
|
||||
" <intercept-url pattern='/login.jsp*' access='IS_AUTHENTICATED_ANONYMOUSLY'/>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <anonymous />" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
closeAppContext();
|
||||
// No filters applied to login page
|
||||
setContext(
|
||||
" <http>" +
|
||||
" <intercept-url pattern='/login.jsp*' filters='none'/>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <anonymous />" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void protectedLoginPageResultsInWarning() {
|
||||
// Protected, no anonymous filter configured.
|
||||
setContext(
|
||||
" <http>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
closeAppContext();
|
||||
// Protected, anonymous provider but no access
|
||||
setContext(
|
||||
" <http>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
" <anonymous />" +
|
||||
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception {
|
||||
setContext("<http auto-config='true' create-session='always'/>" + AUTH_PROVIDER_XML);
|
||||
Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
|
||||
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
|
||||
// Just check that the repo has url rewriting enabled by default
|
||||
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception {
|
||||
setContext("<http auto-config='true' create-session='never'/>" + AUTH_PROVIDER_XML);
|
||||
Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
|
||||
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
||||
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
|
||||
}
|
||||
|
||||
/* SEC-934 */
|
||||
@Test
|
||||
public void supportsTwoIdenticalInterceptUrls() {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <intercept-url pattern='/someurl' access='ROLE_A'/>" +
|
||||
" <intercept-url pattern='/someurl' access='ROLE_B'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
|
||||
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
||||
List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/someurl", null));
|
||||
assertEquals(1, attrDef.size());
|
||||
assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsExternallyDefinedSecurityContextRepository() throws Exception {
|
||||
setContext(
|
||||
"<b:bean id='repo' class='org.springframework.security.context.HttpSessionSecurityContextRepository'/>" +
|
||||
"<http create-session='always' security-context-repository-ref='repo'>" +
|
||||
" <http-basic />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
SecurityContextPersistenceFilter filter = (SecurityContextPersistenceFilter) appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
|
||||
HttpSessionSecurityContextRepository repo = (HttpSessionSecurityContextRepository) appContext.getBean("repo");
|
||||
assertSame(repo, FieldUtils.getFieldValue(filter, "repo"));
|
||||
assertTrue((Boolean)FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void cantUseUnsupportedSessionCreationAttributeWithExternallyDefinedSecurityContextRepository() throws Exception {
|
||||
setContext(
|
||||
"<b:bean id='repo' class='org.springframework.security.context.HttpSessionSecurityContextRepository'/>" +
|
||||
"<http create-session='never' security-context-repository-ref='repo'>" +
|
||||
" <http-basic />" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expressionBasedAccessAllowsAndDeniesAccessAsExpected() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true' use-expressions='true'>" +
|
||||
" <intercept-url pattern='/secure*' access=\"hasRole('ROLE_A')\" />" +
|
||||
" <intercept-url pattern='/**' access='permitAll()' />" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
|
||||
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
|
||||
|
||||
FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
||||
List<? extends ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/secure", null));
|
||||
assertEquals(1, attrDef.size());
|
||||
|
||||
// Try an unprotected invocation
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ROLE_A"));
|
||||
fis.invoke(createFilterinvocation("/permitallurl", null));
|
||||
// Try secure Url as a valid user
|
||||
fis.invoke(createFilterinvocation("/securex", null));
|
||||
// And as a user without the required role
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ROLE_B"));
|
||||
try {
|
||||
fis.invoke(createFilterinvocation("/securex", null));
|
||||
fail("Expected AccessDeniedInvocation");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customSuccessAndFailureHandlersCanBeSetThroughTheNamespace() throws Exception {
|
||||
setContext(
|
||||
"<http>" +
|
||||
" <form-login authentication-success-handler-ref='sh' authentication-failure-handler-ref='fh'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='sh' class='org.springframework.security.ui.SavedRequestAwareAuthenticationSuccessHandler'/>" +
|
||||
"<b:bean id='fh' class='org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
AuthenticationProcessingFilter apf = (AuthenticationProcessingFilter) appContext.getBean(BeanIds.FORM_LOGIN_FILTER);
|
||||
AuthenticationSuccessHandler sh = (AuthenticationSuccessHandler) appContext.getBean("sh");
|
||||
AuthenticationFailureHandler fh = (AuthenticationFailureHandler) appContext.getBean("fh");
|
||||
assertSame(sh, FieldUtils.getFieldValue(apf, "successHandler"));
|
||||
assertSame(fh, FieldUtils.getFieldValue(apf, "failureHandler"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disablingUrlRewritingThroughTheNamespaceSetsCorrectPropertyOnContextRepo() throws Exception {
|
||||
setContext("<http auto-config='true' disable-url-rewriting='true'/>" + AUTH_PROVIDER_XML);
|
||||
Object filter = appContext.getBean(BeanIds.SECURITY_CONTEXT_PERSISTENCE_FILTER);
|
||||
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Filter> getFilters(String url) throws Exception {
|
||||
FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
||||
Method getFilters = fcp.getClass().getDeclaredMethod("getFilters", String.class);
|
||||
getFilters.setAccessible(true);
|
||||
return (List<Filter>) ReflectionUtils.invokeMethod(getFilters, fcp, new Object[] {url});
|
||||
}
|
||||
|
||||
private FilterInvocation createFilterinvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod(method);
|
||||
request.setRequestURI(null);
|
||||
|
||||
request.setServletPath(path);
|
||||
|
||||
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InterceptMethodsBeanDefinitionDecoratorTests {
|
||||
private ClassPathXmlApplicationContext appContext;
|
||||
|
||||
private TestBusinessBean target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
|
||||
target = (TestBusinessBean) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowUnprotectedMethodInvocationWithNoContext() {
|
||||
target.unprotected();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
try {
|
||||
target.doSomething();
|
||||
fail("Expected AuthenticationCredentialsNotFoundException");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
|
||||
target.doSomething();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
try {
|
||||
target.doSomething();
|
||||
fail("Expected AccessDeniedException");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests which make sure invalid configurations are rejected by the namespace. In particular invalid top-level
|
||||
* elements. These are likely to fail after the namespace has been updated using trang, but the spring-security.xsl
|
||||
* transform has not been applied.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InvalidConfigurationTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Parser should throw a SAXParseException
|
||||
@Test(expected=XmlBeanDefinitionStoreException.class)
|
||||
public void passwordEncoderCannotAppearAtTopLevel() {
|
||||
setContext("<password-encoder hash='md5'/>");
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.providers.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class JdbcUserServiceBeanDefinitionParserTests {
|
||||
private static String USER_CACHE_XML = "<b:bean id='userCache' class='org.springframework.security.providers.dao.MockUserCache'/>";
|
||||
|
||||
private static String DATA_SOURCE =
|
||||
" <b:bean id='populator' class='org.springframework.security.config.DataSourcePopulator'>" +
|
||||
" <b:property name='dataSource' ref='dataSource'/>" +
|
||||
" </b:bean>" +
|
||||
|
||||
" <b:bean id='dataSource' class='org.springframework.security.TestDataSource'>" +
|
||||
" <b:constructor-arg value='jdbcnamespaces'/>" +
|
||||
" </b:bean>";
|
||||
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validUsernameIsFound() {
|
||||
setContext("<jdbc-user-service data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean(BeanIds.USER_DETAILS_SERVICE);
|
||||
assertNotNull(mgr.loadUserByUsername("rod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanIdIsParsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
assertTrue(appContext.getBean("myUserService") instanceof JdbcUserDetailsManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
|
||||
String userQuery = "select username, password, true from users where username = ?";
|
||||
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
|
||||
setContext("<jdbc-user-service id='myUserService' " +
|
||||
"data-source-ref='dataSource' " +
|
||||
"users-by-username-query='"+ userQuery +"' " +
|
||||
"authorities-by-username-query='" + authoritiesQuery + "'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertEquals(userQuery, FieldUtils.getFieldValue(mgr, "usersByUsernameQuery"));
|
||||
assertEquals(authoritiesQuery, FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery"));
|
||||
assertTrue(mgr.loadUserByUsername("rod") != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupQueryIsParsedCorrectly() throws Exception {
|
||||
setContext("<jdbc-user-service id='myUserService' " +
|
||||
"data-source-ref='dataSource' " +
|
||||
"group-authorities-by-username-query='blah blah'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertEquals("blah blah", FieldUtils.getFieldValue(mgr, "groupAuthoritiesByUsernameQuery"));
|
||||
assertTrue((Boolean)FieldUtils.getFieldValue(mgr, "enableGroups"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheRefIsparsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' cache-ref='userCache' data-source-ref='dataSource'/>"
|
||||
+ DATA_SOURCE +USER_CACHE_XML);
|
||||
CachingUserDetailsService cachingUserService =
|
||||
(CachingUserDetailsService) appContext.getBean("myUserService" + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX);
|
||||
assertSame(cachingUserService.getUserCache(), appContext.getBean("userCache"));
|
||||
assertNotNull(cachingUserService.loadUserByUsername("rod"));
|
||||
assertNotNull(cachingUserService.loadUserByUsername("rod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSupportedByAuthenticationProviderElement() {
|
||||
setContext(
|
||||
"<authentication-provider>" +
|
||||
" <jdbc-user-service data-source-ref='dataSource'/>" +
|
||||
"</authentication-provider>" + DATA_SOURCE);
|
||||
AuthenticationManager mgr = (AuthenticationManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheIsInjectedIntoAuthenticationProvider() {
|
||||
setContext(
|
||||
"<authentication-provider>" +
|
||||
" <jdbc-user-service cache-ref='userCache' data-source-ref='dataSource'/>" +
|
||||
"</authentication-provider>" + DATA_SOURCE + USER_CACHE_XML);
|
||||
ProviderManager mgr = (ProviderManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0);
|
||||
assertSame(provider.getUserCache(), appContext.getBean("userCache"));
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("rod","koala"));
|
||||
assertNotNull("Cache should contain user after authentication", provider.getUserCache().getUserFromCache("rod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rolePrefixIsUsedWhenSet() {
|
||||
setContext("<jdbc-user-service id='myUserService' role-prefix='PREFIX_' data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
UserDetails rod = mgr.loadUserByUsername("rod");
|
||||
assertTrue(AuthorityUtils.authorityListToSet(rod.getAuthorities()).contains("PREFIX_ROLE_SUPERVISOR"));
|
||||
}
|
||||
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
|
||||
"<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void permitAllShouldBeDefaultAttribute() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.afterinvocation.AfterInvocationProvider;
|
||||
|
||||
public class MockAfterInvocationProvider implements AfterInvocationProvider {
|
||||
|
||||
public Object decide(Authentication authentication, Object object, List<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
/**
|
||||
* Test bean post processor which injects a message into a PostProcessedMockUserDetailsService.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockUserServiceBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof PostProcessedMockUserDetailsService) {
|
||||
((PostProcessedMockUserDetailsService)bean).setPostProcessorWasHere("Hello from the post processor!");
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
|
||||
public class PostProcessedMockUserDetailsService implements UserDetailsService {
|
||||
private String postProcessorWasHere;
|
||||
|
||||
public PostProcessedMockUserDetailsService() {
|
||||
this.postProcessorWasHere = "Post processor hasn't been yet";
|
||||
}
|
||||
|
||||
public String getPostProcessorWasHere() {
|
||||
return postProcessorWasHere;
|
||||
}
|
||||
|
||||
public void setPostProcessorWasHere(String postProcessorWasHere) {
|
||||
this.postProcessorWasHere = postProcessorWasHere;
|
||||
}
|
||||
|
||||
public UserDetails loadUserByUsername(String username)
|
||||
throws UsernameNotFoundException, DataAccessException {
|
||||
throw new UnsupportedOperationException("Not for actual use");
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecuredAnnotationDrivenBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security secured-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionController;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* $Id$
|
||||
*/
|
||||
public class SessionRegistryInjectionBeanPostProcessorTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionRegistryIsSetOnFiltersWhenUsingCustomControllerWithInternalRegistryBean() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'/>" +
|
||||
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
|
||||
" <b:property name='sessionRegistry'>" +
|
||||
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" +
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionRegistryIsSetOnFiltersWhenUsingCustomControllerWithNonStandardController() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'/>" +
|
||||
"<b:bean id='sc' class='org.springframework.security.config.SessionRegistryInjectionBeanPostProcessorTests$MockConcurrentSessionController'/>" +
|
||||
"<b:bean id='sessionRegistry' class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
|
||||
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
|
||||
ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER), "sessionRegistry"));
|
||||
assertNotNull(FieldUtils.getFieldValue(appContext.getBean(BeanIds.FORM_LOGIN_FILTER), "sessionRegistry"));
|
||||
}
|
||||
|
||||
public static class MockConcurrentSessionController implements ConcurrentSessionController {
|
||||
public void checkAuthenticationAllowed(Authentication request) throws AuthenticationException {
|
||||
}
|
||||
public void registerSuccessfulAuthentication(Authentication authentication) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* @author luke
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface TestBusinessBean {
|
||||
|
||||
void setInteger(int i);
|
||||
|
||||
int getInteger();
|
||||
|
||||
void setString(String s);
|
||||
|
||||
void doSomething();
|
||||
|
||||
void unprotected();
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* @author luke
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TestBusinessBeanImpl implements TestBusinessBean {
|
||||
public void setInteger(int i) {
|
||||
}
|
||||
|
||||
public int getInteger() {
|
||||
return 1314;
|
||||
}
|
||||
|
||||
public void setString(String s) {
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return "A string.";
|
||||
}
|
||||
|
||||
public void doSomething() {
|
||||
}
|
||||
|
||||
public void unprotected() {
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.After;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UserServiceBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userServiceWithValidPropertiesFileWorksSuccessfully() {
|
||||
setContext(
|
||||
"<user-service id='service' " +
|
||||
"properties='classpath:org/springframework/security/config/users.properties'/>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
userService.loadUserByUsername("bob");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userServiceWithEmbeddedUsersWorksSuccessfully() {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disabledAndEmbeddedFlagsAreSupported() {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertFalse(joe.isAccountNonLocked());
|
||||
UserDetails bob = userService.loadUserByUsername("bob");
|
||||
assertFalse(bob.isEnabled());
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=FatalBeanException.class)
|
||||
public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
|
||||
setContext(
|
||||
"<user-service id='service' properties='doesntmatter.props'>" +
|
||||
" <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
|
||||
@Test(expected= FatalBeanException.class)
|
||||
public void multipleTopLevelUseWithoutIdThrowsException() {
|
||||
setContext(
|
||||
"<user-service properties='classpath:org/springframework/security/config/users.properties'/>" +
|
||||
"<user-service properties='classpath:org/springframework/security/config/users.properties'/>");
|
||||
|
||||
}
|
||||
|
||||
@Test(expected= FatalBeanException.class)
|
||||
public void userServiceWithMissingPropertiesFileThrowsException() {
|
||||
setContext("<user-service id='service' properties='classpath:doesntexist.properties'/>");
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
package org.springframework.security.intercept.method.aopalliance;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.ITargetObject;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests for SEC-428.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class MethodSecurityInterceptorWithAopConfigTests {
|
||||
static final String AUTH_PROVIDER_XML =
|
||||
" <authentication-provider>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_USER,ROLE_ADMIN' />" +
|
||||
" <user name='bill' password='billspassword' authorities='ROLE_USER' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>";
|
||||
|
||||
static final String ACCESS_MANAGER_XML =
|
||||
"<b:bean id='accessDecisionManager' class='org.springframework.security.vote.AffirmativeBased'>" +
|
||||
" <b:property name='decisionVoters'>" +
|
||||
" <b:list><b:bean class='org.springframework.security.vote.RoleVoter'/></b:list>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>";
|
||||
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@Before
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void securityInterceptorIsAppliedWhenUsedWithAopConfig() {
|
||||
setContext(
|
||||
"<aop:config proxy-target-class=\"true\">" +
|
||||
" <aop:pointcut id='targetMethods' expression='execution(* org.springframework.security.TargetObject.*(..))'/>" +
|
||||
" <aop:advisor advice-ref='securityInterceptor' pointcut-ref='targetMethods' />" +
|
||||
"</aop:config>" +
|
||||
"<b:bean id='target' class='org.springframework.security.TargetObject'/>" +
|
||||
"<b:bean id='securityInterceptor' class='org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor' autowire='byType' >" +
|
||||
" <b:property name='securityMetadataSource'>" +
|
||||
" <b:value>" +
|
||||
"org.springframework.security.TargetObject.makeLower*=ROLE_A\n" +
|
||||
"org.springframework.security.TargetObject.makeUpper*=ROLE_A\n" +
|
||||
"org.springframework.security.TargetObject.computeHashCode*=ROLE_B\n" +
|
||||
" </b:value>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>" +
|
||||
AUTH_PROVIDER_XML + ACCESS_MANAGER_XML);
|
||||
|
||||
ITargetObject target = (ITargetObject) appContext.getBean("target");
|
||||
target.makeLowerCase("TEST");
|
||||
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* 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.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.MockFilterConfig;
|
||||
import org.springframework.security.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
|
||||
/**
|
||||
* Tests {@link FilterChainProxy}.
|
||||
*
|
||||
* @author Carlos Sanchez
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterChainProxyTests {
|
||||
private ClassPathXmlApplicationContext appCtx;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appCtx = new ClassPathXmlApplicationContext("org/springframework/security/util/filtertest-valid.xml");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoNotFilter() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||
MockFilter filter = (MockFilter) appCtx.getBean("mockFilter", MockFilter.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/do/not/filter/somefile.html");
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockFilterChain chain = new MockFilterChain(true);
|
||||
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
assertFalse(filter.isWasInitialized());
|
||||
assertFalse(filter.isWasDoFiltered());
|
||||
assertFalse(filter.isWasDestroyed());
|
||||
}
|
||||
|
||||
@Test(expected=BeanCreationException.class)
|
||||
public void misplacedUniversalPathShouldBeDetected() throws Exception {
|
||||
appCtx.getBean("newFilterChainProxyWrongPathOrder", FilterChainProxy.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperation() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfig() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfigRegex() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathWithNoMatchHasNoFilters() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlStrippingPropertyIsRespected() throws Exception {
|
||||
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||
|
||||
// Should only match if we are stripping the query string
|
||||
String url = "/blah.bar?x=something";
|
||||
assertNotNull(filterChainProxy.getFilters(url));
|
||||
assertEquals(2, filterChainProxy.getFilters(url).size());
|
||||
filterChainProxy.setStripQueryStringFromUrls(false);
|
||||
assertNull(filterChainProxy.getFilters(url));
|
||||
}
|
||||
|
||||
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) throws Exception {
|
||||
List<Filter> filters = filterChainProxy.getFilters("/foo/blah");
|
||||
assertEquals(1, filters.size());
|
||||
assertTrue(filters.get(0) instanceof MockFilter);
|
||||
|
||||
filters = filterChainProxy.getFilters("/some/other/path/blah");
|
||||
assertNotNull(filters);
|
||||
assertEquals(3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.get(1) instanceof MockFilter);
|
||||
assertTrue(filters.get(2) instanceof MockFilter);
|
||||
|
||||
filters = filterChainProxy.getFilters("/do/not/filter");
|
||||
assertEquals(0, filters.size());
|
||||
|
||||
filters = filterChainProxy.getFilters("/another/nonspecificmatch");
|
||||
assertEquals(3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.get(1) instanceof AuthenticationProcessingFilter);
|
||||
assertTrue(filters.get(2) instanceof MockFilter);
|
||||
}
|
||||
|
||||
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
|
||||
MockFilter filter = (MockFilter) appCtx.getBean("mockFilter", MockFilter.class);
|
||||
assertFalse(filter.isWasInitialized());
|
||||
assertFalse(filter.isWasDoFiltered());
|
||||
assertFalse(filter.isWasDestroyed());
|
||||
|
||||
filterChainProxy.init(new MockFilterConfig());
|
||||
assertTrue(filter.isWasInitialized());
|
||||
assertFalse(filter.isWasDoFiltered());
|
||||
assertFalse(filter.isWasDestroyed());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/foo/secure/super/somefile.html");
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockFilterChain chain = new MockFilterChain(true);
|
||||
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
assertTrue(filter.isWasInitialized());
|
||||
assertTrue(filter.isWasDoFiltered());
|
||||
assertFalse(filter.isWasDestroyed());
|
||||
|
||||
request.setServletPath("/a/path/which/doesnt/match/any/filter.html");
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
|
||||
filterChainProxy.destroy();
|
||||
assertTrue(filter.isWasInitialized());
|
||||
assertTrue(filter.isWasDoFiltered());
|
||||
assertTrue(filter.isWasDestroyed());
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
* Copyright 2004 Acegi Technology Pty Limited
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
<beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:sec="http://www.springframework.org/schema/security"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<bean id="mockFilter" class="org.springframework.security.util.MockFilter"/>
|
||||
|
||||
<bean id="mockFilter2" class="org.springframework.security.util.MockFilter"/>
|
||||
|
||||
<!-- These are just here so we have filters of a specific type to check the ordering is as expected -->
|
||||
<bean id="sif" class="org.springframework.security.context.SecurityContextPersistenceFilter"/>
|
||||
|
||||
<bean id="apf" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
|
||||
<property name="authenticationManager">
|
||||
<bean class="org.springframework.security.MockAuthenticationManager"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="mockNotAFilter" class="org.springframework.security.util.MockNotAFilter"/>
|
||||
|
||||
<bean id="filterChain" class="org.springframework.security.util.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/foo/**" filters="mockFilter"/>
|
||||
<sec:filter-chain pattern="/some/other/path/**" filters="mockFilter"/>
|
||||
<sec:filter-chain pattern="/do/not/filter" filters="none"/>
|
||||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
|
||||
<!-- TODO: Refactor to replace the above (SEC-1034: 'new' is now the only valid syntax) -->
|
||||
<bean id="newFilterChainProxy" class="org.springframework.security.util.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/foo/**" filters="mockFilter"/>
|
||||
<sec:filter-chain pattern="/some/other/path/**" filters="sif,mockFilter,mockFilter2"/>
|
||||
<sec:filter-chain pattern="/do/not/filter" filters="none"/>
|
||||
<sec:filter-chain pattern="/**" filters="sif,apf,mockFilter"/>
|
||||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
|
||||
<bean id="newFilterChainProxyNoDefaultPath" class="org.springframework.security.util.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/foo/**" filters="mockFilter"/>
|
||||
<sec:filter-chain pattern="/*.bar" filters="mockFilter,mockFilter2"/>
|
||||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
|
||||
<bean id="newFilterChainProxyWrongPathOrder" class="org.springframework.security.util.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/foo/**" filters="mockFilter"/>
|
||||
<sec:filter-chain pattern="/**" filters="sif,apf,mockFilter"/>
|
||||
<sec:filter-chain pattern="/some/other/path/**" filters="sif,mockFilter,mockFilter2"/>
|
||||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
|
||||
<bean id="newFilterChainProxyRegex" class="org.springframework.security.util.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="regex">
|
||||
<sec:filter-chain pattern="\A/foo/.*\Z" filters="mockFilter"/>
|
||||
<sec:filter-chain pattern="\A/s[oO]me/other/path/.*\Z" filters="sif,mockFilter,mockFilter2"/>
|
||||
<sec:filter-chain pattern="\A/do/not/filter\Z" filters="none"/>
|
||||
<sec:filter-chain pattern="\A/.*\Z" filters="sif,apf,mockFilter"/>
|
||||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
|
||||
<bean id="newFilterChainProxyNonNamespace" class="org.springframework.security.util.FilterChainProxy">
|
||||
<property name="matcher">
|
||||
<bean class="org.springframework.security.util.AntUrlPathMatcher"/>
|
||||
</property>
|
||||
<property name="filterChainMap">
|
||||
<map>
|
||||
<entry key="/foo/**">
|
||||
<list>
|
||||
<ref local="mockFilter"/>
|
||||
</list>
|
||||
</entry>
|
||||
<entry key="/some/other/path/**">
|
||||
<list>
|
||||
<ref local="sif"/>
|
||||
<ref local="mockFilter"/>
|
||||
<ref local="mockFilter2"/>
|
||||
</list>
|
||||
</entry>
|
||||
<entry key="/do/not/filter">
|
||||
<list/>
|
||||
</entry>
|
||||
<entry key="/**">
|
||||
<list>
|
||||
<ref local="sif"/>
|
||||
<ref local="apf"/>
|
||||
<ref local="mockFilter"/>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user