spring security HttpConfigurationBuilder 源码

  • 2022-08-13
  • 浏览 (222)

spring security HttpConfigurationBuilder 代码

文件路径:/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

/*
 * Copyright 2002-2022 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
 *
 *      https://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.util.ArrayList;
import java.util.List;

import jakarta.servlet.ServletRequest;
import org.w3c.dom.Element;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.FactoryBean;
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.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
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.SecurityContextHolderFilter;
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.DisableEncodeUrlFilter;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
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.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;

/**
 * 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_HOLDER_STRATEGY = "security-context-holder-strategy-ref";

	private static final String ATT_SECURITY_CONTEXT_REPOSITORY = "security-context-repository-ref";

	private static final String ATT_SECURITY_CONTEXT_EXPLICIT_SAVE = "security-context-explicit-save";

	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_USE_AUTHORIZATION_MGR = "use-authorization-manager";

	private static final String ATT_AUTHORIZATION_MGR = "authorization-manager-ref";

	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 static final String ATT_EXPIRY_URL = "expired-url";

	private static final String ATT_EXPIRED_SESSION_STRATEGY_REF = "expired-session-strategy-ref";

	private static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";

	private static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";

	private static final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";

	private static final String DEF_SERVLET_API_PROVISION = "true";

	private static final String ATT_JAAS_API_PROVISION = "jaas-api-provision";

	private static final String DEF_JAAS_API_PROVISION = "false";

	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 BeanDefinition forceEagerSessionCreationFilter;

	private BeanMetadataElement holderStrategyRef;

	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 BeanDefinition disableUrlRewriteFilter;

	private BeanDefinition wellKnownChangePasswordRedirectFilter;

	private BeanMetadataElement csrfLogoutHandler;

	private BeanMetadataElement csrfAuthStrategy;

	private CsrfBeanDefinitionParser csrfParser;

	private BeanDefinition invalidSession;

	private boolean addAllAuth;

	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);
		this.interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
		validateInterceptUrls(pc);
		String createSession = element.getAttribute(ATT_CREATE_SESSION);
		this.sessionPolicy = !StringUtils.hasText(createSession) ? SessionCreationPolicy.IF_REQUIRED
				: createPolicy(createSession);
		createSecurityContextHolderStrategy();
		createForceEagerSessionCreationFilter();
		createDisableEncodeUrlFilter();
		createCsrfFilter();
		createSecurityPersistence();
		createSessionManagementFilters();
		createWebAsyncManagerFilter();
		createRequestCacheFilter();
		createServletApiFilter(authenticationManager);
		createJaasApiFilter();
		createChannelProcessingFilter();
		createFilterSecurity(authenticationManager);
		createAddHeadersFilter();
		createCorsFilter();
		createWellKnownChangePasswordRedirectFilter();
	}

	private void validateInterceptUrls(ParserContext pc) {
		for (Element element : this.interceptUrls) {
			if (StringUtils.hasText(element.getAttribute(HttpSecurityBeanDefinitionParser.ATT_FILTERS))) {
				String message = "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.getReaderContext().error(message, pc.extractSource(element));
			}
		}
	}

	private SessionCreationPolicy createPolicy(String createSession) {
		if ("ifRequired".equals(createSession)) {
			return SessionCreationPolicy.IF_REQUIRED;
		}
		if ("always".equals(createSession)) {
			return SessionCreationPolicy.ALWAYS;
		}
		if ("never".equals(createSession)) {
			return SessionCreationPolicy.NEVER;
		}
		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 (this.concurrentSessionFilter != null) {
				this.concurrentSessionFilter.getPropertyValues().add("logoutHandlers", logoutHandlers);
			}
			if (this.servApiFilter != null) {
				this.servApiFilter.getPropertyValues().add("logoutHandlers", logoutHandlers);
			}
		}
	}

	void setEntryPoint(BeanMetadataElement entryPoint) {
		if (this.servApiFilter != null) {
			this.servApiFilter.getPropertyValues().add("authenticationEntryPoint", entryPoint);
		}
	}

	void setAccessDeniedHandler(BeanMetadataElement accessDeniedHandler) {
		if (this.csrfParser != null) {
			this.csrfParser.initAccessDeniedHandler(this.invalidSession, accessDeniedHandler);
		}
	}

	void setCsrfIgnoreRequestMatchers(List<BeanDefinition> requestMatchers) {
		if (this.csrfParser != null) {
			this.csrfParser.setIgnoreCsrfRequestMatchers(requestMatchers);
		}
	}

	// Needed to account for placeholders
	static String createPath(String path, boolean lowerCase) {
		return lowerCase ? path.toLowerCase() : path;
	}

	BeanMetadataElement getSecurityContextHolderStrategyForAuthenticationFilters() {
		return this.holderStrategyRef;
	}

	BeanReference getSecurityContextRepositoryForAuthenticationFilters() {
		return (isExplicitSave()) ? this.contextRepoRef : null;
	}

	private void createSecurityPersistence() {
		createSecurityContextRepository();
		if (isExplicitSave()) {
			createSecurityContextHolderFilter();
		}
		else {
			createSecurityContextPersistenceFilter();
		}
	}

	private boolean isExplicitSave() {
		String explicitSaveAttr = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_EXPLICIT_SAVE);
		return Boolean.parseBoolean(explicitSaveAttr);
	}

	private void createForceEagerSessionCreationFilter() {
		if (this.sessionPolicy == SessionCreationPolicy.ALWAYS) {
			this.forceEagerSessionCreationFilter = new RootBeanDefinition(ForceEagerSessionCreationFilter.class);
		}
	}

	private void createSecurityContextPersistenceFilter() {
		BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
		switch (this.sessionPolicy) {
		case ALWAYS:
			scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
			break;
		case NEVER:
			scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
			break;
		default:
			scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
		}
		scpf.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
		scpf.addConstructorArgValue(this.contextRepoRef);

		this.securityContextPersistenceFilter = scpf.getBeanDefinition();
	}

	private void createSecurityContextHolderStrategy() {
		String holderStrategyRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_HOLDER_STRATEGY);
		if (StringUtils.hasText(holderStrategyRef)) {
			this.holderStrategyRef = new RuntimeBeanReference(holderStrategyRef);
			return;
		}
		this.holderStrategyRef = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderStrategyFactory.class)
				.getBeanDefinition();
	}

	private void createSecurityContextRepository() {
		String repoRef = this.httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
		if (!StringUtils.hasText(repoRef)) {
			BeanDefinitionBuilder contextRepo;
			if (this.sessionPolicy == SessionCreationPolicy.STATELESS) {
				contextRepo = BeanDefinitionBuilder.rootBeanDefinition(NullSecurityContextRepository.class);
			}
			else {
				contextRepo = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
				switch (this.sessionPolicy) {
				case ALWAYS:
					contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
					break;
				case NEVER:
					contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
					break;
				default:
					contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
				}
				if (isDisableUrlRewriting()) {
					contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
				}
			}
			contextRepo.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
			BeanDefinition repoBean = contextRepo.getBeanDefinition();
			repoRef = this.pc.getReaderContext().generateBeanName(repoBean);
			this.pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
		}

		this.contextRepoRef = new RuntimeBeanReference(repoRef);
	}

	private boolean isDisableUrlRewriting() {
		String disableUrlRewriting = this.httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
		return !"false".equals(disableUrlRewriting);
	}

	private void createSecurityContextHolderFilter() {
		BeanDefinitionBuilder filter = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderFilter.class);
		filter.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
		filter.addConstructorArgValue(this.contextRepoRef);
		this.securityContextPersistenceFilter = filter.getBeanDefinition();
	}

	private void createSessionManagementFilters() {
		Element sessionMgmtElt = DomUtils.getChildElementByTagName(this.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 (this.sessionPolicy == SessionCreationPolicy.STATELESS) {
				this.pc.getReaderContext()
						.error(Elements.SESSION_MANAGEMENT + "  cannot be used" + " in combination with "
								+ ATT_CREATE_SESSION + "='" + SessionCreationPolicy.STATELESS + "'",
								this.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)) {
				this.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)) {
					this.pc.getReaderContext()
							.error(ATT_SESSION_AUTH_STRATEGY_REF + " attribute cannot be used"
									+ " in combination with <" + Elements.CONCURRENT_SESSIONS + ">",
									this.pc.extractSource(sessionCtrlElt));
				}
				createConcurrencyControlFilterAndSessionRegistry(sessionCtrlElt);
			}
		}

		if (!StringUtils.hasText(sessionFixationAttribute)) {
			sessionFixationAttribute = OPT_CHANGE_SESSION_ID;
		}
		else if (StringUtils.hasText(sessionAuthStratRef)) {
			this.pc.getReaderContext().error(ATT_SESSION_FIXATION_PROTECTION + " attribute cannot be used"
					+ " in combination with " + ATT_SESSION_AUTH_STRATEGY_REF, this.pc.extractSource(sessionMgmtElt));
		}

		if (this.sessionPolicy == SessionCreationPolicy.STATELESS) {
			// SEC-1424: do nothing
			return;
		}
		boolean sessionFixationProtectionRequired = !sessionFixationAttribute
				.equals(OPT_SESSION_FIXATION_NO_PROTECTION);
		ManagedList<BeanMetadataElement> delegateSessionStrategies = new ManagedList<>();
		BeanDefinitionBuilder concurrentSessionStrategy;
		BeanDefinitionBuilder sessionFixationStrategy = null;
		BeanDefinitionBuilder registerSessionStrategy;
		if (this.csrfAuthStrategy != null) {
			delegateSessionStrategies.add(this.csrfAuthStrategy);
		}
		if (sessionControlEnabled) {
			Assert.state(this.sessionRegistryRef != null, "No sessionRegistryRef found");
			concurrentSessionStrategy = BeanDefinitionBuilder
					.rootBeanDefinition(ConcurrentSessionControlAuthenticationStrategy.class);
			concurrentSessionStrategy.addConstructorArgValue(this.sessionRegistryRef);
			String maxSessions = this.pc.getReaderContext().getEnvironment()
					.resolvePlaceholders(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(this.sessionRegistryRef);
			delegateSessionStrategies.add(registerSessionStrategy.getBeanDefinition());
		}
		if (delegateSessionStrategies.isEmpty()) {
			this.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("securityContextHolderStrategy", this.holderStrategyRef);
		sessionMgmtFilter.addPropertyValue("authenticationFailureHandler", failureHandler);
		sessionMgmtFilter.addConstructorArgValue(this.contextRepoRef);
		if (!StringUtils.hasText(sessionAuthStratRef) && sessionFixationStrategy != null && !useChangeSessionId) {
			if (sessionFixationProtectionRequired) {
				sessionFixationStrategy.addPropertyValue("migrateSessionAttributes",
						sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION));
			}
		}
		if (!delegateSessionStrategies.isEmpty()) {
			BeanDefinitionBuilder sessionStrategy = BeanDefinitionBuilder
					.rootBeanDefinition(CompositeSessionAuthenticationStrategy.class);
			BeanDefinition strategyBean = sessionStrategy.getBeanDefinition();
			sessionStrategy.addConstructorArgValue(delegateSessionStrategies);
			sessionAuthStratRef = this.pc.getReaderContext().generateBeanName(strategyBean);
			this.pc.registerBeanComponent(new BeanComponentDefinition(strategyBean, sessionAuthStratRef));
		}
		if (StringUtils.hasText(invalidSessionUrl)) {
			BeanDefinitionBuilder invalidSessionBldr = BeanDefinitionBuilder
					.rootBeanDefinition(SimpleRedirectInvalidSessionStrategy.class);
			invalidSessionBldr.addConstructorArgValue(invalidSessionUrl);
			this.invalidSession = invalidSessionBldr.getBeanDefinition();
			sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", this.invalidSession);
		}
		else if (StringUtils.hasText(invalidSessionStrategyRef)) {
			sessionMgmtFilter.addPropertyReference("invalidSessionStrategy", invalidSessionStrategyRef);
		}
		sessionMgmtFilter.addConstructorArgReference(sessionAuthStratRef);
		this.sfpf = (RootBeanDefinition) sessionMgmtFilter.getBeanDefinition();
		this.sessionStrategyRef = new RuntimeBeanReference(sessionAuthStratRef);
	}

	private void createConcurrencyControlFilterAndSessionRegistry(Element element) {
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
				this.pc.extractSource(element));
		this.pc.pushContainingComponent(compositeDef);
		BeanDefinitionRegistry beanRegistry = this.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 = this.pc.getReaderContext().registerWithGeneratedName(sessionRegistry);
			this.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 = this.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)) {
			this.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);
		}
		this.pc.popAndRegisterContainingComponent();
		this.concurrentSessionFilter = filterBuilder.getBeanDefinition();
		this.sessionRegistryRef = new RuntimeBeanReference(sessionRegistryId);
	}

	private void createWebAsyncManagerFilter() {
		boolean asyncSupported = ClassUtils.hasMethod(ServletRequest.class, "startAsync");
		if (asyncSupported) {
			this.webAsyncManagerFilter = new RootBeanDefinition(WebAsyncManagerIntegrationFilter.class);
			this.webAsyncManagerFilter.getPropertyValues().add("securityContextHolderStrategy", this.holderStrategyRef);
		}
	}

	// Adds the servlet-api integration filter if required
	private void createServletApiFilter(BeanReference authenticationManager) {
		String provideServletApi = this.httpElt.getAttribute(ATT_SERVLET_API_PROVISION);
		if (!StringUtils.hasText(provideServletApi)) {
			provideServletApi = DEF_SERVLET_API_PROVISION;
		}
		if ("true".equals(provideServletApi)) {
			this.servApiFilter = GrantedAuthorityDefaultsParserUtils.registerWithDefaultRolePrefix(this.pc,
					SecurityContextHolderAwareRequestFilterBeanFactory.class);
			this.servApiFilter.getPropertyValues().add("authenticationManager", authenticationManager);
			this.servApiFilter.getPropertyValues().add("securityContextHolderStrategy", this.holderStrategyRef);
		}
	}

	// Adds the jaas-api integration filter if required
	private void createJaasApiFilter() {
		String provideJaasApi = this.httpElt.getAttribute(ATT_JAAS_API_PROVISION);
		if (!StringUtils.hasText(provideJaasApi)) {
			provideJaasApi = DEF_JAAS_API_PROVISION;
		}
		if ("true".equals(provideJaasApi)) {
			this.jaasApiFilter = BeanDefinitionBuilder.rootBeanDefinition(JaasApiIntegrationFilter.class)
					.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef).getBeanDefinition();
		}
	}

	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);
		channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource",
				metadataSourceBldr.getBeanDefinition());
		RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
		ManagedList<RootBeanDefinition> channelProcessors = new ManagedList<>(3);
		RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);
		RootBeanDefinition retryWithHttp = new RootBeanDefinition(RetryWithHttpEntryPoint.class);
		RootBeanDefinition retryWithHttps = new RootBeanDefinition(RetryWithHttpsEntryPoint.class);
		retryWithHttp.getPropertyValues().addPropertyValue("portMapper", this.portMapper);
		retryWithHttp.getPropertyValues().addPropertyValue("portResolver", this.portResolver);
		retryWithHttps.getPropertyValues().addPropertyValue("portMapper", this.portMapper);
		retryWithHttps.getPropertyValues().addPropertyValue("portResolver", this.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 = this.pc.getReaderContext().registerWithGeneratedName(channelDecisionManager);
		channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager", new RuntimeBeanReference(id));
		this.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<>();
		for (Element urlElt : this.interceptUrls) {
			String path = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_PATTERN);
			String method = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_HTTP_METHOD);
			String matcherRef = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUEST_MATCHER_REF);
			boolean hasMatcherRef = StringUtils.hasText(matcherRef);
			if (!hasMatcherRef && !StringUtils.hasText(path)) {
				this.pc.getReaderContext().error("pattern attribute cannot be empty or null", urlElt);
			}
			String requiredChannel = urlElt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REQUIRES_CHANNEL);
			if (StringUtils.hasText(requiredChannel)) {
				BeanMetadataElement matcher = hasMatcherRef ? new RuntimeBeanReference(matcherRef)
						: this.matcherType.createMatcher(this.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(this.httpElt, Elements.REQUEST_CACHE);
		if (requestCacheElt != null) {
			this.requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
		}
		else {
			BeanDefinitionBuilder requestCacheBldr;
			if (this.sessionPolicy == SessionCreationPolicy.STATELESS) {
				requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class);
			}
			else {
				requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
				requestCacheBldr.addPropertyValue("createSessionAllowed",
						this.sessionPolicy == SessionCreationPolicy.IF_REQUIRED);
				requestCacheBldr.addPropertyValue("portResolver", this.portResolver);
				if (this.csrfFilter != null) {
					BeanDefinitionBuilder requestCacheMatcherBldr = BeanDefinitionBuilder
							.rootBeanDefinition(AntPathRequestMatcher.class);
					requestCacheMatcherBldr.addConstructorArgValue("/**");
					requestCacheMatcherBldr.addConstructorArgValue("GET");
					requestCacheBldr.addPropertyValue("requestMatcher", requestCacheMatcherBldr.getBeanDefinition());
				}
			}
			BeanDefinition bean = requestCacheBldr.getBeanDefinition();
			String id = this.pc.getReaderContext().generateBeanName(bean);
			this.pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
			this.requestCache = new RuntimeBeanReference(id);
		}
		this.requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
		this.requestCacheAwareFilter.getConstructorArgumentValues().addGenericArgumentValue(this.requestCache);
	}

	private void createFilterSecurity(BeanReference authManager) {
		boolean useAuthorizationManager = Boolean.parseBoolean(this.httpElt.getAttribute(ATT_USE_AUTHORIZATION_MGR));
		if (useAuthorizationManager) {
			createAuthorizationFilter();
			return;
		}
		if (StringUtils.hasText(this.httpElt.getAttribute(ATT_AUTHORIZATION_MGR))) {
			createAuthorizationFilter();
			return;
		}
		createFilterSecurityInterceptor(authManager);
	}

	private void createAuthorizationFilter() {
		AuthorizationFilterParser authorizationFilterParser = new AuthorizationFilterParser();
		BeanDefinition fsiBean = authorizationFilterParser.parse(this.httpElt, this.pc);
		String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean);
		this.pc.registerBeanComponent(new BeanComponentDefinition(fsiBean, fsiId));
		// Create and register a AuthorizationManagerWebInvocationPrivilegeEvaluator for
		// use with
		// taglibs etc.
		BeanDefinition wipe = BeanDefinitionBuilder
				.rootBeanDefinition(AuthorizationManagerWebInvocationPrivilegeEvaluator.class)
				.addConstructorArgReference(authorizationFilterParser.getAuthorizationManagerRef()).getBeanDefinition();
		this.pc.registerBeanComponent(
				new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
		this.fsi = new RuntimeBeanReference(fsiId);
	}

	private void createFilterSecurityInterceptor(BeanReference authManager) {
		boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(this.httpElt);
		RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser
				.createSecurityMetadataSource(this.interceptUrls, this.addAllAuth, this.httpElt, this.pc);
		RootBeanDefinition accessDecisionMgr;
		ManagedList<BeanDefinition> voters = new ManagedList<>(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(this.pc,
					RoleVoterBeanFactory.class));
			voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
		}
		accessDecisionMgr = new RootBeanDefinition(AffirmativeBased.class);
		accessDecisionMgr.getConstructorArgumentValues().addGenericArgumentValue(voters);
		accessDecisionMgr.setSource(this.pc.extractSource(this.httpElt));
		// Set up the access manager reference for http
		String accessManagerId = this.httpElt.getAttribute(ATT_ACCESS_MGR);
		if (!StringUtils.hasText(accessManagerId)) {
			accessManagerId = this.pc.getReaderContext().generateBeanName(accessDecisionMgr);
			this.pc.registerBeanComponent(new BeanComponentDefinition(accessDecisionMgr, accessManagerId));
		}
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
		builder.addPropertyReference("accessDecisionManager", accessManagerId);
		builder.addPropertyValue("authenticationManager", authManager);
		if ("false".equals(this.httpElt.getAttribute(ATT_ONCE_PER_REQUEST))) {
			builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
		}
		builder.addPropertyValue("securityMetadataSource", securityMds);
		builder.addPropertyValue("securityContextHolderStrategy", this.holderStrategyRef);
		BeanDefinition fsiBean = builder.getBeanDefinition();
		String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean);
		this.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));
		this.pc.registerBeanComponent(
				new BeanComponentDefinition(wipe, this.pc.getReaderContext().generateBeanName(wipe)));
		this.fsi = new RuntimeBeanReference(fsiId);
	}

	private void createAddHeadersFilter() {
		Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.HEADERS);
		this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, this.pc);
	}

	private void createCorsFilter() {
		Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.CORS);
		this.corsFilter = new CorsBeanDefinitionParser().parse(elmt, this.pc);

	}

	private void createDisableEncodeUrlFilter() {
		if (isDisableUrlRewriting()) {
			this.disableUrlRewriteFilter = new RootBeanDefinition(DisableEncodeUrlFilter.class);
		}
	}

	private void createCsrfFilter() {
		Element elmt = DomUtils.getChildElementByTagName(this.httpElt, Elements.CSRF);
		this.csrfParser = new CsrfBeanDefinitionParser();
		this.csrfFilter = this.csrfParser.parse(elmt, this.pc);
		if (this.csrfFilter == null) {
			this.csrfParser = null;
			return;
		}
		this.csrfAuthStrategy = this.csrfParser.getCsrfAuthenticationStrategy();
		this.csrfLogoutHandler = this.csrfParser.getCsrfLogoutHandler();
	}

	private void createWellKnownChangePasswordRedirectFilter() {
		Element element = DomUtils.getChildElementByTagName(this.httpElt, Elements.PASSWORD_MANAGEMENT);
		if (element == null) {
			return;
		}
		WellKnownChangePasswordBeanDefinitionParser parser = new WellKnownChangePasswordBeanDefinitionParser();
		this.wellKnownChangePasswordRedirectFilter = parser.parse(element, this.pc);
	}

	BeanMetadataElement getCsrfLogoutHandler() {
		return this.csrfLogoutHandler;
	}

	BeanReference getSessionStrategy() {
		return this.sessionStrategyRef;
	}

	SessionCreationPolicy getSessionCreationPolicy() {
		return this.sessionPolicy;
	}

	BeanReference getRequestCache() {
		return this.requestCache;
	}

	List<OrderDecorator> getFilters() {
		List<OrderDecorator> filters = new ArrayList<>();
		if (this.forceEagerSessionCreationFilter != null) {
			filters.add(new OrderDecorator(this.forceEagerSessionCreationFilter,
					SecurityFilters.FORCE_EAGER_SESSION_FILTER));
		}
		if (this.disableUrlRewriteFilter != null) {
			filters.add(new OrderDecorator(this.disableUrlRewriteFilter, SecurityFilters.DISABLE_ENCODE_URL_FILTER));
		}
		if (this.cpf != null) {
			filters.add(new OrderDecorator(this.cpf, SecurityFilters.CHANNEL_FILTER));
		}
		if (this.concurrentSessionFilter != null) {
			filters.add(new OrderDecorator(this.concurrentSessionFilter, SecurityFilters.CONCURRENT_SESSION_FILTER));
		}
		if (this.webAsyncManagerFilter != null) {
			filters.add(new OrderDecorator(this.webAsyncManagerFilter, SecurityFilters.WEB_ASYNC_MANAGER_FILTER));
		}
		filters.add(new OrderDecorator(this.securityContextPersistenceFilter, SecurityFilters.SECURITY_CONTEXT_FILTER));
		if (this.servApiFilter != null) {
			filters.add(new OrderDecorator(this.servApiFilter, SecurityFilters.SERVLET_API_SUPPORT_FILTER));
		}
		if (this.jaasApiFilter != null) {
			filters.add(new OrderDecorator(this.jaasApiFilter, SecurityFilters.JAAS_API_SUPPORT_FILTER));
		}
		if (this.sfpf != null) {
			filters.add(new OrderDecorator(this.sfpf, SecurityFilters.SESSION_MANAGEMENT_FILTER));
		}
		filters.add(new OrderDecorator(this.fsi, SecurityFilters.FILTER_SECURITY_INTERCEPTOR));
		if (this.sessionPolicy != SessionCreationPolicy.STATELESS) {
			filters.add(new OrderDecorator(this.requestCacheAwareFilter, SecurityFilters.REQUEST_CACHE_FILTER));
		}
		if (this.corsFilter != null) {
			filters.add(new OrderDecorator(this.corsFilter, SecurityFilters.CORS_FILTER));
		}
		if (this.addHeadersFilter != null) {
			filters.add(new OrderDecorator(this.addHeadersFilter, SecurityFilters.HEADERS_FILTER));
		}
		if (this.csrfFilter != null) {
			filters.add(new OrderDecorator(this.csrfFilter, SecurityFilters.CSRF_FILTER));
		}
		if (this.wellKnownChangePasswordRedirectFilter != null) {
			filters.add(new OrderDecorator(this.wellKnownChangePasswordRedirectFilter,
					SecurityFilters.WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER));
		}
		return filters;
	}

	static class RoleVoterBeanFactory extends AbstractGrantedAuthorityDefaultsBeanFactory {

		private RoleVoter voter = new RoleVoter();

		@Override
		public RoleVoter getBean() {
			this.voter.setRolePrefix(this.rolePrefix);
			return this.voter;
		}

	}

	static class SecurityContextHolderAwareRequestFilterBeanFactory
			extends GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory {

		private SecurityContextHolderAwareRequestFilter filter = new SecurityContextHolderAwareRequestFilter();

		private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
				.getContextHolderStrategy();

		@Override
		public SecurityContextHolderAwareRequestFilter getBean() {
			this.filter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
			this.filter.setRolePrefix(this.rolePrefix);
			return this.filter;
		}

		void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
			this.securityContextHolderStrategy = securityContextHolderStrategy;
		}

	}

	static class SecurityContextHolderStrategyFactory implements FactoryBean<SecurityContextHolderStrategy> {

		@Override
		public SecurityContextHolderStrategy getObject() throws Exception {
			return SecurityContextHolder.getContextHolderStrategy();
		}

		@Override
		public Class<?> getObjectType() {
			return SecurityContextHolderStrategy.class;
		}

	}

}

相关信息

spring security 源码目录

相关文章

spring security AuthenticationConfigBuilder 源码

spring security AuthorizationFilterParser 源码

spring security ChannelAttributeFactory 源码

spring security CorsBeanDefinitionParser 源码

spring security CsrfBeanDefinitionParser 源码

spring security DefaultFilterChainValidator 源码

spring security FilterChainBeanDefinitionParser 源码

spring security FilterChainMapBeanDefinitionDecorator 源码

spring security FilterInvocationSecurityMetadataSourceParser 源码

spring security FormLoginBeanDefinitionParser 源码

0  赞