FormLoginBeanDefinitionParser.java
/*
* Copyright 2004-present 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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
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.ForwardAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.util.StringUtils;
/**
* @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 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) {
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
this.loginMethod = loginMethod;
this.filterClassName = filterClassName;
this.requestCache = requestCache;
this.sessionStrategy = sessionStrategy;
this.allowSessionCreation = allowSessionCreation;
this.portMapper = portMapper;
}
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);
this.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(this.loginPage)) {
this.loginPage = null;
}
WebConfigUtils.validateHttpRedirect(this.loginPage, pc, source);
usernameParameter = elt.getAttribute(ATT_USERNAME_PARAMETER);
passwordParameter = elt.getAttribute(ATT_PASSWORD_PARAMETER);
}
this.filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, this.loginPage,
authenticationFailureUrl, successHandlerRef, failureHandlerRef, authDetailsSourceRef,
authenticationFailureForwardUrl, authenticationSuccessForwardUrl);
if (StringUtils.hasText(usernameParameter)) {
this.filterBean.getPropertyValues().addPropertyValue("usernameParameter", usernameParameter);
}
if (StringUtils.hasText(passwordParameter)) {
this.filterBean.getPropertyValues().addPropertyValue("passwordParameter", passwordParameter);
}
this.filterBean.setSource(source);
BeanDefinitionBuilder entryPointBuilder = BeanDefinitionBuilder
.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class);
entryPointBuilder.getRawBeanDefinition().setSource(source);
entryPointBuilder.addConstructorArgValue((this.loginPage != null) ? this.loginPage : DEF_LOGIN_PAGE);
entryPointBuilder.addPropertyValue("portMapper", this.portMapper);
this.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(this.filterClassName);
if (!StringUtils.hasText(loginUrl)) {
loginUrl = this.defaultLoginProcessingUrl;
}
this.loginProcessingUrl = loginUrl;
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder
.rootBeanDefinition(RequestMatcherFactoryBean.class);
matcherBuilder.addConstructorArgValue(loginUrl);
if (this.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", this.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 (this.sessionStrategy != null) {
filterBuilder.addPropertyValue("sessionAuthenticationStrategy", this.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", this.allowSessionCreation);
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
}
return (RootBeanDefinition) filterBuilder.getBeanDefinition();
}
RootBeanDefinition getFilterBean() {
return this.filterBean;
}
RootBeanDefinition getEntryPointBean() {
return this.entryPointBean;
}
String getLoginPage() {
return this.loginPage;
}
String getLoginProcessingUrl() {
return this.loginProcessingUrl;
}
}