/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.http;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.w3c.dom.Element;
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.config.Elements;
import org.springframework.security.config.http.GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory;
import org.springframework.security.core.session.SessionRegistryImpl;
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.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy;
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.ATT_FILTERS;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.ATT_HTTP_METHOD;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.ATT_PATH_PATTERN;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.ATT_REQUIRES_CHANNEL;
import static org.springframework.security.config.http.SecurityFilters.CHANNEL_FILTER;
import static org.springframework.security.config.http.SecurityFilters.CONCURRENT_SESSION_FILTER;
import static org.springframework.security.config.http.SecurityFilters.CORS_FILTER;
import static org.springframework.security.config.http.SecurityFilters.CSRF_FILTER;
import static org.springframework.security.config.http.SecurityFilters.FILTER_SECURITY_INTERCEPTOR;
import static org.springframework.security.config.http.SecurityFilters.HEADERS_FILTER;
import static org.springframework.security.config.http.SecurityFilters.JAAS_API_SUPPORT_FILTER;
import static org.springframework.security.config.http.SecurityFilters.REQUEST_CACHE_FILTER;
import static org.springframework.security.config.http.SecurityFilters.SECURITY_CONTEXT_FILTER;
import static org.springframework.security.config.http.SecurityFilters.SERVLET_API_SUPPORT_FILTER;
import static org.springframework.security.config.http.SecurityFilters.SESSION_MANAGEMENT_FILTER;
import static org.springframework.security.config.http.SecurityFilters.WEB_ASYNC_MANAGER_FILTER;
/**
* Stateful class which helps HttpSecurityBDP to create the configuration for the
* <http> element.
*
* @author Luke Taylor
* @author Rob Winch
* @since 3.0
*/
class HttpConfigurationBuilder {
private static final String ATT_CREATE_SESSION = "create-session";
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 OPT_CHANGE_SESSION_ID = "changeSessionId";
private static final String ATT_INVALID_SESSION_URL = "invalid-session-url";
private static final String ATT_SESSION_AUTH_STRATEGY_REF = "session-authentication-strategy-ref";
private static final String ATT_SESSION_AUTH_ERROR_URL = "session-authentication-error-url";
private static final String ATT_SECURITY_CONTEXT_REPOSITORY = "security-context-repository-ref";
private static final String ATT_INVALID_SESSION_STRATEGY_REF = "invalid-session-strategy-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_ONCE_PER_REQUEST = "once-per-request";
private static final String ATT_REF = "ref";
private final Element httpElt;
private final ParserContext pc;
private final SessionCreationPolicy sessionPolicy;
private final List<Element> interceptUrls;
private final MatcherType matcherType;
private BeanDefinition cpf;
private BeanDefinition securityContextPersistenceFilter;
private BeanReference contextRepoRef;
private BeanReference sessionRegistryRef;
private BeanDefinition concurrentSessionFilter;
private BeanDefinition webAsyncManagerFilter;
private BeanDefinition requestCacheAwareFilter;
private BeanReference sessionStrategyRef;
private RootBeanDefinition sfpf;
private BeanDefinition servApiFilter;
private BeanDefinition jaasApiFilter;
private final BeanReference portMapper;
private final BeanReference portResolver;
private BeanReference fsi;
private BeanReference requestCache;
private BeanDefinition addHeadersFilter;
private BeanMetadataElement corsFilter;
private BeanDefinition csrfFilter;
private BeanMetadataElement csrfLogoutHandler;
private BeanMetadataElement csrfAuthStrategy;
private CsrfBeanDefinitionParser csrfParser;
private BeanDefinition invalidSession;
private boolean addAllAuth;
public HttpConfigurationBuilder(Element element, boolean addAllAuth,
ParserContext pc, BeanReference portMapper, BeanReference portResolver,
BeanReference authenticationManager) {
this.httpElt = element;
this.addAllAuth = addAllAuth;
this.pc = pc;
this.portMapper = portMapper;
this.portResolver = portResolver;
this.matcherType = MatcherType.fromElement(element);
interceptUrls = DomUtils.getChildElementsByTagName(element,
Elements.INTERCEPT_URL);
for (Element urlElt : interceptUrls) {
if (StringUtils.hasText(urlElt.getAttribute(ATT_FILTERS))) {
pc.getReaderContext()
.error("The use of \"filters='none'\" is no longer supported. Please define a"
+ " separate <http> element for the pattern you want to exclude and use the attribute"
+ " \"security='none'\".", pc.extractSource(urlElt));
}
}
String createSession = element.getAttribute(ATT_CREATE_SESSION);
if (StringUtils.hasText(createSession)) {
sessionPolicy = createPolicy(createSession);
}
else {
sessionPolicy = SessionCreationPolicy.IF_REQUIRED;
}
createCsrfFilter();
createSecurityContextPersistenceFilter();
createSessionManagementFilters();
createWebAsyncManagerFilter();
createRequestCacheFilter();
createServletApiFilter(authenticationManager);
createJaasApiFilter();
createChannelProcessingFilter();
createFilterSecurityInterceptor(authenticationManager);
createAddHeadersFilter();
createCorsFilter();
}
private SessionCreationPolicy createPolicy(String createSession) {
if ("ifRequired".equals(createSession)) {
return SessionCreationPolicy.IF_REQUIRED;
}
else if ("always".equals(createSession)) {
return SessionCreationPolicy.ALWAYS;
}
else if ("never".equals(createSession)) {
return SessionCreationPolicy.NEVER;
}
else if ("stateless".equals(createSession)) {
return SessionCreationPolicy.STATELESS;
}
throw new IllegalStateException("Cannot convert " + createSession + " to "
+ SessionCreationPolicy.class.getName());
}
@SuppressWarnings("rawtypes")
void setLogoutHandlers(ManagedList logoutHandlers) {
if (logoutHandlers != null) {
if (concurrentSessionFilter != null) {
concurrentSessionFilter.getPropertyValues().add("logoutHandlers",
logoutHandlers);
}
if (servApiFilter != null) {
servApiFilter.getPropertyValues().add("logoutHandlers", logoutHandlers);
}
}
}
void setEntryPoint(BeanMetadataElement entryPoint) {
if (servApiFilter != null) {
servApiFilter.getPropertyValues().add("authenticationEntryPoint", entryPoint);
}
}
void setAccessDeniedHandler(BeanMetadataElement accessDeniedHandler) {
if (csrfParser != null) {
csrfParser.initAccessDeniedHandler(this.invalidSession, accessDeniedHandler);
}
}
// Needed to account for placeholders
static String createPath(String path, boolean lowerCase) {
return lowerCase ? path.toLowerCase() : path;
}
private void createSecurityContextPersistenceFilter() {
BeanDefinitionBuilder scpf = BeanDefinitionBuilder
.rootBeanDefinition(SecurityContextPersistenceFilter.class);
String repoRef = httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
String disableUrlRewriting = httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
if(!StringUtils.hasText(disableUrlRewriting)) {
disableUrlRewriting = "true";
}
if (StringUtils.hasText(repoRef)) {
if (sessionPolicy == SessionCreationPolicy.ALWAYS) {
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
}
}
else {
BeanDefinitionBuilder contextRepo;
if (sessionPolicy == SessionCreationPolicy.STATELESS) {
contextRepo = BeanDefinitionBuilder
.rootBeanDefinition(NullSecurityContextRepository.class);
}
else {
contextRepo = BeanDefinitionBuilder
.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
switch (sessionPolicy) {
case ALWAYS:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
break;
case NEVER:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
break;
default:
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().generateBeanName(repoBean);
pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
}
contextRepoRef = new RuntimeBeanReference(repoRef);
scpf.addConstructorArgValue(contextRepoRef);
securityContextPersistenceFilter = scpf.getBeanDefinition();
}
private void createSessionManagementFilters() {
Element sessionMgmtElt = DomUtils.getChildElementByTagName(httpElt,
Elements.SESSION_MANAGEMENT);
Element sessionCtrlElt = null;
String sessionFixationAttribute = null;
String invalidSessionUrl = null;
String invalidSessionStrategyRef = null;
String sessionAuthStratRef = null;
String errorUrl = null;
boolean sessionControlEnabled = false;
if (sessionMgmtElt != null) {
if (sessionPolicy == SessionCreationPolicy.STATELESS) {
pc.getReaderContext().error(
Elements.SESSION_MANAGEMENT + " cannot be used"
+ " in combination with " + ATT_CREATE_SESSION + "='"
+ SessionCreationPolicy.STATELESS + "'",
pc.extractSource(sessionMgmtElt));
}
sessionFixationAttribute = sessionMgmtElt
.getAttribute(ATT_SESSION_FIXATION_PROTECTION);
invalidSessionUrl = sessionMgmtElt.getAttribute(ATT_INVALID_SESSION_URL);
invalidSessionStrategyRef = sessionMgmtElt.getAttribute(ATT_INVALID_SESSION_STRATEGY_REF);
sessionAuthStratRef = sessionMgmtElt
.getAttribute(ATT_SESSION_AUTH_STRATEGY_REF);
errorUrl = sessionMgmtElt.getAttribute(ATT_SESSION_AUTH_ERROR_URL);
sessionCtrlElt = DomUtils.getChildElementByTagName(sessionMgmtElt,
Elements.CONCURRENT_SESSIONS);
sessionControlEnabled = sessionCtrlElt != null;
if (StringUtils.hasText(invalidSessionUrl) && StringUtils.hasText(invalidSessionStrategyRef)) {
pc.getReaderContext().error(ATT_INVALID_SESSION_URL + " attribute cannot be used in combination with" +
" the " + ATT_INVALID_SESSION_STRATEGY_REF + " attribute.", sessionMgmtElt);
}
if (sessionControlEnabled) {
if (StringUtils.hasText(sessionAuthStratRef)) {
pc.getReaderContext().error(
ATT_SESSION_AUTH_STRATEGY_REF + " attribute cannot be used"
+ " in combination with <"
+ Elements.CONCURRENT_SESSIONS + ">",
pc.extractSource(sessionCtrlElt));
}
createConcurrencyControlFilterAndSessionRegistry(sessionCtrlElt);
}
}
if (!StringUtils.hasText(sessionFixationAttribute)) {
Method changeSessionIdMethod = ReflectionUtils.findMethod(
HttpServletRequest.class, "changeSessionId");
sessionFixationAttribute = changeSessionIdMethod == null ? OPT_SESSION_FIXATION_MIGRATE_SESSION
: OPT_CHANGE_SESSION_ID;
}
else if (StringUtils.hasText(sessionAuthStratRef)) {
pc.getReaderContext().error(
ATT_SESSION_FIXATION_PROTECTION + " attribute cannot be used"
+ " in combination with " + ATT_SESSION_AUTH_STRATEGY_REF,
pc.extractSource(sessionMgmtElt));
}
if (sessionPolicy == SessionCreationPolicy.STATELESS) {
// SEC-1424: do nothing
return;
}
boolean sessionFixationProtectionRequired = !sessionFixationAttribute
.equals(OPT_SESSION_FIXATION_NO_PROTECTION);
ManagedList<BeanMetadataElement> delegateSessionStrategies = new ManagedList<BeanMetadataElement>();
BeanDefinitionBuilder concurrentSessionStrategy;
BeanDefinitionBuilder sessionFixationStrategy = null;
BeanDefinitionBuilder registerSessionStrategy;
if (csrfAuthStrategy != null) {
delegateSessionStrategies.add(csrfAuthStrategy);
}
if (sessionControlEnabled) {
assert sessionRegistryRef != null;
concurrentSessionStrategy = BeanDefinitionBuilder
.rootBeanDefinition(ConcurrentSessionControlAuthenticationStrategy.class);
concurrentSessionStrategy.addConstructorArgValue(sessionRegistryRef);
String maxSessions = sessionCtrlElt.getAttribute("max-sessions");
if (StringUtils.hasText(maxSessions)) {
concurrentSessionStrategy
.addPropertyValue("maximumSessions", maxSessions);
}
String exceptionIfMaximumExceeded = sessionCtrlElt
.getAttribute("error-if-maximum-exceeded");
if (StringUtils.hasText(exceptionIfMaximumExceeded)) {
concurrentSessionStrategy.addPropertyValue("exceptionIfMaximumExceeded",
exceptionIfMaximumExceeded);
}
delegateSessionStrategies.add(concurrentSessionStrategy.getBeanDefinition());
}
boolean useChangeSessionId = OPT_CHANGE_SESSION_ID
.equals(sessionFixationAttribute);
if (sessionFixationProtectionRequired || StringUtils.hasText(invalidSessionUrl)) {
if (useChangeSessionId) {
sessionFixationStrategy = BeanDefinitionBuilder
.rootBeanDefinition(ChangeSessionIdAuthenticationStrategy.class);
}
else {
sessionFixationStrategy = BeanDefinitionBuilder
.rootBeanDefinition(SessionFixationProtectionStrategy.class);
}
delegateSessionStrategies.add(sessionFixationStrategy.getBeanDefinition());
}
if (StringUtils.hasText(sessionAuthStratRef)) {
delegateSessionStrategies.add(new RuntimeBeanReference(sessionAuthStratRef));
}
if (sessionControlEnabled) {
registerSessionStrategy = BeanDefinitionBuilder
.rootBeanDefinition(RegisterSessionAuthenticationStrategy.class);
registerSessionStrategy.addConstructorArgValue(sessionRegistryRef);
delegateSessionStrategies.add(registerSessionStrategy.getBeanDefinition());
}
if (delegateSessionStrategies.isEmpty()) {
sfpf = null;
return;
}
BeanDefinitionBuilder sessionMgmtFilter = BeanDefinitionBuilder
.rootBeanDefinition(SessionManagementFilter.class);
RootBeanDefinition failureHandler = new RootBeanDefinition(
SimpleUrlAuthenticationFailureHandler.class);
if (StringUtils.hasText(errorUrl)) {
failureHandler.getPropertyValues().addPropertyValue("defaultFailureUrl",
errorUrl);
}
sessionMgmtFilter
.addPropertyValue("authenticationFailureHandler", failureHandler);
sessionMgmtFilter.addConstructorArgValue(contextRepoRef);
if (!StringUtils.hasText(sessionAuthStratRef) && sessionFixationStrategy != null
&& !useChangeSessionId) {
if (sessionFixationProtectionRequired) {
sessionFixationStrategy.addPropertyValue("migrateSessionAttributes",
Boolean.valueOf(sessionFixationAttribute
.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
}
}
if (!delegateSessionStrategies.isEmpty()) {
BeanDefinitionBuilder sessionStrategy = BeanDefinitionBuilder
.rootBeanDefinition(CompositeSessionAuthenticationStrategy.class);
BeanDefinition strategyBean = sessionStrategy.getBeanDefinition();
sessionStrategy.addConstructorArgValue(delegateSessionStrategies);
sessionAuthStratRef = pc.getReaderContext().generateBeanName(strategyBean);
pc.registerBeanComponent(new BeanComponentDefinition(strategyBean,
sessionAuthStratRef));
}
if (StringUtils.hasText(invalidSessionUrl)) {
BeanDefinitionBuilder invalidSessionBldr = BeanDefinitionBuilder
.rootBeanDefinition(SimpleRedirectInvalidSessionStrategy.class);
invalidSessionBldr.addConstructorArgValue(invalidSessionUrl);
invalidSession = invalidSessionBldr.getBeanDefinition();
sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", invalidSession);
} else if (StringUtils.hasText(invalidSessionStrategyRef)) {
sessionMgmtFilter.addPropertyReference("invalidSessionStrategy", invalidSessionStrategyRef);
}
sessionMgmtFilter.addConstructorArgReference(sessionAuthStratRef);
sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition();
sessionStrategyRef = new RuntimeBeanReference(sessionAuthStratRef);
}
private void createConcurrencyControlFilterAndSessionRegistry(Element element) {
final String ATT_EXPIRY_URL = "expired-url";
final String ATT_EXPIRED_SESSION_STRATEGY_REF = "expired-session-strategy-ref";
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.addConstructorArgReference(sessionRegistryId);
Object source = pc.extractSource(element);
filterBuilder.getRawBeanDefinition().setSource(source);
filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String expiryUrl = element.getAttribute(ATT_EXPIRY_URL);
String expiredSessionStrategyRef = element.getAttribute(ATT_EXPIRED_SESSION_STRATEGY_REF);
if (StringUtils.hasText(expiryUrl) && StringUtils.hasText(expiredSessionStrategyRef)) {
pc.getReaderContext().error("Cannot use 'expired-url' attribute and 'expired-session-strategy-ref'" +
" attribute together.", source);
}
if (StringUtils.hasText(expiryUrl)) {
BeanDefinitionBuilder expiredSessionBldr = BeanDefinitionBuilder
.rootBeanDefinition(SimpleRedirectSessionInformationExpiredStrategy.class);
expiredSessionBldr.addConstructorArgValue(expiryUrl);
filterBuilder.addConstructorArgValue(expiredSessionBldr.getBeanDefinition());
} else if (StringUtils.hasText(expiredSessionStrategyRef)) {
filterBuilder.addConstructorArgReference(expiredSessionStrategyRef);
}
pc.popAndRegisterContainingComponent();
concurrentSessionFilter = filterBuilder.getBeanDefinition();
sessionRegistryRef = new RuntimeBeanReference(sessionRegistryId);
}
private void createWebAsyncManagerFilter() {
boolean asyncSupported = ClassUtils.hasMethod(ServletRequest.class, "startAsync");
if (asyncSupported) {
webAsyncManagerFilter = new RootBeanDefinition(
WebAsyncManagerIntegrationFilter.class);
}
}
// Adds the servlet-api integration filter if required
private void createServletApiFilter(BeanReference authenticationManager) {
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 = GrantedAuthorityDefaultsParserUtils.registerWithDefaultRolePrefix(pc, SecurityContextHolderAwareRequestFilterBeanFactory.class);
servApiFilter.getPropertyValues().add("authenticationManager",
authenticationManager);
}
}
// Adds the jaas-api integration filter if required
private void createJaasApiFilter() {
final String ATT_JAAS_API_PROVISION = "jaas-api-provision";
final String DEF_JAAS_API_PROVISION = "false";
String provideJaasApi = httpElt.getAttribute(ATT_JAAS_API_PROVISION);
if (!StringUtils.hasText(provideJaasApi)) {
provideJaasApi = DEF_JAAS_API_PROVISION;
}
if ("true".equals(provideJaasApi)) {
jaasApiFilter = new RootBeanDefinition(JaasApiIntegrationFilter.class);
}
}
private void createChannelProcessingFilter() {
ManagedMap<BeanMetadataElement, BeanDefinition> channelRequestMap = parseInterceptUrlsForChannelSecurity();
if (channelRequestMap.isEmpty()) {
return;
}
RootBeanDefinition channelFilter = new RootBeanDefinition(
ChannelProcessingFilter.class);
BeanDefinitionBuilder metadataSourceBldr = BeanDefinitionBuilder
.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
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);
retryWithHttp.getPropertyValues().addPropertyValue("portMapper", portMapper);
retryWithHttp.getPropertyValues().addPropertyValue("portResolver", portResolver);
retryWithHttps.getPropertyValues().addPropertyValue("portMapper", portMapper);
retryWithHttps.getPropertyValues().addPropertyValue("portResolver", portResolver);
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<BeanMetadataElement, BeanDefinition> parseInterceptUrlsForChannelSecurity() {
ManagedMap<BeanMetadataElement, BeanDefinition> channelRequestMap = new ManagedMap<BeanMetadataElement, BeanDefinition>();
for (Element urlElt : interceptUrls) {
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
String matcherRef = urlElt.getAttribute(ATT_REQUEST_MATCHER_REF);
boolean hasMatcherRef = StringUtils.hasText(matcherRef);
if (!hasMatcherRef && !StringUtils.hasText(path)) {
pc.getReaderContext().error("pattern attribute cannot be empty or null",
urlElt);
}
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
if (StringUtils.hasText(requiredChannel)) {
BeanMetadataElement matcher = hasMatcherRef ? new RuntimeBeanReference(matcherRef) : matcherType.createMatcher(pc, path, method);
RootBeanDefinition channelAttributes = new RootBeanDefinition(
ChannelAttributeFactory.class);
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(
requiredChannel);
channelAttributes.setFactoryMethodName("createChannelAttributes");
channelRequestMap.put(matcher, channelAttributes);
}
}
return channelRequestMap;
}
private void createRequestCacheFilter() {
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt,
Elements.REQUEST_CACHE);
if (requestCacheElt != null) {
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
}
else {
BeanDefinitionBuilder requestCacheBldr;
if (sessionPolicy == SessionCreationPolicy.STATELESS) {
requestCacheBldr = BeanDefinitionBuilder
.rootBeanDefinition(NullRequestCache.class);
}
else {
requestCacheBldr = BeanDefinitionBuilder
.rootBeanDefinition(HttpSessionRequestCache.class);
requestCacheBldr.addPropertyValue("createSessionAllowed",
sessionPolicy == SessionCreationPolicy.IF_REQUIRED);
requestCacheBldr.addPropertyValue("portResolver", portResolver);
if (csrfFilter != null) {
BeanDefinitionBuilder requestCacheMatcherBldr = BeanDefinitionBuilder
.rootBeanDefinition(AntPathRequestMatcher.class);
requestCacheMatcherBldr.addConstructorArgValue("/**");
requestCacheMatcherBldr.addConstructorArgValue("GET");
requestCacheBldr.addPropertyValue("requestMatcher",
requestCacheMatcherBldr.getBeanDefinition());
}
}
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
String id = pc.getReaderContext().generateBeanName(bean);
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
this.requestCache = new RuntimeBeanReference(id);
}
requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
requestCacheAwareFilter.getConstructorArgumentValues().addGenericArgumentValue(
requestCache);
}
private void createFilterSecurityInterceptor(BeanReference authManager) {
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser
.isUseExpressions(httpElt);
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser
.createSecurityMetadataSource(interceptUrls, addAllAuth, httpElt, pc);
RootBeanDefinition accessDecisionMgr;
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
if (useExpressions) {
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder
.rootBeanDefinition(WebExpressionVoter.class);
// Read the expression handler from the FISMS
RuntimeBeanReference expressionHandler = (RuntimeBeanReference) securityMds
.getConstructorArgumentValues()
.getArgumentValue(1, RuntimeBeanReference.class).getValue();
expressionVoter.addPropertyValue("expressionHandler", expressionHandler);
voters.add(expressionVoter.getBeanDefinition());
}
else {
voters.add(GrantedAuthorityDefaultsParserUtils.registerWithDefaultRolePrefix(pc, RoleVoterBeanFactory.class));
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
}
accessDecisionMgr = new RootBeanDefinition(AffirmativeBased.class);
accessDecisionMgr.getConstructorArgumentValues().addGenericArgumentValue(voters);
accessDecisionMgr.setSource(pc.extractSource(httpElt));
// Set up the access manager reference for http
String accessManagerId = httpElt.getAttribute(ATT_ACCESS_MGR);
if (!StringUtils.hasText(accessManagerId)) {
accessManagerId = pc.getReaderContext().generateBeanName(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", securityMds);
BeanDefinition fsiBean = builder.getBeanDefinition();
String fsiId = pc.getReaderContext().generateBeanName(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));
pc.registerBeanComponent(new BeanComponentDefinition(wipe, pc.getReaderContext()
.generateBeanName(wipe)));
this.fsi = new RuntimeBeanReference(fsiId);
}
private void createAddHeadersFilter() {
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.HEADERS);
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
}
private void createCorsFilter() {
Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.CORS);
this.corsFilter = new CorsBeanDefinitionParser().parse(elmt, this.pc);
}
private void createCsrfFilter() {
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.CSRF);
csrfParser = new CsrfBeanDefinitionParser();
csrfFilter = csrfParser.parse(elmt, pc);
if (csrfFilter == null) {
csrfParser = null;
return;
}
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
}
BeanMetadataElement getCsrfLogoutHandler() {
return this.csrfLogoutHandler;
}
BeanReference getSessionStrategy() {
return sessionStrategyRef;
}
SessionCreationPolicy getSessionCreationPolicy() {
return sessionPolicy;
}
BeanReference getRequestCache() {
return requestCache;
}
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));
}
if (webAsyncManagerFilter != null) {
filters.add(new OrderDecorator(webAsyncManagerFilter,
WEB_ASYNC_MANAGER_FILTER));
}
filters.add(new OrderDecorator(securityContextPersistenceFilter,
SECURITY_CONTEXT_FILTER));
if (servApiFilter != null) {
filters.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER));
}
if (jaasApiFilter != null) {
filters.add(new OrderDecorator(jaasApiFilter, JAAS_API_SUPPORT_FILTER));
}
if (sfpf != null) {
filters.add(new OrderDecorator(sfpf, SESSION_MANAGEMENT_FILTER));
}
filters.add(new OrderDecorator(fsi, FILTER_SECURITY_INTERCEPTOR));
if (sessionPolicy != SessionCreationPolicy.STATELESS) {
filters.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
}
if (this.corsFilter != null) {
filters.add(new OrderDecorator(this.corsFilter, CORS_FILTER));
}
if (addHeadersFilter != null) {
filters.add(new OrderDecorator(addHeadersFilter, HEADERS_FILTER));
}
if (csrfFilter != null) {
filters.add(new OrderDecorator(csrfFilter, CSRF_FILTER));
}
return filters;
}
static class RoleVoterBeanFactory extends AbstractGrantedAuthorityDefaultsBeanFactory {
private RoleVoter voter = new RoleVoter();
public RoleVoter getBean() {
voter.setRolePrefix(this.rolePrefix);
return voter;
}
}
static class SecurityContextHolderAwareRequestFilterBeanFactory extends GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory {
private SecurityContextHolderAwareRequestFilter filter = new SecurityContextHolderAwareRequestFilter();
public SecurityContextHolderAwareRequestFilter getBean() {
filter.setRolePrefix(this.rolePrefix);
return filter;
}
}
}