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