/* * 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; } } }