General refactorings and improvements to namespace support, including

autoDetect="true" attribute for <http> element.
This commit is contained in:
Ben Alex 2007-12-04 10:35:08 +00:00
parent 2441ab6d9a
commit 8e7c540b16
11 changed files with 305 additions and 211 deletions

View File

@ -9,6 +9,7 @@ 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;
/**
@ -17,17 +18,40 @@ import org.w3c.dom.Element;
*/
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 = "grantedAuthority";
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;
if (element != null) {
grantedAuthority = element.getAttribute(ATT_GRANTED_AUTHORITY);
username = element.getAttribute(ATT_USERNAME);
key = element.getAttribute(ATT_KEY);
}
if (!StringUtils.hasText(grantedAuthority)) {
grantedAuthority = DEF_GRANTED_AUTHORITY;
}
if (!StringUtils.hasText(username)) {
username = DEF_USERNAME;
}
if (!StringUtils.hasText(key)) {
key = DEF_KEY;
}
BeanDefinition filter = new RootBeanDefinition(AnonymousProcessingFilter.class);
String grantedAuthority = element.getAttribute(ATT_GRANTED_AUTHORITY);
String username = element.getAttribute(ATT_USERNAME);
String key = element.getAttribute(ATT_KEY);
filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority);
filter.getPropertyValues().addPropertyValue(ATT_KEY, key);

View File

@ -26,21 +26,20 @@ public class BasicAuthenticationBeanDefinitionParser implements BeanDefinitionPa
}
public BeanDefinition parse(Element elt, ParserContext parserContext) {
BeanDefinitionBuilder filterBuilder =
BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class);
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class);
entryPoint.getPropertyValues().addPropertyValue("realmName", realmName);
filterBuilder.addPropertyValue("authenticationEntryPoint", entryPoint);
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());
return null;
}
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class);
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class);
entryPoint.getPropertyValues().addPropertyValue("realmName", realmName);
filterBuilder.addPropertyValue("authenticationEntryPoint", entryPoint);
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());
return null;
}
}

View File

@ -29,9 +29,9 @@ class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDecorator {
Map filterChainMap = new LinkedHashMap();
Element elt = (Element)node;
String pathType = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATTERN_TYPE);
String pathType = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_TYPE);
if (HttpSecurityBeanDefinitionParser.ATT_PATTERN_TYPE_REGEX.equals(pathType)) {
if (HttpSecurityBeanDefinitionParser.OPT_PATH_TYPE_REGEX.equals(pathType)) {
filterChainProxy.getPropertyValues().addPropertyValue("matcher", new RegexUrlPathMatcher());
}
@ -46,7 +46,7 @@ class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDecorator {
Assert.hasText(filters, "The attribute '" + HttpSecurityBeanDefinitionParser.ATT_FILTERS +
"'must not be empty");
if (filters.equals(HttpSecurityBeanDefinitionParser.NO_FILTERS_VALUE)) {
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
filterChainMap.put(path, Collections.EMPTY_LIST);
} else {
String[] filterBeanNames = StringUtils.tokenizeToStringArray(filters, ",");

View File

@ -36,9 +36,21 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
public BeanDefinition parse(Element elt, ParserContext parserContext) {
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
String loginUrl = null;
String defaultTargetUrl = null;
String authenticationFailureUrl = null;
String loginPage = null;
if (elt != null) {
loginUrl = elt.getAttribute(ATT_LOGIN_URL);
defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL);
authenticationFailureUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL);
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
}
BeanDefinition filterBean = createFilterBean(elt);
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
BeanDefinition filterBean = createFilterBean(loginUrl, defaultTargetUrl, authenticationFailureUrl);
filterBean.getPropertyValues().addPropertyValue("authenticationManager",
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
@ -46,7 +58,6 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
BeanDefinitionBuilder entryPointBuilder =
BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
String loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
// If no login page has been defined, add in the default page generator.
if (!StringUtils.hasText(loginPage)) {
@ -68,11 +79,10 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
return null;
}
private BeanDefinition createFilterBean(Element elt) {
private BeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String authenticationFailureUrl) {
BeanDefinitionBuilder filterBuilder =
BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilter.class);
String loginUrl = elt.getAttribute(ATT_LOGIN_URL);
if (!StringUtils.hasText(loginUrl)) {
loginUrl = DEF_LOGIN_URL;
@ -80,7 +90,6 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
filterBuilder.addPropertyValue("filterProcessesUrl", loginUrl);
String defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL);
if (!StringUtils.hasText(defaultTargetUrl)) {
defaultTargetUrl = DEF_FORM_LOGIN_TARGET_URL;
@ -88,8 +97,6 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
filterBuilder.addPropertyValue("defaultTargetUrl", defaultTargetUrl);
String authenticationFailureUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL);
if (!StringUtils.hasText(authenticationFailureUrl)) {
authenticationFailureUrl = DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL;
}

View File

@ -1,5 +1,19 @@
package org.springframework.security.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
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.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
@ -15,26 +29,11 @@ import org.springframework.security.securechannel.SecureChannelProcessor;
import org.springframework.security.ui.ExceptionTranslationFilter;
import org.springframework.security.util.FilterChainProxy;
import org.springframework.security.util.RegexUrlPathMatcher;
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.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Sets up HTTP security: filter stack and protected URLs.
*
@ -48,54 +47,84 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
static final String DEF_REALM = "Spring Security Application";
static final String ATT_PATH_PATTERN = "pattern";
static final String ATT_PATTERN_TYPE = "pathType";
static final String ATT_PATTERN_TYPE_REGEX = "regex";
static final String ATT_PATH_TYPE = "pathType";
static final String DEF_PATH_TYPE_ANT = "ant";
static final String OPT_PATH_TYPE_REGEX = "regex";
static final String ATT_FILTERS = "filters";
static final String NO_FILTERS_VALUE = "none";
static final String OPT_FILTERS_NONE = "none";
static final String ATT_ACCESS_CONFIG = "access";
static final String ATT_REQUIRES_CHANNEL = "requiresChannel";
static final String ATT_CREATE_SESSION = "create-session";
static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
static final String OPT_CREATE_SESSION_ALWAYS = "always";
static final String OPT_CREATE_SESSION_NEVER = "never";
static final String ATT_LOWERCASE_COMPARISONS = "lowercaseComparisons";
static final String DEF_LOWERCASE_COMPARISONS = "true";
static final String ATT_AUTO_CONFIG = "autoConfig";
static final String DEF_AUTO_CONFIG = "false";
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
RootBeanDefinition httpSCIF = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
//TODO: Set session creation parameters based on session-creation attribute
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
String createSession = element.getAttribute(ATT_CREATE_SESSION);
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.FALSE);
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
} else {
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
}
BeanDefinitionBuilder filterSecurityInterceptorBuilder
= BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
BeanDefinitionBuilder exceptionTranslationFilterBuilder
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
// Autowire for entry point (for now)
// TODO: Examine entry point beans in post processing and pick the correct one
// i.e. form login or cas if defined, then any other non-basic, non-digest, then basic or digest
exceptionTranslationFilterBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
// TODO: Get path type attribute and determine FilDefInvS class
Map filterChainMap = new LinkedHashMap();
String patternType = element.getAttribute(ATT_PATTERN_TYPE);
String patternType = element.getAttribute(ATT_PATH_TYPE);
if (!StringUtils.hasText(patternType)) {
patternType = DEF_PATH_TYPE_ANT;
}
FilterInvocationDefinitionMap interceptorFilterInvDefSource = new PathBasedFilterInvocationDefinitionMap();
FilterInvocationDefinitionMap channelFilterInvDefSource = new PathBasedFilterInvocationDefinitionMap();
if (patternType.equals(ATT_PATTERN_TYPE_REGEX)) {
if (patternType.equals(OPT_PATH_TYPE_REGEX)) {
filterChainProxy.getPropertyValues().addPropertyValue("matcher", new RegexUrlPathMatcher());
interceptorFilterInvDefSource = new RegExpBasedFilterInvocationDefinitionMap();
channelFilterInvDefSource = new RegExpBasedFilterInvocationDefinitionMap();
}
// Deal with lowercase conversion requests
String lowercaseComparisons = element.getAttribute(ATT_LOWERCASE_COMPARISONS);
if (!StringUtils.hasText(lowercaseComparisons)) {
lowercaseComparisons = DEF_LOWERCASE_COMPARISONS;
}
if ("true".equals(lowercaseComparisons)) {
interceptorFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(true);
channelFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(true);
} else {
interceptorFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(false);
channelFilterInvDefSource.setConvertUrlToLowercaseBeforeComparison(false);
}
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource);
// Again pick up auth manager
//filterSecurityInterceptorBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"),
filterChainMap, interceptorFilterInvDefSource, channelFilterInvDefSource, parserContext);
@ -119,64 +148,56 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
registry.registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
registry.registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
}
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
if (sessionControlElt != null) {
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
}
Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
if (anonymousElt != null) {
new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext);
}
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME);
if (rememberMeElt != null) {
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
}
Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT);
if (logoutElt != null) {
new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
}
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
if (formLoginElt != null) {
new FormLoginBeanDefinitionParser().parse(formLoginElt, parserContext);
}
String realm = element.getAttribute(ATT_REALM);
if (!StringUtils.hasText(realm)) {
realm = DEF_REALM;
}
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
if (sessionControlElt != null) {
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
}
boolean autoConfig = false;
if ("true".equals(element.getAttribute(ATT_AUTO_CONFIG))) {
autoConfig = true;
}
Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
if (anonymousElt != null || autoConfig) {
new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext);
}
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME);
if (rememberMeElt != null || autoConfig) {
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
}
if (basicAuthElt != null) {
Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
}
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
if (formLoginElt != null || autoConfig) {
new FormLoginBeanDefinitionParser().parse(formLoginElt, parserContext);
}
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
if (basicAuthElt != null || autoConfig) {
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext);
}
registry.registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
registry.registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpSCIF);
registry.registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER,
exceptionTranslationFilterBuilder.getBeanDefinition());
registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR,
filterSecurityInterceptorBuilder.getBeanDefinition());
registry.registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
registry.registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, filterSecurityInterceptorBuilder.getBeanDefinition());
// Register the post processor which will tie up the loose ends in the configuration once the
// app context has been created and all beans are available.
registry.registerBeanDefinition("__httpConfigBeanFactoryPostProcessor",
new RootBeanDefinition(HttpSecurityConfigPostProcessor.class));
// Register the post processor which will tie up the loose ends in the configuration once the app context has been created and all beans are available.
registry.registerBeanDefinition("__httpConfigBeanFactoryPostProcessor", new RootBeanDefinition(HttpSecurityConfigPostProcessor.class));
return null;
}
@ -228,7 +249,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
String filters = urlElt.getAttribute(ATT_FILTERS);
if (StringUtils.hasText(filters)) {
if (!filters.equals(NO_FILTERS_VALUE)) {
if (!filters.equals(OPT_FILTERS_NONE)) {
parserContext.getReaderContext().error("Currently only 'none' is supported as the custom " +
"filters attribute", urlElt);
}

View File

@ -1,16 +1,14 @@
package org.springframework.security.config;
import org.springframework.security.ui.logout.LogoutFilter;
import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
import org.springframework.beans.factory.BeanDefinitionStoreException;
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.ManagedList;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
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;
/**
@ -18,47 +16,60 @@ import org.w3c.dom.Element;
* @author Ben Alex
* @version $Id$
*/
public class LogoutBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_LOGOUT_SUCCESS_URL = "logoutSuccessUrl";
static final String DEF_LOGOUT_SUCCESS_URL = "/";
static final String ATT_INVALIDATE_SESSION = "invalidateSession";
static final String DEF_INVALIDATE_SESSION = "true";
static final String ATT_LOGOUT_URL = "logoutUrl";
public static final String DEF_LOGOUT_SUCCESS_URL = "/";
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
protected Class getBeanClass(Element element) {
return LogoutFilter.class;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
String logoutUrl = null;
String logoutSuccessUrl = null;
String invalidateSession = null;
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String logoutUrl = element.getAttribute(ATT_LOGOUT_URL);
if (StringUtils.hasText(logoutUrl)) {
builder.addPropertyValue("filterProcessesUrl", logoutUrl);
if (element != null) {
logoutUrl = element.getAttribute(ATT_LOGOUT_URL);
logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION);
}
String logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
if (!StringUtils.hasText(logoutUrl)) {
logoutUrl = DEF_LOGOUT_URL;
}
builder.addPropertyValue("filterProcessesUrl", logoutUrl);
if (!StringUtils.hasText(logoutSuccessUrl)) {
logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL;
}
builder.addConstructorArg(logoutSuccessUrl);
if (!StringUtils.hasText(invalidateSession)) {
invalidateSession = DEF_INVALIDATE_SESSION;
}
ManagedList handlers = new ManagedList();
handlers.add(new SecurityContextLogoutHandler());
SecurityContextLogoutHandler sclh = new SecurityContextLogoutHandler();
if ("true".equals(invalidateSession)) {
sclh.setInvalidateHttpSession(true);
} else {
sclh.setInvalidateHttpSession(false);
}
handlers.add(sclh);
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
handlers.add(new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
}
builder.addConstructorArg(handlers);
parserContext.getRegistry().registerBeanDefinition(BeanIds.LOGOUT_FILTER, builder.getBeanDefinition());
}
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
String id = super.resolveId(element, definition, parserContext);
if (StringUtils.hasText(id)) {
return id;
}
return BeanIds.LOGOUT_FILTER;
}
return null;
}
}

View File

@ -23,21 +23,29 @@ import org.w3c.dom.Element;
*/
public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_KEY = "key";
static final String DEF_KEY = "doesNotMatter";
static final String ATT_DATA_SOURCE = "dataSource";
static final String ATT_TOKEN_REPOSITORY = "tokenRepository";
protected final Log logger = LogFactory.getLog(getClass());
public BeanDefinition parse(Element element, ParserContext parserContext) {
String tokenRepository = null;
String dataSource = null;
String key = null;
if (element != null) {
tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
dataSource = element.getAttribute(ATT_DATA_SOURCE);
key = element.getAttribute(ATT_KEY);
}
BeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
BeanDefinition services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
filter.getPropertyValues().addPropertyValue("authenticationManager",
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
String tokenRepository = element.getAttribute(ATT_TOKEN_REPOSITORY);
String dataSource = element.getAttribute(ATT_DATA_SOURCE);
String key = element.getAttribute(ATT_KEY);
boolean dataSourceSet = StringUtils.hasText(dataSource);
boolean tokenRepoSet = StringUtils.hasText(tokenRepository);
@ -63,16 +71,15 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
services = new RootBeanDefinition(TokenBasedRememberMeServices.class);
}
if (StringUtils.hasText(key) && isPersistent) {
logger.warn("The attribute 'key' ('" + key + "') is not required for persistent remember-me services and " +
"will be ignored.");
if (!StringUtils.hasText(key) && !isPersistent) {
key = DEF_KEY;
}
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
BeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
providers.add(provider);

View File

@ -10,9 +10,9 @@ start = http | ldap | repository
# targetNamespace="http://www.springframework.org/schema/security"
path-type =
## Defines the type types of pattern used to specify URL paths. Defaults to "ant"
[ a:defaultValue = "ant" ] attribute pathType {"regex" | "ant"}
pathType =
## 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 pathType {"ant" | "regex"}
port =
## Specifies an IP port number. Used to configure an embedded LDAP server, for example.
@ -22,11 +22,6 @@ url =
## Specifies a URL.
attribute url { xsd:string }
autoconfig =
## Provides automatic security configration for a application
element autoconfig {autoconfig.attlist, empty}
autoconfig.attlist = empty
ldap =
## Sets up an ldap authentication provider, optionally with an embedded ldap server
element ldap {ldap.attlist, empty}
@ -60,14 +55,17 @@ http =
## Container element for HTTP security configuration
element http {http.attlist, (intercept-url+ & form-login? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous?) }
http.attlist &=
## Controls the eagerness with which an HTTP session is created.
[ a:defaultValue = "ifRequired" ] attribute createSession {"ifRequired" | "always" | "never" }?
## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services and remember-me. 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 autoConfig {"true" | "false" }?
http.attlist &=
## The path format used to define the paths used in child elements.
path-type?
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired".
attribute createSession {"ifRequired" | "always" | "never" }?
http.attlist &=
## Whether test URLs should be converted to lower case prior to comparing with defined path patterns.
[ a:defaultValue = "true" ] attribute lowerCaseComparisons {"true" | "false"}?
## The path format used to define the paths in child elements.
pathType?
http.attlist &=
## Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true".
attribute lowercaseComparisons {"true" | "false"}?
http.attlist &=
## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
attribute accessDecisionManager {xsd:string}?
@ -93,13 +91,17 @@ intercept-url.attlist &=
attribute requiresChannel {"http" | "https"}?
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 &=
[ a:defaultValue = "/j_spring_security_logout" ] attribute logoutUrl {xsd:string}?
## 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 logoutUrl {xsd:string}?
logout.attlist &=
[ a:defaultValue = "/" ] attribute logoutSuccessUrl {xsd:string}?
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
attribute logoutSuccessUrl {xsd:string}?
logout.attlist &=
[ a:defaultValue = "true" ] attribute invalidateSession {"true" | "false"}?
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
attribute invalidateSession {"true" | "false"}?
form-login =
## Sets up a form login configuration
@ -121,7 +123,7 @@ 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
pathType
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.
@ -155,14 +157,14 @@ 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 used between the provider and filter. This generally does not need to be set.
[ a:defaultValue = "doesNotMatter" ] attribute key {xsd:string}?
## The key used 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.
[ a:defaultValue = "anonymousUser" ] attribute username {xsd:string}?
## 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.
[ a:defaultValue = "ROLE_ANONYMOUS" ] attribute grantedAuthority {xsd:string}?
## 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 grantedAuthority {xsd:string}?
repository =
element repository {repository.attlist, (user-service | jdbc-user-service | custom-user-service)}

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.springframework.org/schema/security" xmlns:security="http://www.springframework.org/schema/security">
<!-- targetNamespace="http://www.springframework.org/schema/security" -->
<xs:attributeGroup name="path-type">
<xs:attributeGroup name="pathType">
<xs:attribute name="pathType" use="required">
<xs:annotation>
<xs:documentation>Defines the type types of pattern used to specify URL paths. Defaults to "ant"</xs:documentation>
<xs:documentation>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.</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="regex"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
@ -28,12 +28,6 @@
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="autoconfig">
<xs:annotation>
<xs:documentation>Provides automatic security configration for a application</xs:documentation>
</xs:annotation>
<xs:complexType/>
</xs:element>
<xs:element name="ldap">
<xs:annotation>
<xs:documentation>Sets up an ldap authentication provider, optionally with an embedded ldap server</xs:documentation>
@ -107,9 +101,20 @@
</xs:complexType>
</xs:element>
<xs:attributeGroup name="http.attlist">
<xs:attribute name="createSession" default="ifRequired">
<xs:attribute name="autoConfig">
<xs:annotation>
<xs:documentation>Controls the eagerness with which an HTTP session is created.</xs:documentation>
<xs:documentation>Automatically registers a login form, BASIC authentication, anonymous authentication, logout services and remember-me. 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".</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="createSession">
<xs:annotation>
<xs:documentation>Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired".</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
@ -121,18 +126,18 @@
</xs:attribute>
<xs:attribute name="pathType">
<xs:annotation>
<xs:documentation>Defines the type types of pattern used to specify URL paths. Defaults to "ant"</xs:documentation>
<xs:documentation>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.</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="regex"/>
<xs:enumeration value="ant"/>
<xs:enumeration value="regex"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="lowerCaseComparisons" default="true">
<xs:attribute name="lowercaseComparisons">
<xs:annotation>
<xs:documentation>Whether test URLs should be converted to lower case prior to comparing with defined path patterns.</xs:documentation>
<xs:documentation>Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true".</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
@ -194,14 +199,28 @@
</xs:attribute>
</xs:attributeGroup>
<xs:element name="logout">
<xs:annotation>
<xs:documentation>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.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:logout.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="logout.attlist">
<xs:attribute name="logoutUrl" default="/j_spring_security_logout" type="xs:string"/>
<xs:attribute name="logoutSuccessUrl" default="/" type="xs:string"/>
<xs:attribute name="invalidateSession" default="true">
<xs:attribute name="logoutUrl" type="xs:string">
<xs:annotation>
<xs:documentation>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.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="logoutSuccessUrl" type="xs:string">
<xs:annotation>
<xs:documentation>Specifies the URL to display once the user has logged out. If not specified, defaults to /.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="invalidateSession">
<xs:annotation>
<xs:documentation>Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
@ -252,7 +271,7 @@
</xs:complexType>
</xs:element>
<xs:attributeGroup name="filter-chain-map.attlist">
<xs:attributeGroup ref="security:path-type"/>
<xs:attributeGroup ref="security:pathType"/>
</xs:attributeGroup>
<xs:element name="filter-chain">
<xs:annotation>
@ -311,19 +330,19 @@
</xs:complexType>
</xs:element>
<xs:attributeGroup name="anonymous.attlist">
<xs:attribute name="key" default="doesNotMatter" type="xs:string">
<xs:attribute name="key" type="xs:string">
<xs:annotation>
<xs:documentation>The key used between the provider and filter. This generally does not need to be set.</xs:documentation>
<xs:documentation>The key used between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="username" default="anonymousUser" type="xs:string">
<xs:attribute name="username" type="xs:string">
<xs:annotation>
<xs:documentation>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. </xs:documentation>
<xs:documentation>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". </xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="grantedAuthority" default="ROLE_ANONYMOUS" type="xs:string">
<xs:attribute name="grantedAuthority" type="xs:string">
<xs:annotation>
<xs:documentation>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.</xs:documentation>
<xs:documentation>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".</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>

View File

@ -6,19 +6,19 @@
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">
<http createSession="ifRequired" pathType="ant" lowerCaseComparisons="true">
<http>
<intercept-url pattern="/unprotected" filters="none" />
<intercept-url pattern="/somepath" access="ROLE_SPECIAL,ROLE_USER" requiresChannel="http" />
<intercept-url pattern="/**" access="ROLE_USER" />
<!-- Default form login configuration. Will create filter and entry point -->
<form-login loginUrl="/j_spring_security_check" />
<form-login />
<!-- Default basic auth configuration. Will create filter and entry point -->
<http-basic/>
<!-- Default logout configuration -->
<logout logoutUrl="/j_spring_security_logout" logoutSuccessUrl="/" invalidateSession="true" />
<logout />
<concurrent-session-control maxSessions="1"/>

View File

@ -11,23 +11,27 @@
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">
<http>
<http>
<intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR"/>
<intercept-url pattern="/secure/**" access="IS_AUTHENTICATED_REMEMBERED" />
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!-- All of this is unnecessary if autoConfig="true"-->
<form-login />
<anonymous />
<http-basic />
<logout />
<logout />
<remember-me />
<concurrent-session-control maxSessions="1" exceptionIfMaximumExceeded="true"/>
<remember-me key="doesntmatter"/>
</http>
<!--
</http>
<!--
<beans:bean name="tokenRepo" class="org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl"/>
-->
-->
<repository>
<user-service>
<user name="bob" password="bobspassword" authorities="ROLE_SUPERVISOR" />