/* * Copyright 2002-2015 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 org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.security.web.authentication.*; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.util.StringUtils; import org.w3c.dom.Element; /** * @author Luke Taylor * @author Ben Alex * @author Rob Winch * @author Kazuki Shimizu * @author Shazin Sadakath */ public class FormLoginBeanDefinitionParser { protected final Log logger = LogFactory.getLog(getClass()); private static final String ATT_LOGIN_URL = "login-processing-url"; static final String ATT_LOGIN_PAGE = "login-page"; private static final String DEF_LOGIN_PAGE = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL; private static final String ATT_FORM_LOGIN_TARGET_URL = "default-target-url"; private static final String ATT_ALWAYS_USE_DEFAULT_TARGET_URL = "always-use-default-target"; private static final String DEF_FORM_LOGIN_TARGET_URL = "/"; private static final String ATT_USERNAME_PARAMETER = "username-parameter"; private static final String ATT_PASSWORD_PARAMETER = "password-parameter"; private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url"; private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME; private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref"; private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref"; private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_FORWARD_URL = "authentication-failure-forward-url"; private static final String ATT_FORM_LOGIN_AUTHENTICATION_SUCCESS_FORWARD_URL = "authentication-success-forward-url"; private final String defaultLoginProcessingUrl; private final String filterClassName; private final BeanReference requestCache; private final BeanReference sessionStrategy; private final boolean allowSessionCreation; private final BeanReference portMapper; private final BeanReference portResolver; private RootBeanDefinition filterBean; private RootBeanDefinition entryPointBean; private String loginPage; private String loginMethod; private String loginProcessingUrl; FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String loginMethod, String filterClassName, BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation, BeanReference portMapper, BeanReference portResolver) { this.defaultLoginProcessingUrl = defaultLoginProcessingUrl; this.loginMethod = loginMethod; this.filterClassName = filterClassName; this.requestCache = requestCache; this.sessionStrategy = sessionStrategy; this.allowSessionCreation = allowSessionCreation; this.portMapper = portMapper; this.portResolver = portResolver; } public BeanDefinition parse(Element elt, ParserContext pc) { String loginUrl = null; String defaultTargetUrl = null; String authenticationFailureUrl = null; String alwaysUseDefault = null; String successHandlerRef = null; String failureHandlerRef = null; // Only available with form-login String usernameParameter = null; String passwordParameter = null; String authDetailsSourceRef = null; String authenticationFailureForwardUrl = null; String authenticationSuccessForwardUrl = null; Object source = null; if (elt != null) { source = pc.extractSource(elt); loginUrl = elt.getAttribute(ATT_LOGIN_URL); WebConfigUtils.validateHttpRedirect(loginUrl, pc, source); defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL); WebConfigUtils.validateHttpRedirect(defaultTargetUrl, pc, source); authenticationFailureUrl = elt .getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL); WebConfigUtils.validateHttpRedirect(authenticationFailureUrl, pc, source); alwaysUseDefault = elt.getAttribute(ATT_ALWAYS_USE_DEFAULT_TARGET_URL); loginPage = elt.getAttribute(ATT_LOGIN_PAGE); successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF); failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF); authDetailsSourceRef = elt .getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF); authenticationFailureForwardUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_FORWARD_URL); WebConfigUtils.validateHttpRedirect(authenticationFailureForwardUrl, pc, source); authenticationSuccessForwardUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_SUCCESS_FORWARD_URL); WebConfigUtils.validateHttpRedirect(authenticationSuccessForwardUrl, pc, source); if (!StringUtils.hasText(loginPage)) { loginPage = null; } WebConfigUtils.validateHttpRedirect(loginPage, pc, source); usernameParameter = elt.getAttribute(ATT_USERNAME_PARAMETER); passwordParameter = elt.getAttribute(ATT_PASSWORD_PARAMETER); } filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl, successHandlerRef, failureHandlerRef, authDetailsSourceRef, authenticationFailureForwardUrl, authenticationSuccessForwardUrl); if (StringUtils.hasText(usernameParameter)) { filterBean.getPropertyValues().addPropertyValue("usernameParameter", usernameParameter); } if (StringUtils.hasText(passwordParameter)) { filterBean.getPropertyValues().addPropertyValue("passwordParameter", passwordParameter); } filterBean.setSource(source); BeanDefinitionBuilder entryPointBuilder = BeanDefinitionBuilder .rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class); entryPointBuilder.getRawBeanDefinition().setSource(source); entryPointBuilder.addConstructorArgValue(loginPage != null ? loginPage : DEF_LOGIN_PAGE); entryPointBuilder.addPropertyValue("portMapper", portMapper); entryPointBuilder.addPropertyValue("portResolver", portResolver); entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition(); return null; } private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault, String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef, String authDetailsSourceRef, String authenticationFailureForwardUrl, String authenticationSuccessForwardUrl) { BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder .rootBeanDefinition(filterClassName); if (!StringUtils.hasText(loginUrl)) { loginUrl = defaultLoginProcessingUrl; } this.loginProcessingUrl = loginUrl; BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder .rootBeanDefinition("org.springframework.security.web.util.matcher.AntPathRequestMatcher"); matcherBuilder.addConstructorArgValue(loginUrl); if (loginMethod != null) { matcherBuilder.addConstructorArgValue("POST"); } filterBuilder.addPropertyValue("requiresAuthenticationRequestMatcher", matcherBuilder.getBeanDefinition()); if (StringUtils.hasText(successHandlerRef)) { filterBuilder.addPropertyReference("authenticationSuccessHandler", successHandlerRef); } else if(StringUtils.hasText(authenticationSuccessForwardUrl)) { BeanDefinitionBuilder forwardSuccessHandler = BeanDefinitionBuilder .rootBeanDefinition(ForwardAuthenticationSuccessHandler.class); forwardSuccessHandler.addConstructorArgValue(authenticationSuccessForwardUrl); filterBuilder.addPropertyValue("authenticationSuccessHandler", forwardSuccessHandler.getBeanDefinition()); } else { BeanDefinitionBuilder successHandler = BeanDefinitionBuilder .rootBeanDefinition(SavedRequestAwareAuthenticationSuccessHandler.class); if ("true".equals(alwaysUseDefault)) { successHandler .addPropertyValue("alwaysUseDefaultTargetUrl", Boolean.TRUE); } successHandler.addPropertyValue("requestCache", requestCache); successHandler.addPropertyValue("defaultTargetUrl", StringUtils .hasText(defaultTargetUrl) ? defaultTargetUrl : DEF_FORM_LOGIN_TARGET_URL); filterBuilder.addPropertyValue("authenticationSuccessHandler", successHandler.getBeanDefinition()); } if (StringUtils.hasText(authDetailsSourceRef)) { filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef); } if (sessionStrategy != null) { filterBuilder.addPropertyValue("sessionAuthenticationStrategy", sessionStrategy); } if (StringUtils.hasText(failureHandlerRef)) { filterBuilder.addPropertyReference("authenticationFailureHandler", failureHandlerRef); } else if(StringUtils.hasText(authenticationFailureForwardUrl)) { BeanDefinitionBuilder forwardFailureHandler = BeanDefinitionBuilder .rootBeanDefinition(ForwardAuthenticationFailureHandler.class); forwardFailureHandler.addConstructorArgValue(authenticationFailureForwardUrl); filterBuilder.addPropertyValue("authenticationFailureHandler", forwardFailureHandler.getBeanDefinition()); } else { BeanDefinitionBuilder failureHandler = BeanDefinitionBuilder .rootBeanDefinition(SimpleUrlAuthenticationFailureHandler.class); if (!StringUtils.hasText(authenticationFailureUrl)) { // Fall back to re-displaying the custom login page, if one was specified. if (StringUtils.hasText(loginPage)) { authenticationFailureUrl = loginPage + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME; } else { authenticationFailureUrl = DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL; } } failureHandler .addPropertyValue("defaultFailureUrl", authenticationFailureUrl); failureHandler.addPropertyValue("allowSessionCreation", allowSessionCreation); filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition()); } return (RootBeanDefinition) filterBuilder.getBeanDefinition(); } RootBeanDefinition getFilterBean() { return filterBean; } RootBeanDefinition getEntryPointBean() { return entryPointBean; } String getLoginPage() { return loginPage; } String getLoginProcessingUrl() { return loginProcessingUrl; } }