SEC-1229: Added session-management element to namespace and refactored existing session-related attributes and concurrency control. Refactored <http> parsing code to split it up into more manageable units.
This commit is contained in:
parent
b8c0bb71f1
commit
aa153681bf
|
@ -0,0 +1,11 @@
|
|||
#! /bin/sh
|
||||
|
||||
pushd src/main/resources/org/springframework/security/config/
|
||||
|
||||
echo "Converting rnc file to xsd ..."
|
||||
java -jar ~/bin/trang.jar spring-security-3.0.rnc spring-security-3.0.xsd
|
||||
|
||||
echo "Applying XSL transformation to xsd ..."
|
||||
xsltproc --output spring-security-3.0.xsd spring-security.xsl spring-security-3.0.xsd
|
||||
|
||||
popd
|
|
@ -28,7 +28,8 @@ public abstract class Elements {
|
|||
public static final String PRE_INVOCATION_ADVICE = "pre-invocation-advice";
|
||||
public static final String POST_INVOCATION_ADVICE = "post-invocation-advice";
|
||||
public static final String PROTECT = "protect";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
|
||||
public static final String SESSION_MANAGEMENT = "session-management";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrency-control";
|
||||
public static final String LOGOUT = "logout";
|
||||
public static final String FORM_LOGIN = "form-login";
|
||||
public static final String OPENID_LOGIN = "openid-login";
|
||||
|
|
|
@ -0,0 +1,614 @@
|
|||
package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.FilterChainOrder.*;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
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.ParserContext;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||
import org.springframework.security.web.PortResolverImpl;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.authentication.AnonymousProcessingFilter;
|
||||
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509PreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicProcessingFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicProcessingFilterEntryPoint;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Handles creation of authentication mechanism filters and related beans for <http> parsing.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
final class AuthenticationConfigBuilder {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_REALM = "realm";
|
||||
private static final String DEF_REALM = "Spring Security Application";
|
||||
|
||||
static final String OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProcessingFilter";
|
||||
static final String OPEN_ID_AUTHENTICATION_PROVIDER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProvider";
|
||||
static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
|
||||
static final String OPEN_ID_ATTRIBUTE_CLASS = "org.springframework.security.openid.OpenIDAttribute";
|
||||
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter";
|
||||
|
||||
private static final String ATT_AUTO_CONFIG = "auto-config";
|
||||
|
||||
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
private static final String ATT_ACCESS_DENIED_ERROR_PAGE = "error-page";
|
||||
private static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
|
||||
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
|
||||
|
||||
private static final String ATT_REF = "ref";
|
||||
|
||||
private Element httpElt;
|
||||
private ParserContext pc;
|
||||
|
||||
private final boolean autoConfig;
|
||||
private final boolean allowSessionCreation;
|
||||
private final String portMapperName;
|
||||
|
||||
private RootBeanDefinition anonymousFilter;
|
||||
private BeanReference anonymousProviderRef;
|
||||
private BeanDefinition rememberMeFilter;
|
||||
private String rememberMeServicesId;
|
||||
private BeanReference rememberMeProviderRef;
|
||||
private BeanDefinition basicFilter;
|
||||
private BeanDefinition basicEntryPoint;
|
||||
private RootBeanDefinition formFilter;
|
||||
private BeanDefinition formEntryPoint;
|
||||
private RootBeanDefinition openIDFilter;
|
||||
private BeanDefinition openIDEntryPoint;
|
||||
private BeanReference openIDProviderRef;
|
||||
private String openIDProviderId;
|
||||
private String formFilterId = null;
|
||||
private String openIDFilterId = null;
|
||||
private BeanDefinition x509Filter;
|
||||
private BeanDefinition x509EntryPoint;
|
||||
private BeanReference x509ProviderRef;
|
||||
private String x509ProviderId;
|
||||
private BeanDefinition logoutFilter;
|
||||
private BeanDefinition loginPageGenerationFilter;
|
||||
private BeanDefinition etf;
|
||||
private BeanReference requestCache;
|
||||
|
||||
final SecureRandom random;
|
||||
|
||||
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
|
||||
String portMapperName) {
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.portMapperName = portMapperName;
|
||||
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
|
||||
this.allowSessionCreation = allowSessionCreation;
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Shouldn't happen...
|
||||
throw new RuntimeException("Failed find SHA1PRNG algorithm!");
|
||||
}
|
||||
}
|
||||
|
||||
void createRememberMeFilter(BeanReference authenticationManager) {
|
||||
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
|
||||
|
||||
if (rememberMeElt != null) {
|
||||
rememberMeFilter = (RootBeanDefinition) new RememberMeBeanDefinitionParser().parse(rememberMeElt, pc);
|
||||
rememberMeFilter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
|
||||
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
|
||||
createRememberMeProvider();
|
||||
}
|
||||
}
|
||||
|
||||
private void createRememberMeProvider() {
|
||||
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
provider.setSource(rememberMeFilter.getSource());
|
||||
// Locate the RememberMeServices bean and read the "key" property from it
|
||||
PropertyValue key = null;
|
||||
if (pc.getRegistry().containsBeanDefinition(rememberMeServicesId)) {
|
||||
BeanDefinition services = pc.getRegistry().getBeanDefinition(rememberMeServicesId);
|
||||
|
||||
key = services.getPropertyValues().getPropertyValue("key");
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
key = new PropertyValue("key", RememberMeBeanDefinitionParser.DEF_KEY);
|
||||
}
|
||||
|
||||
provider.getPropertyValues().addPropertyValue(key);
|
||||
|
||||
String id = pc.getReaderContext().registerWithGeneratedName(provider);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(provider, id));
|
||||
|
||||
rememberMeProviderRef = new RuntimeBeanReference(id);
|
||||
}
|
||||
|
||||
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
|
||||
|
||||
if (formLoginElt != null || autoConfig) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
|
||||
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
|
||||
|
||||
parser.parse(formLoginElt, pc);
|
||||
formFilter = parser.getFilterBean();
|
||||
formEntryPoint = parser.getEntryPointBean();
|
||||
}
|
||||
|
||||
if (formFilter != null) {
|
||||
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
|
||||
|
||||
// Id is required by login page filter
|
||||
formFilterId = pc.getReaderContext().registerWithGeneratedName(formFilter);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(formFilter, formFilterId));
|
||||
injectRememberMeServicesRef(formFilter, rememberMeServicesId);
|
||||
}
|
||||
}
|
||||
|
||||
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||
|
||||
if (openIDLoginElt != null) {
|
||||
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
|
||||
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
|
||||
|
||||
parser.parse(openIDLoginElt, pc);
|
||||
openIDFilter = parser.getFilterBean();
|
||||
openIDEntryPoint = parser.getEntryPointBean();
|
||||
|
||||
Element attrExElt = DomUtils.getChildElementByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
|
||||
|
||||
if (attrExElt != null) {
|
||||
// Set up the consumer with the required attribute list
|
||||
BeanDefinitionBuilder consumerBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_CONSUMER_CLASS);
|
||||
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
|
||||
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
|
||||
String name = attElt.getAttribute("name");
|
||||
String type = attElt.getAttribute("type");
|
||||
String required = attElt.getAttribute("required");
|
||||
String count = attElt.getAttribute("count");
|
||||
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
|
||||
attrBldr.addConstructorArgValue(name);
|
||||
attrBldr.addConstructorArgValue(type);
|
||||
if (StringUtils.hasLength(required)) {
|
||||
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(count)) {
|
||||
attrBldr.addPropertyValue("count", Integer.parseInt(count));
|
||||
}
|
||||
attributes.add(attrBldr.getBeanDefinition());
|
||||
}
|
||||
consumerBldr.addConstructorArgValue(attributes);
|
||||
openIDFilter.getPropertyValues().addPropertyValue("consumer", consumerBldr.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
|
||||
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
|
||||
// Required by login page filter
|
||||
openIDFilterId = pc.getReaderContext().registerWithGeneratedName(openIDFilter);
|
||||
pc.getRegistry().registerBeanDefinition(openIDFilterId, openIDFilter);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(openIDFilter, openIDFilterId));
|
||||
injectRememberMeServicesRef(openIDFilter, rememberMeServicesId);
|
||||
|
||||
createOpenIDProvider();
|
||||
}
|
||||
}
|
||||
|
||||
private void createOpenIDProvider() {
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||
BeanDefinitionBuilder openIDProviderBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
|
||||
|
||||
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
if (StringUtils.hasText(userService)) {
|
||||
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
|
||||
}
|
||||
|
||||
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
|
||||
openIDProviderId = pc.getReaderContext().registerWithGeneratedName(openIDProvider);
|
||||
openIDProviderRef = new RuntimeBeanReference(openIDProviderId);
|
||||
}
|
||||
|
||||
private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) {
|
||||
if (rememberMeServicesId != null) {
|
||||
bean.getPropertyValues().addPropertyValue("rememberMeServices", new RuntimeBeanReference(rememberMeServicesId));
|
||||
}
|
||||
}
|
||||
|
||||
void createBasicFilter(BeanReference authManager) {
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt, Elements.BASIC_AUTH);
|
||||
|
||||
String realm = httpElt.getAttribute(ATT_REALM);
|
||||
if (!StringUtils.hasText(realm)) {
|
||||
realm = DEF_REALM;
|
||||
}
|
||||
|
||||
RootBeanDefinition filter = null;
|
||||
RootBeanDefinition entryPoint = null;
|
||||
|
||||
if (basicAuthElt != null || autoConfig) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicProcessingFilter.class);
|
||||
entryPoint = new RootBeanDefinition(BasicProcessingFilterEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(httpElt));
|
||||
|
||||
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
|
||||
|
||||
String entryPointId = pc.getReaderContext().registerWithGeneratedName(entryPoint);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPointId));
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
basicFilter = filter;
|
||||
basicEntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
void createX509Filter(BeanReference authManager) {
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
|
||||
RootBeanDefinition filter = null;
|
||||
RootBeanDefinition entryPoint = null;
|
||||
|
||||
if (x509Elt != null) {
|
||||
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509PreAuthenticatedProcessingFilter.class);
|
||||
filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(x509Elt));
|
||||
filterBuilder.addPropertyValue("authenticationManager", authManager);
|
||||
|
||||
String regex = x509Elt.getAttribute("subject-principal-regex");
|
||||
|
||||
if (StringUtils.hasText(regex)) {
|
||||
BeanDefinitionBuilder extractor = BeanDefinitionBuilder.rootBeanDefinition(SubjectDnX509PrincipalExtractor.class);
|
||||
extractor.addPropertyValue("subjectDnRegex", regex);
|
||||
|
||||
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
|
||||
}
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
|
||||
entryPoint.setSource(pc.extractSource(x509Elt));
|
||||
|
||||
createX509Provider();
|
||||
}
|
||||
|
||||
x509Filter = filter;
|
||||
x509EntryPoint = entryPoint;
|
||||
}
|
||||
|
||||
private void createX509Provider() {
|
||||
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
|
||||
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
|
||||
|
||||
String userServiceRef = x509Elt.getAttribute(ATT_USER_SERVICE_REF);
|
||||
|
||||
if (StringUtils.hasText(userServiceRef)) {
|
||||
RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class);
|
||||
preAuthUserService.setSource(pc.extractSource(x509Elt));
|
||||
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
|
||||
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService);
|
||||
}
|
||||
|
||||
x509ProviderId = pc.getReaderContext().registerWithGeneratedName(provider);
|
||||
x509ProviderRef = new RuntimeBeanReference(x509ProviderId);
|
||||
}
|
||||
|
||||
|
||||
void createLoginPageFilterIfNeeded() {
|
||||
boolean needLoginPage = formFilter != null || openIDFilter != null;
|
||||
String formLoginPage = getLoginFormUrl(formEntryPoint);
|
||||
// If the login URL is the default one, then it is assumed not to have been set explicitly
|
||||
if (DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL == formLoginPage) {
|
||||
formLoginPage = null;
|
||||
}
|
||||
String openIDLoginPage = getLoginFormUrl(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 (formFilter != null) {
|
||||
loginPageFilter.addConstructorArgReference(formFilterId);
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
loginPageFilter.addConstructorArgReference(openIDFilterId);
|
||||
}
|
||||
|
||||
loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
void createLogoutFilter() {
|
||||
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
|
||||
if (logoutElt != null || autoConfig) {
|
||||
logoutFilter = new LogoutBeanDefinitionParser(rememberMeServicesId).parse(logoutElt, pc);
|
||||
}
|
||||
}
|
||||
|
||||
void createAnonymousFilter() {
|
||||
Element anonymousElt = DomUtils.getChildElementByTagName(httpElt, Elements.ANONYMOUS);
|
||||
|
||||
if (anonymousElt != null && "false".equals(anonymousElt.getAttribute("enabled"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
String grantedAuthority = null;
|
||||
String username = null;
|
||||
String key = null;
|
||||
Object source = pc.extractSource(httpElt);
|
||||
|
||||
if (anonymousElt != null) {
|
||||
grantedAuthority = httpElt.getAttribute("granted-authority");
|
||||
username = httpElt.getAttribute("username");
|
||||
key = httpElt.getAttribute("key");
|
||||
source = pc.extractSource(anonymousElt);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(grantedAuthority)) {
|
||||
grantedAuthority = "ROLE_ANONYMOUS";
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(username)) {
|
||||
username = "anonymousUser";
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(key)) {
|
||||
// Generate a random key for the Anonymous provider
|
||||
key = Long.toString(random.nextLong());
|
||||
}
|
||||
|
||||
anonymousFilter = new RootBeanDefinition(AnonymousProcessingFilter.class);
|
||||
|
||||
PropertyValue keyPV = new PropertyValue("key", key);
|
||||
anonymousFilter.setSource(source);
|
||||
anonymousFilter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority);
|
||||
anonymousFilter.getPropertyValues().addPropertyValue(keyPV);
|
||||
|
||||
RootBeanDefinition anonymousProviderBean = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
|
||||
anonymousProviderBean.setSource(anonymousFilter.getSource());
|
||||
anonymousProviderBean.getPropertyValues().addPropertyValue(keyPV);
|
||||
String id = pc.getReaderContext().registerWithGeneratedName(anonymousProviderBean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(anonymousProviderBean, id));
|
||||
|
||||
anonymousProviderRef = new RuntimeBeanReference(id);
|
||||
|
||||
}
|
||||
|
||||
void createExceptionTranslationFilter() {
|
||||
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
|
||||
assert requestCache != null;
|
||||
etfBuilder.addPropertyValue("requestCache", requestCache);
|
||||
etfBuilder.addPropertyValue("authenticationEntryPoint", selectEntryPoint());
|
||||
|
||||
etf = etfBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
void createRequestCache() {
|
||||
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt, Elements.REQUEST_CACHE);
|
||||
|
||||
if (requestCacheElt != null) {
|
||||
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
|
||||
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
|
||||
portResolver.addPropertyReference("portMapper", portMapperName);
|
||||
requestCacheBldr.addPropertyValue("createSessionAllowed", allowSessionCreation);
|
||||
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
|
||||
|
||||
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
|
||||
String id = pc.getReaderContext().registerWithGeneratedName(bean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
|
||||
|
||||
this.requestCache = new RuntimeBeanReference(id);
|
||||
}
|
||||
|
||||
|
||||
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
WebConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
Element accessDeniedElt = DomUtils.getChildElementByTagName(element, Elements.ACCESS_DENIED_HANDLER);
|
||||
BeanDefinitionBuilder accessDeniedHandler = BeanDefinitionBuilder.rootBeanDefinition(AccessDeniedHandlerImpl.class);
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
if (accessDeniedElt != null) {
|
||||
pc.getReaderContext().error("The attribute " + ATT_ACCESS_DENIED_PAGE +
|
||||
" cannot be used with <" + Elements.ACCESS_DENIED_HANDLER + ">", pc.extractSource(accessDeniedElt));
|
||||
}
|
||||
|
||||
accessDeniedHandler.addPropertyValue("errorPage", accessDeniedPage);
|
||||
}
|
||||
|
||||
if (accessDeniedElt != null) {
|
||||
String errorPage = accessDeniedElt.getAttribute("error-page");
|
||||
String ref = accessDeniedElt.getAttribute("ref");
|
||||
|
||||
if (StringUtils.hasText(errorPage)) {
|
||||
if (StringUtils.hasText(ref)) {
|
||||
pc.getReaderContext().error("The attribute " + ATT_ACCESS_DENIED_ERROR_PAGE +
|
||||
" cannot be used together with the 'ref' attribute within <" +
|
||||
Elements.ACCESS_DENIED_HANDLER + ">", pc.extractSource(accessDeniedElt));
|
||||
|
||||
}
|
||||
accessDeniedHandler.addPropertyValue("errorPage", errorPage);
|
||||
} else if (StringUtils.hasText(ref)) {
|
||||
return new RuntimeBeanReference(ref);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return accessDeniedHandler.getBeanDefinition();
|
||||
}
|
||||
|
||||
private BeanMetadataElement selectEntryPoint() {
|
||||
// We need to establish the main entry point.
|
||||
// First check if a custom entry point bean is set
|
||||
String customEntryPoint = httpElt.getAttribute(ATT_ENTRY_POINT_REF);
|
||||
|
||||
if (StringUtils.hasText(customEntryPoint)) {
|
||||
return new RuntimeBeanReference(customEntryPoint);
|
||||
}
|
||||
|
||||
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt, Elements.BASIC_AUTH);
|
||||
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
|
||||
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
|
||||
// Basic takes precedence if explicit element is used and no others are configured
|
||||
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
|
||||
return basicEntryPoint;
|
||||
}
|
||||
|
||||
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
|
||||
// has been set
|
||||
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
|
||||
|
||||
if (formFilter != null && openIDLoginPage == null) {
|
||||
return formEntryPoint;
|
||||
}
|
||||
|
||||
// Otherwise use OpenID if enabled
|
||||
if (openIDFilter != null && formFilter == null) {
|
||||
return openIDEntryPoint;
|
||||
}
|
||||
|
||||
// If X.509 has been enabled, use the preauth entry point.
|
||||
if (DomUtils.getChildElementByTagName(httpElt, Elements.X509) != null) {
|
||||
return x509EntryPoint;
|
||||
}
|
||||
|
||||
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 '" + ATT_ENTRY_POINT_REF+ "' attribute ",
|
||||
pc.extractSource(httpElt));
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getLoginFormUrl(BeanDefinition entryPoint) {
|
||||
if (entryPoint == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PropertyValues pvs = entryPoint.getPropertyValues();
|
||||
PropertyValue pv = pvs.getPropertyValue("loginFormUrl");
|
||||
if (pv == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (String) pv.getValue();
|
||||
}
|
||||
|
||||
void createUserServiceInjector() {
|
||||
BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
|
||||
userServiceInjector.addConstructorArgValue(x509ProviderId);
|
||||
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
|
||||
userServiceInjector.addConstructorArgValue(openIDProviderId);
|
||||
userServiceInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
pc.getReaderContext().registerWithGeneratedName(userServiceInjector.getBeanDefinition());
|
||||
}
|
||||
|
||||
List<OrderDecorator> getFilters() {
|
||||
List<OrderDecorator> filters = new ArrayList<OrderDecorator>();
|
||||
|
||||
if (anonymousFilter != null) {
|
||||
filters.add(new OrderDecorator(anonymousFilter, ANONYMOUS_FILTER));
|
||||
}
|
||||
|
||||
if (rememberMeFilter != null) {
|
||||
filters.add(new OrderDecorator(rememberMeFilter, REMEMBER_ME_FILTER));
|
||||
}
|
||||
|
||||
if (logoutFilter != null) {
|
||||
filters.add(new OrderDecorator(logoutFilter, LOGOUT_FILTER));
|
||||
}
|
||||
|
||||
if (x509Filter != null) {
|
||||
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
|
||||
}
|
||||
|
||||
if (formFilter != null) {
|
||||
filters.add(new OrderDecorator(formFilter, AUTHENTICATION_PROCESSING_FILTER));
|
||||
}
|
||||
|
||||
if (openIDFilter != null) {
|
||||
filters.add(new OrderDecorator(openIDFilter, OPENID_PROCESSING_FILTER));
|
||||
}
|
||||
|
||||
if (loginPageGenerationFilter != null) {
|
||||
filters.add(new OrderDecorator(loginPageGenerationFilter, LOGIN_PAGE_FILTER));
|
||||
}
|
||||
|
||||
if (basicFilter != null) {
|
||||
filters.add(new OrderDecorator(basicFilter, BASIC_PROCESSING_FILTER));
|
||||
}
|
||||
|
||||
filters.add(new OrderDecorator(etf, EXCEPTION_TRANSLATION_FILTER));
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
List<BeanReference> getProviders() {
|
||||
List<BeanReference> providers = new ArrayList<BeanReference>();
|
||||
|
||||
if (anonymousProviderRef != null) {
|
||||
providers.add(anonymousProviderRef);
|
||||
}
|
||||
|
||||
if (rememberMeProviderRef != null) {
|
||||
providers.add(rememberMeProviderRef);
|
||||
}
|
||||
|
||||
if (openIDProviderRef != null) {
|
||||
providers.add(openIDProviderRef);
|
||||
}
|
||||
|
||||
if (x509ProviderRef != null) {
|
||||
providers.add(x509ProviderRef);
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
public BeanReference getRequestCache() {
|
||||
return requestCache;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,520 @@
|
|||
package org.springframework.security.config.http;
|
||||
|
||||
import static org.springframework.security.config.http.FilterChainOrder.*;
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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.BeanReference;
|
||||
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.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.access.vote.AffirmativeBased;
|
||||
import org.springframework.security.access.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.access.vote.RoleVoter;
|
||||
import org.springframework.security.authentication.concurrent.SessionRegistryImpl;
|
||||
import org.springframework.security.config.Elements;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||
import org.springframework.security.web.access.channel.InsecureChannelProcessor;
|
||||
import org.springframework.security.web.access.channel.RetryWithHttpEntryPoint;
|
||||
import org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint;
|
||||
import org.springframework.security.web.access.channel.SecureChannelProcessor;
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter;
|
||||
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.access.intercept.RequestKey;
|
||||
import org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
||||
import org.springframework.security.web.session.ConcurrentSessionControlAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.session.DefaultSessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.security.web.util.AntUrlPathMatcher;
|
||||
import org.springframework.security.web.util.UrlMatcher;
|
||||
import org.springframework.security.web.wrapper.SecurityContextHolderAwareRequestFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Stateful class which helps HttpSecurityBDP to create the configuration for the <http> element.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
class HttpConfigurationBuilder {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private static final String ATT_CREATE_SESSION = "create-session";
|
||||
private static final String OPT_CREATE_SESSION_NEVER = "never";
|
||||
private static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
|
||||
private static final String OPT_CREATE_SESSION_ALWAYS = "always";
|
||||
|
||||
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_INVALID_SESSION_URL = "invalid-session-url";
|
||||
|
||||
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 ATT_ACCESS_MGR = "access-decision-manager-ref";
|
||||
private static final String ATT_USE_EXPRESSIONS = "use-expressions";
|
||||
private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
|
||||
private final Element httpElt;
|
||||
private final ParserContext pc;
|
||||
private final UrlMatcher matcher;
|
||||
private final Boolean convertPathsToLowerCase;
|
||||
private final boolean allowSessionCreation;
|
||||
private final List<Element> interceptUrls;
|
||||
|
||||
// Use ManagedMap to allow placeholder resolution
|
||||
private List<String> emptyFilterChainPaths;
|
||||
private ManagedMap<String, List<BeanMetadataElement>> filterChainMap;
|
||||
|
||||
private BeanDefinition cpf;
|
||||
private BeanDefinition securityContextPersistenceFilter;
|
||||
private BeanReference contextRepoRef;
|
||||
private BeanReference sessionRegistryRef;
|
||||
private BeanDefinition concurrentSessionFilter;
|
||||
private BeanReference sessionStrategyRef;
|
||||
private RootBeanDefinition sfpf;
|
||||
private BeanDefinition servApiFilter;
|
||||
private String portMapperName;
|
||||
private BeanReference fsi;
|
||||
|
||||
|
||||
public HttpConfigurationBuilder(Element element, ParserContext pc, UrlMatcher matcher, String portMapperName) {
|
||||
this.httpElt = element;
|
||||
this.pc = pc;
|
||||
this.portMapperName = portMapperName;
|
||||
this.matcher = matcher;
|
||||
// SEC-501 - should paths stored in request maps be converted to lower case
|
||||
// true if Ant path and using lower case
|
||||
convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
|
||||
interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
|
||||
allowSessionCreation = !OPT_CREATE_SESSION_NEVER.equals(element.getAttribute(ATT_CREATE_SESSION));
|
||||
}
|
||||
|
||||
void parseInterceptUrlsForEmptyFilterChains() {
|
||||
emptyFilterChainPaths = new ArrayList<String>();
|
||||
filterChainMap = new ManagedMap<String, List<BeanMetadataElement>>();
|
||||
|
||||
for (Element urlElt : interceptUrls) {
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
pc.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||
}
|
||||
|
||||
if (convertPathsToLowerCase) {
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
String filters = urlElt.getAttribute(ATT_FILTERS);
|
||||
|
||||
if (StringUtils.hasText(filters)) {
|
||||
if (!filters.equals(OPT_FILTERS_NONE)) {
|
||||
pc.getReaderContext().error("Currently only 'none' is supported as the custom " +
|
||||
"filters attribute", urlElt);
|
||||
}
|
||||
|
||||
emptyFilterChainPaths.add(path);
|
||||
|
||||
List<BeanMetadataElement> noFilters = Collections.emptyList();
|
||||
filterChainMap.put(path, noFilters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createSecurityContextPersistenceFilter() {
|
||||
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
|
||||
|
||||
String repoRef = httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
|
||||
String createSession = httpElt.getAttribute(ATT_CREATE_SESSION);
|
||||
String disableUrlRewriting = httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
|
||||
|
||||
if (StringUtils.hasText(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", httpElt);
|
||||
}
|
||||
} 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);
|
||||
} 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);
|
||||
}
|
||||
|
||||
BeanDefinition repoBean = contextRepo.getBeanDefinition();
|
||||
repoRef = pc.getReaderContext().registerWithGeneratedName(repoBean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
|
||||
|
||||
}
|
||||
|
||||
contextRepoRef = new RuntimeBeanReference(repoRef);
|
||||
scpf.addPropertyValue("securityContextRepository", contextRepoRef);
|
||||
|
||||
securityContextPersistenceFilter = scpf.getBeanDefinition();
|
||||
}
|
||||
|
||||
void createSessionManagementFilters() {
|
||||
Element sessionMgmtElt = DomUtils.getChildElementByTagName(httpElt, Elements.SESSION_MANAGEMENT);
|
||||
Element sessionCtrlEt = null;
|
||||
|
||||
String sessionFixationAttribute = null;
|
||||
String invalidSessionUrl = null;
|
||||
|
||||
if (sessionMgmtElt != null) {
|
||||
sessionFixationAttribute = sessionMgmtElt.getAttribute(ATT_SESSION_FIXATION_PROTECTION);
|
||||
invalidSessionUrl = sessionMgmtElt.getAttribute(ATT_INVALID_SESSION_URL);
|
||||
sessionCtrlEt = DomUtils.getChildElementByTagName(sessionMgmtElt, Elements.CONCURRENT_SESSIONS);
|
||||
|
||||
if (sessionCtrlEt != null) {
|
||||
createConcurrencyControlFilterAndSessionRegistry(sessionCtrlEt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(sessionFixationAttribute)) {
|
||||
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
|
||||
}
|
||||
|
||||
boolean sessionFixationProtectionRequired = !sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION);
|
||||
|
||||
BeanDefinitionBuilder sessionStrategy;
|
||||
|
||||
if (sessionCtrlEt != null) {
|
||||
assert sessionRegistryRef != null;
|
||||
sessionStrategy = BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControlAuthenticatedSessionStrategy.class);
|
||||
sessionStrategy.addConstructorArgValue(sessionRegistryRef);
|
||||
|
||||
String maxSessions = sessionCtrlEt.getAttribute("max-sessions");
|
||||
|
||||
if (StringUtils.hasText(maxSessions)) {
|
||||
sessionStrategy.addPropertyValue("maximumSessions", maxSessions);
|
||||
}
|
||||
|
||||
String exceptionIfMaximumExceeded = sessionCtrlEt.getAttribute("exception-if-maximum-exceeded");
|
||||
|
||||
if (StringUtils.hasText(exceptionIfMaximumExceeded)) {
|
||||
sessionStrategy.addPropertyValue("exceptionIfMaximumExceeded", exceptionIfMaximumExceeded);
|
||||
}
|
||||
} else if (sessionFixationProtectionRequired || StringUtils.hasText(invalidSessionUrl)) {
|
||||
sessionStrategy = BeanDefinitionBuilder.rootBeanDefinition(DefaultSessionAuthenticationStrategy.class);
|
||||
} else {
|
||||
sfpf = null;
|
||||
return;
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder sessionMgmtFilter = BeanDefinitionBuilder.rootBeanDefinition(SessionManagementFilter.class);
|
||||
sessionMgmtFilter.addConstructorArgValue(contextRepoRef);
|
||||
BeanDefinition strategyBean = sessionStrategy.getBeanDefinition();
|
||||
|
||||
String sessionStrategyId = pc.getReaderContext().registerWithGeneratedName(strategyBean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(strategyBean, sessionStrategyId));
|
||||
sessionMgmtFilter.addPropertyReference("authenticatedSessionStrategy", sessionStrategyId);
|
||||
if (sessionFixationProtectionRequired) {
|
||||
|
||||
sessionStrategy.addPropertyValue("migrateSessionAttributes",
|
||||
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(invalidSessionUrl)) {
|
||||
sessionMgmtFilter.addPropertyValue("invalidSessionUrl", invalidSessionUrl);
|
||||
}
|
||||
|
||||
sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition();
|
||||
sessionStrategyRef = new RuntimeBeanReference(sessionStrategyId);
|
||||
}
|
||||
|
||||
private void createConcurrencyControlFilterAndSessionRegistry(Element element) {
|
||||
final String ATT_EXPIRY_URL = "expired-url";
|
||||
final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
|
||||
final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";
|
||||
|
||||
CompositeComponentDefinition compositeDef =
|
||||
new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
|
||||
pc.pushContainingComponent(compositeDef);
|
||||
|
||||
BeanDefinitionRegistry beanRegistry = pc.getRegistry();
|
||||
|
||||
String sessionRegistryId = element.getAttribute(ATT_SESSION_REGISTRY_REF);
|
||||
|
||||
if (!StringUtils.hasText(sessionRegistryId)) {
|
||||
// Register an internal SessionRegistryImpl if no external reference supplied.
|
||||
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
|
||||
sessionRegistryId = pc.getReaderContext().registerWithGeneratedName(sessionRegistry);
|
||||
pc.registerComponent(new BeanComponentDefinition(sessionRegistry, sessionRegistryId));
|
||||
}
|
||||
|
||||
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
|
||||
if (StringUtils.hasText(registryAlias)) {
|
||||
beanRegistry.registerAlias(sessionRegistryId, registryAlias);
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder filterBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
|
||||
filterBuilder.addPropertyReference("sessionRegistry", sessionRegistryId);
|
||||
|
||||
Object source = pc.extractSource(element);
|
||||
filterBuilder.getRawBeanDefinition().setSource(source);
|
||||
filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
String expiryUrl = element.getAttribute(ATT_EXPIRY_URL);
|
||||
|
||||
if (StringUtils.hasText(expiryUrl)) {
|
||||
WebConfigUtils.validateHttpRedirect(expiryUrl, pc, source);
|
||||
filterBuilder.addPropertyValue("expiredUrl", expiryUrl);
|
||||
}
|
||||
|
||||
pc.popAndRegisterContainingComponent();
|
||||
|
||||
concurrentSessionFilter = filterBuilder.getBeanDefinition();
|
||||
sessionRegistryRef = new RuntimeBeanReference(sessionRegistryId);
|
||||
}
|
||||
|
||||
// Adds the servlet-api integration filter if required
|
||||
void createServletApiFilter() {
|
||||
final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
|
||||
final String DEF_SERVLET_API_PROVISION = "true";
|
||||
|
||||
String provideServletApi = httpElt.getAttribute(ATT_SERVLET_API_PROVISION);
|
||||
if (!StringUtils.hasText(provideServletApi)) {
|
||||
provideServletApi = DEF_SERVLET_API_PROVISION;
|
||||
}
|
||||
|
||||
if ("true".equals(provideServletApi)) {
|
||||
servApiFilter = new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
void createChannelProcessingFilter() {
|
||||
ManagedMap<BeanDefinition,BeanDefinition> channelRequestMap = parseInterceptUrlsForChannelSecurity();
|
||||
|
||||
if (channelRequestMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
|
||||
BeanDefinitionBuilder metadataSourceBldr = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
|
||||
metadataSourceBldr.addConstructorArgValue(matcher);
|
||||
metadataSourceBldr.addConstructorArgValue(channelRequestMap);
|
||||
metadataSourceBldr.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource", metadataSourceBldr.getBeanDefinition());
|
||||
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
|
||||
ManagedList<RootBeanDefinition> channelProcessors = new ManagedList<RootBeanDefinition>(3);
|
||||
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
|
||||
RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
|
||||
RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
|
||||
RuntimeBeanReference portMapper = new RuntimeBeanReference(portMapperName);
|
||||
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);
|
||||
|
||||
String id = pc.getReaderContext().registerWithGeneratedName(channelDecisionManager);
|
||||
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", new RuntimeBeanReference(id));
|
||||
cpf = channelFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the intercept-url elements to obtain the map used by channel security.
|
||||
* This will be empty unless the <tt>requires-channel</tt> attribute has been used on a URL path.
|
||||
*/
|
||||
private ManagedMap<BeanDefinition,BeanDefinition> parseInterceptUrlsForChannelSecurity() {
|
||||
|
||||
ManagedMap<BeanDefinition, BeanDefinition> channelRequestMap = new ManagedMap<BeanDefinition, BeanDefinition>();
|
||||
|
||||
for (Element urlElt : interceptUrls) {
|
||||
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
|
||||
|
||||
if(!StringUtils.hasText(path)) {
|
||||
pc.getReaderContext().error("path attribute cannot be empty or null", urlElt);
|
||||
}
|
||||
|
||||
if (convertPathsToLowerCase) {
|
||||
path = path.toLowerCase();
|
||||
}
|
||||
|
||||
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
|
||||
|
||||
if (StringUtils.hasText(requiredChannel)) {
|
||||
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
|
||||
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
|
||||
|
||||
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
|
||||
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
|
||||
channelAttributes.setFactoryMethodName("createChannelAttributes");
|
||||
|
||||
channelRequestMap.put(requestKey, channelAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
return channelRequestMap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void createFilterSecurityInterceptor(BeanReference authManager) {
|
||||
BeanDefinitionBuilder fidsBuilder;
|
||||
|
||||
boolean useExpressions = "true".equals(httpElt.getAttribute(ATT_USE_EXPRESSIONS));
|
||||
|
||||
ManagedMap<BeanDefinition,BeanDefinition> requestToAttributesMap =
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(DomUtils.getChildElementsByTagName(httpElt, Elements.INTERCEPT_URL),
|
||||
convertPathsToLowerCase, useExpressions, pc);
|
||||
|
||||
RootBeanDefinition accessDecisionMgr;
|
||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
|
||||
|
||||
if (useExpressions) {
|
||||
Element expressionHandlerElt = DomUtils.getChildElementByTagName(httpElt, 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 {
|
||||
BeanDefinition expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_HANDLER_CLASS).getBeanDefinition();
|
||||
expressionHandlerRef = pc.getReaderContext().registerWithGeneratedName(expressionHandler);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
|
||||
}
|
||||
|
||||
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_FIMDS_CLASS);
|
||||
fidsBuilder.addConstructorArgValue(matcher);
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
fidsBuilder.addConstructorArgReference(expressionHandlerRef);
|
||||
voters.add(new RootBeanDefinition(WebExpressionVoter.class));
|
||||
} else {
|
||||
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
|
||||
fidsBuilder.addConstructorArgValue(matcher);
|
||||
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
|
||||
voters.add(new RootBeanDefinition(RoleVoter.class));
|
||||
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
|
||||
}
|
||||
accessDecisionMgr = new RootBeanDefinition(AffirmativeBased.class);
|
||||
accessDecisionMgr.getPropertyValues().addPropertyValue("decisionVoters", voters);
|
||||
accessDecisionMgr.setSource(pc.extractSource(httpElt));
|
||||
fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
|
||||
|
||||
// Set up the access manager reference for http
|
||||
String accessManagerId = httpElt.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
accessManagerId = pc.getReaderContext().registerWithGeneratedName(accessDecisionMgr);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(accessDecisionMgr, accessManagerId));
|
||||
}
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
||||
builder.addPropertyReference("accessDecisionManager", accessManagerId);
|
||||
builder.addPropertyValue("authenticationManager", authManager);
|
||||
|
||||
if ("false".equals(httpElt.getAttribute(ATT_ONCE_PER_REQUEST))) {
|
||||
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
|
||||
}
|
||||
|
||||
builder.addPropertyValue("securityMetadataSource", fidsBuilder.getBeanDefinition());
|
||||
BeanDefinition fsiBean = builder.getBeanDefinition();
|
||||
String fsiId = pc.getReaderContext().registerWithGeneratedName(fsiBean);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(fsiBean,fsiId));
|
||||
|
||||
// Create and register a DefaultWebInvocationPrivilegeEvaluator for use with taglibs etc.
|
||||
BeanDefinition wipe = new RootBeanDefinition(DefaultWebInvocationPrivilegeEvaluator.class);
|
||||
wipe.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(fsiId));
|
||||
String wipeId = pc.getReaderContext().registerWithGeneratedName(wipe);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(wipe, wipeId));
|
||||
|
||||
this.fsi = new RuntimeBeanReference(fsiId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the filter invocation map which will be used to configure the FilterInvocationSecurityMetadataSource
|
||||
* used in the security interceptor.
|
||||
*/
|
||||
private static ManagedMap<BeanDefinition,BeanDefinition>
|
||||
parseInterceptUrlsForFilterInvocationRequestMap(List<Element> urlElts, boolean useLowerCasePaths,
|
||||
boolean useExpressions, ParserContext parserContext) {
|
||||
|
||||
return FilterInvocationSecurityMetadataSourceBeanDefinitionParser.parseInterceptUrlsForFilterInvocationRequestMap(urlElts, useLowerCasePaths, useExpressions, parserContext);
|
||||
|
||||
}
|
||||
|
||||
BeanReference getSessionStrategy() {
|
||||
return sessionStrategyRef;
|
||||
}
|
||||
|
||||
|
||||
boolean isAllowSessionCreation() {
|
||||
return allowSessionCreation;
|
||||
}
|
||||
|
||||
List<String> getEmptyFilterChainPaths() {
|
||||
return emptyFilterChainPaths;
|
||||
}
|
||||
|
||||
List<OrderDecorator> getFilters() {
|
||||
List<OrderDecorator> filters = new ArrayList<OrderDecorator>();
|
||||
|
||||
if (cpf != null) {
|
||||
filters.add(new OrderDecorator(cpf, CHANNEL_FILTER));
|
||||
}
|
||||
|
||||
if (concurrentSessionFilter != null) {
|
||||
filters.add(new OrderDecorator(concurrentSessionFilter, CONCURRENT_SESSION_FILTER));
|
||||
}
|
||||
|
||||
filters.add(new OrderDecorator(securityContextPersistenceFilter, SECURITY_CONTEXT_FILTER));
|
||||
|
||||
if (servApiFilter != null) {
|
||||
filters.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER));
|
||||
}
|
||||
|
||||
if (sfpf != null) {
|
||||
filters.add(new OrderDecorator(sfpf, SESSION_FIXATION_FILTER));
|
||||
}
|
||||
|
||||
filters.add(new OrderDecorator(fsi, FILTER_SECURITY_INTERCEPTOR));
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -130,7 +130,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
|
|||
BeanDefinition expressionHandler = new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class);
|
||||
expressionHandlerRef = pc.getReaderContext().registerWithGeneratedName(expressionHandler);
|
||||
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
|
||||
logger.warn("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " +
|
||||
logger.info("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " +
|
||||
"All hasPermision() expressions will evaluate to false.");
|
||||
}
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@ protect-pointcut.attlist &=
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration
|
||||
element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache?) }
|
||||
element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache?) }
|
||||
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}?
|
||||
|
@ -274,9 +274,6 @@ http.attlist &=
|
|||
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:token}?
|
||||
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:token}?
|
||||
|
@ -289,9 +286,7 @@ http.attlist &=
|
|||
http.attlist &=
|
||||
##
|
||||
attribute disable-url-rewriting {boolean}?
|
||||
http.attlist &=
|
||||
## The URL to which a user will be redirected if they submit an invalid session indentifier. Typically used to detect session timeouts.
|
||||
attribute invalid-session-url {xsd:token}?
|
||||
|
||||
|
||||
access-denied-handler =
|
||||
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
|
||||
|
@ -421,28 +416,37 @@ 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}
|
||||
|
||||
session-management =
|
||||
element session-management {session-management.attlist, concurrency-control?}
|
||||
|
||||
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".
|
||||
session-management.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" }?
|
||||
session-management.attlist &=
|
||||
## The URL to which a user will be redirected if they submit an invalid session indentifier. Typically used to detect session timeouts.
|
||||
attribute invalid-session-url {xsd:token}?
|
||||
|
||||
|
||||
concurrency-control =
|
||||
## Enables concurrent session control, limiting the number of authenticated sessions a user may have at the same time.
|
||||
element concurrency-control {concurrency-control.attlist, empty}
|
||||
|
||||
concurrency-control.attlist &=
|
||||
## The maximum number of sessions a single authenticated 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.
|
||||
concurrency-control.attlist &=
|
||||
## The URL a user will be redirected to if they attempt to use a session which has been "expired" because they have logged in again.
|
||||
attribute expired-url {xsd:token}?
|
||||
concurrent-sessions.attlist &=
|
||||
concurrency-control.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
|
||||
concurrency-control.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:token}?
|
||||
concurrent-sessions.attlist &=
|
||||
## A reference to an external SessionRegistry implementation which will be used in place of the standard one.
|
||||
concurrency-control.attlist &=
|
||||
## Allows you to define an external SessionRegistry bean to be used by the concurrency control setup.
|
||||
attribute session-registry-ref {xsd:token}?
|
||||
concurrent-sessions.attlist &=
|
||||
## Allows a custom session controller to be set on the internal http AuthenticationManager. If used, the session-registry-ref attribute must also be set.
|
||||
attribute session-controller-ref {xsd:token}?
|
||||
|
||||
|
||||
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.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@
|
|||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:variable name="elts-to-inline">
|
||||
<xsl:text>,access-denied-handler,anonymous,concurrent-session-control,after-invocation-provider,authentication-provider,ldap-authentication-provider,user,port-mapping,openid-login,expression-handler,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,</xsl:text>
|
||||
<xsl:text>,access-denied-handler,anonymous,session-management,concurrency-control,after-invocation-provider,authentication-provider,ldap-authentication-provider,user,port-mapping,openid-login,expression-handler,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,</xsl:text>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:template match="xs:element">
|
||||
|
|
|
@ -3,7 +3,7 @@ package org.springframework.security.config.http;
|
|||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
|
||||
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
|
||||
import static org.springframework.security.config.http.AuthenticationConfigBuilder.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
@ -101,8 +101,8 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
|
||||
@Test
|
||||
public void beanClassNamesAreCorrect() throws Exception {
|
||||
assertEquals(DefaultWebSecurityExpressionHandler.class.getName(), EXPRESSION_HANDLER_CLASS);
|
||||
assertEquals(ExpressionBasedFilterInvocationSecurityMetadataSource.class.getName(), EXPRESSION_FIMDS_CLASS);
|
||||
assertEquals(DefaultWebSecurityExpressionHandler.class.getName(), HttpSecurityBeanDefinitionParser.EXPRESSION_HANDLER_CLASS);
|
||||
assertEquals(ExpressionBasedFilterInvocationSecurityMetadataSource.class.getName(), HttpSecurityBeanDefinitionParser.EXPRESSION_FIMDS_CLASS);
|
||||
assertEquals(UsernamePasswordAuthenticationProcessingFilter.class.getName(), AUTHENTICATION_PROCESSING_FILTER_CLASS);
|
||||
assertEquals(OpenIDAuthenticationProcessingFilter.class.getName(), OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS);
|
||||
assertEquals(OpenIDAuthenticationProvider.class.getName(), OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
|
||||
|
@ -662,7 +662,9 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
public void concurrentSessionSupportAddsFilterAndExpectedBeans() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-alias='sr' expired-url='/expired'/>" +
|
||||
" <session-management>" +
|
||||
" <concurrency-control session-registry-alias='sr' expired-url='/expired'/>" +
|
||||
" </session-management>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
|
||||
|
@ -677,40 +679,15 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-ref='sr' />" +
|
||||
" <session-management>" +
|
||||
" <concurrency-control session-registry-ref='sr' />" +
|
||||
" </session-management>" +
|
||||
"</http>" +
|
||||
"<b:bean id='sr' class='" + SessionRegistryImpl.class.getName() + "'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
checkSessionRegistry();
|
||||
}
|
||||
|
||||
// @Test(expected=BeanDefinitionParsingException.class)
|
||||
// public void useOfExternalConcurrentSessionControllerRequiresSessionRegistryToBeSet() throws Exception {
|
||||
// setContext(
|
||||
// "<http auto-config='true'>" +
|
||||
// " <concurrent-session-control session-controller-ref='sc' expired-url='/expired'/>" +
|
||||
// "</http>" +
|
||||
// "<b:bean id='sc' class='" + ConcurrentSessionControllerImpl.class.getName() +"'>" +
|
||||
// " <b:property name='sessionRegistry'>" +
|
||||
// " <b:bean class='"+ SessionRegistryImpl.class.getName() + "'/>" +
|
||||
// " </b:property>" +
|
||||
// "</b:bean>" + AUTH_PROVIDER_XML);
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void useOfExternalSessionControllerAndRegistryIsWiredCorrectly() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true'>" +
|
||||
" <concurrent-session-control session-registry-ref='sr' session-controller-ref='sc' expired-url='/expired'/>" +
|
||||
"</http>" +
|
||||
"<b:bean id='sc' class='" + ConcurrentSessionControllerImpl.class.getName() +"'>" +
|
||||
" <b:property name='sessionRegistry' ref='sr'/>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='sr' class='"+ SessionRegistryImpl.class.getName() + "'/>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
checkSessionRegistry();
|
||||
}
|
||||
|
||||
private void checkSessionRegistry() throws Exception {
|
||||
Object sessionRegistry = appContext.getBean("sr");
|
||||
Object sessionRegistryFromConcurrencyFilter = FieldUtils.getFieldValue(
|
||||
|
@ -727,42 +704,14 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
// SEC-1143
|
||||
assertSame(sessionRegistry, sessionRegistryFromFormLoginFilter);
|
||||
}
|
||||
/*
|
||||
// These no longer apply with the internal authentication manager in <http> and it won't be possible to check the
|
||||
// Validity of the configuration against the central AuthenticationManager when we allow more than one <http> element.
|
||||
@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='" + ConcurrentSessionControllerImpl.class.getName() +"'>" +
|
||||
" <b:property name='sessionRegistry'>" +
|
||||
" <b:bean class='"+ SessionRegistryImpl.class.getName() + "'/>" +
|
||||
" </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.authentication.concurrent.ConcurrentSessionControllerImpl'>" +
|
||||
" <b:property name='sessionRegistry'>" +
|
||||
" <b:bean class='" + SessionRegistryImpl.class.getName() + "'/>" +
|
||||
" </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' />" +
|
||||
" <session-management>" +
|
||||
" <concurrency-control max-sessions='2' exception-if-maximum-exceeded='true' />" +
|
||||
" </session-management>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
SessionAuthenticationStrategy seshStrategy = (SessionAuthenticationStrategy) FieldUtils.getFieldValue(
|
||||
getFilter(SessionManagementFilter.class), "sessionStrategy");
|
||||
|
@ -830,7 +779,9 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
@Test
|
||||
public void disablingSessionProtectionRemovesSessionManagementFilterIfNoInvalidSessionUrlSet() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true' session-fixation-protection='none'/>" + AUTH_PROVIDER_XML);
|
||||
"<http auto-config='true'>" +
|
||||
" <session-management session-fixation-protection='none'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
assertFalse(filters.get(8) instanceof SessionManagementFilter);
|
||||
}
|
||||
|
@ -838,8 +789,9 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
@Test
|
||||
public void disablingSessionProtectionRetainsSessionManagementFilterInvalidSessionUrlSet() throws Exception {
|
||||
setContext(
|
||||
"<http auto-config='true' session-fixation-protection='none'" +
|
||||
" invalid-session-url='/timeoutUrl' />" + AUTH_PROVIDER_XML);
|
||||
"<http auto-config='true'>" +
|
||||
" <session-management session-fixation-protection='none' invalid-session-url='/timeoutUrl'/>" +
|
||||
"</http>" + AUTH_PROVIDER_XML);
|
||||
List<Filter> filters = getFilters("/someurl");
|
||||
Object filter = filters.get(8);
|
||||
assertTrue(filter instanceof SessionManagementFilter);
|
||||
|
|
|
@ -38,21 +38,12 @@
|
|||
|
||||
</http>
|
||||
|
||||
<!--
|
||||
Usernames/Passwords are
|
||||
rod/koala
|
||||
dianne/emu
|
||||
scott/wombat
|
||||
peter/opal
|
||||
-->
|
||||
<authentication-manager>
|
||||
<authentication-provider>
|
||||
<password-encoder hash="md5"/>
|
||||
<user-service>
|
||||
<user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
|
||||
<user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
|
||||
<user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
|
||||
<user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
|
||||
<user name="joe" password="password" authorities="ROLE_JANITOR" />
|
||||
<user name="jim" password="password" authorities="ROLE_TRADER" />
|
||||
<user name="jane" password="password" authorities="ROLE_SUPERVISOR" />
|
||||
</user-service>
|
||||
</authentication-provider>
|
||||
</authentication-manager>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Global logging configuration
|
||||
log4j.rootLogger=WARN, stdout
|
||||
log4j.rootLogger=DEBUG, stdout
|
||||
|
||||
log4j.logger.org.springframework.security=DEBUG
|
||||
|
||||
|
|
Loading…
Reference in New Issue