diff --git a/core/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java index f44746b007..9053a68dd8 100644 --- a/core/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/FormLoginBeanDefinitionParser.java @@ -24,7 +24,6 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { protected final Log logger = LogFactory.getLog(getClass()); static final String ATT_LOGIN_URL = "login-processing-url"; - static final String DEF_LOGIN_URL = "/j_spring_security_check"; static final String ATT_LOGIN_PAGE = "login-page"; static final String DEF_LOGIN_PAGE = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL; @@ -35,11 +34,23 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url"; static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME; + String defaultLoginProcessingUrl; + String filterClassName; + + RootBeanDefinition filterBean; + RootBeanDefinition entryPointBean; + String loginPage; + + FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName) { + this.defaultLoginProcessingUrl = defaultLoginProcessingUrl; + this.filterClassName = filterClassName; + } + public BeanDefinition parse(Element elt, ParserContext parserContext) { String loginUrl = null; String defaultTargetUrl = null; String authenticationFailureUrl = null; - String loginPage = null; + Object source = null; if (elt != null) { @@ -52,7 +63,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { ConfigUtils.registerProviderManagerIfNecessary(parserContext); - RootBeanDefinition filterBean = createFilterBean(loginUrl, defaultTargetUrl, loginPage, authenticationFailureUrl); + filterBean = createFilterBean(loginUrl, defaultTargetUrl, loginPage, authenticationFailureUrl); filterBean.setSource(source); filterBean.getPropertyValues().addPropertyValue("authenticationManager", @@ -62,34 +73,18 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class); entryPointBuilder.setSource(source); + entryPointBuilder.addPropertyValue("loginFormUrl", StringUtils.hasText(loginPage) ? loginPage : DEF_LOGIN_PAGE); - // If no login page has been defined, add in the default page generator. - if (!StringUtils.hasText(loginPage)) { - logger.info("No login page configured in form-login element. The default internal one will be used. Use" + - "the 'loginPage' attribute to specify the URL of the login page."); - loginPage = DEF_LOGIN_PAGE; - RootBeanDefinition loginPageFilter = new RootBeanDefinition(DefaultLoginPageGeneratingFilter.class); - loginPageFilter.getConstructorArgumentValues().addGenericArgumentValue( - new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER)); - parserContext.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, loginPageFilter); - } - - entryPointBuilder.addPropertyValue("loginFormUrl", loginPage); - - parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, filterBean); - parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, - entryPointBuilder.getBeanDefinition()); + entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition(); return null; } private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String loginPage, String authenticationFailureUrl) { - BeanDefinitionBuilder filterBuilder = - BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilter.class); - + BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName); if (!StringUtils.hasText(loginUrl)) { - loginUrl = DEF_LOGIN_URL; + loginUrl = defaultLoginProcessingUrl; } filterBuilder.addPropertyValue("filterProcessesUrl", loginUrl); @@ -114,4 +109,16 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser { return (RootBeanDefinition) filterBuilder.getBeanDefinition(); } + + RootBeanDefinition getFilterBean() { + return filterBean; + } + + RootBeanDefinition getEntryPointBean() { + return entryPointBean; + } + + String getLoginPage() { + return loginPage; + } } diff --git a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java index 7ff70ad094..a578e21e09 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -6,6 +6,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +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.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -28,6 +30,7 @@ import org.springframework.security.securechannel.SecureChannelProcessor; import org.springframework.security.securechannel.RetryWithHttpEntryPoint; import org.springframework.security.securechannel.RetryWithHttpsEntryPoint; import org.springframework.security.ui.ExceptionTranslationFilter; +import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter; import org.springframework.security.util.FilterChainProxy; import org.springframework.security.util.RegexUrlPathMatcher; import org.springframework.security.util.AntUrlPathMatcher; @@ -44,6 +47,7 @@ import org.w3c.dom.Element; * @version $Id$ */ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { + protected final Log logger = LogFactory.getLog(getClass()); static final String ATT_REALM = "realm"; static final String DEF_REALM = "Spring Security Application"; @@ -190,11 +194,6 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { registry.registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager); } - String realm = element.getAttribute(ATT_REALM); - if (!StringUtils.hasText(realm)) { - realm = DEF_REALM; - } - Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS); if (sessionControlElt != null) { new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext); @@ -220,16 +219,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { if (logoutElt != null || autoConfig) { new LogoutBeanDefinitionParser().parse(logoutElt, parserContext); } - - Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN); - if (formLoginElt != null || autoConfig) { - new FormLoginBeanDefinitionParser().parse(formLoginElt, parserContext); - } - - Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH); - if (basicAuthElt != null || autoConfig) { - new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext); - } + + parseBasicFormLoginAndOpenID(element, parserContext, autoConfig); Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509); if (x509Elt != null) { @@ -248,6 +239,104 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } + private void parseBasicFormLoginAndOpenID(Element element, ParserContext parserContext, boolean autoConfig) { + RootBeanDefinition formLoginFilter = null; + RootBeanDefinition formLoginEntryPoint = null; + String formLoginPage = null; + RootBeanDefinition openIDFilter = null; + RootBeanDefinition openIDEntryPoint = null; + String openIDLoginPage = null; + + String realm = element.getAttribute(ATT_REALM); + if (!StringUtils.hasText(realm)) { + realm = DEF_REALM; + } + + Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH); + if (basicAuthElt != null || autoConfig) { + new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, parserContext); + } + + Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN); + + if (formLoginElt != null || autoConfig) { + FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check", + "org.springframework.security.ui.webapp.AuthenticationProcessingFilter"); + + parser.parse(formLoginElt, parserContext); + formLoginFilter = parser.getFilterBean(); + formLoginEntryPoint = parser.getEntryPointBean(); + formLoginPage = parser.getLoginPage(); + } + + Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN); + + if (openIDLoginElt != null) { + FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check", + "org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter"); + + parser.parse(openIDLoginElt, parserContext); + openIDFilter = parser.getFilterBean(); + openIDEntryPoint = parser.getEntryPointBean(); + openIDLoginPage = parser.getLoginPage(); + } + + if (formLoginFilter == null && openIDFilter == null) { + return; + } + + if (formLoginFilter != null) { + parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter); + parserContext.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint); + } + + if (openIDFilter != null) { + parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter); + parserContext.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint); + } + + // If no login page has been defined, add in the default page generator. + if (formLoginPage == null && openIDLoginPage == null) { + logger.info("No login page configured. The default internal one will be used. Use the '" + + FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page."); + BeanDefinitionBuilder loginPageFilter = + BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class); + + if (formLoginFilter != null) { + loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER)); + } + + if (openIDFilter != null) { + loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER)); + } + + parserContext.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER, + loginPageFilter.getBeanDefinition()); + } + + // We need to establish the main entry point. + // Basic takes precedence if explicit element is used and no others are configured + if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) { + parserContext.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return; + } + + // If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page + // has been set + if (formLoginFilter != null && openIDLoginPage == null) { + parserContext.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return; + } + + // Otherwise use OpenID + if (openIDFilter != null && formLoginFilter == null) { + parserContext.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT); + return; + } + + throw new IllegalStateException("Couldn't set entry point"); + } + static UrlMatcher createUrlMatcher(Element element) { String patternType = element.getAttribute(ATT_PATH_TYPE); if (!StringUtils.hasText(patternType)) { diff --git a/core/src/main/java/org/springframework/security/ui/webapp/DefaultLoginPageGeneratingFilter.java b/core/src/main/java/org/springframework/security/ui/webapp/DefaultLoginPageGeneratingFilter.java index ffa9eb1270..d3af5d9973 100644 --- a/core/src/main/java/org/springframework/security/ui/webapp/DefaultLoginPageGeneratingFilter.java +++ b/core/src/main/java/org/springframework/security/ui/webapp/DefaultLoginPageGeneratingFilter.java @@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.springframework.beans.BeanWrapperImpl; import org.springframework.security.AuthenticationException; import org.springframework.security.ui.AbstractProcessingFilter; import org.springframework.security.ui.FilterChainOrder; @@ -26,21 +27,52 @@ import org.springframework.security.ui.rememberme.AbstractRememberMeServices; public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter { public static final String DEFAULT_LOGIN_PAGE_URL = "/spring_security_login"; public static final String ERROR_PARAMETER_NAME = "login_error"; + boolean formLoginEnabled; + boolean openIdEnabled; private String authenticationUrl; private String usernameParameter; private String passwordParameter; private String rememberMeParameter; - - public DefaultLoginPageGeneratingFilter(AuthenticationProcessingFilter authFilter) { - authenticationUrl = authFilter.getDefaultFilterProcessesUrl(); - usernameParameter = authFilter.getUsernameParameter(); - passwordParameter = authFilter.getPasswordParameter(); - - if (authFilter.getRememberMeServices() instanceof AbstractRememberMeServices) { - rememberMeParameter = ((AbstractRememberMeServices)authFilter.getRememberMeServices()).getParameter(); - } + private String openIDauthenticationUrl; + private String openIDusernameParameter; + private String openIDrememberMeParameter; + + public DefaultLoginPageGeneratingFilter(AbstractProcessingFilter filter) { + if (filter instanceof AuthenticationProcessingFilter) { + init((AuthenticationProcessingFilter)filter, null); + } else { + init(null, filter); + } } + + public DefaultLoginPageGeneratingFilter(AuthenticationProcessingFilter authFilter, AbstractProcessingFilter openIDFilter) { + init(authFilter, openIDFilter); + } + + private void init(AuthenticationProcessingFilter authFilter, AbstractProcessingFilter openIDFilter) { + if (authFilter != null) { + formLoginEnabled = true; + authenticationUrl = authFilter.getDefaultFilterProcessesUrl(); + usernameParameter = authFilter.getUsernameParameter(); + passwordParameter = authFilter.getPasswordParameter(); + + if (authFilter.getRememberMeServices() instanceof AbstractRememberMeServices) { + rememberMeParameter = ((AbstractRememberMeServices)authFilter.getRememberMeServices()).getParameter(); + } + } + + if (openIDFilter != null) { + openIdEnabled = true; + openIDauthenticationUrl = openIDFilter.getAuthenticationFailureUrl(); + openIDusernameParameter = (String) (new BeanWrapperImpl(openIDFilter)).getPropertyValue("claimedIdentityFieldName"); + if (openIDFilter.getRememberMeServices() instanceof AbstractRememberMeServices) { + openIDrememberMeParameter = ((AbstractRememberMeServices)openIDFilter.getRememberMeServices()).getParameter(); + } + } + } + + protected void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { if (isLoginUrlRequest(request)) { response.getOutputStream().print(generateLoginPageHtml(request)); @@ -68,24 +100,59 @@ public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter { } } } - - return "
Your login attempt was not successful, try again.
Reason: ");
+ sb.append(errorMsg);
+ sb.append("