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 4a11e675e8..44cfe38472 100644 --- a/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java @@ -159,20 +159,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext); } - // Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation. - Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME); - if (rememberMeElt != null || autoConfig) { - new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext); - // Post processor to inject RememberMeServices into filters which need it - RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class); - rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor); - } - - Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT); - if (logoutElt != null || autoConfig) { - new LogoutBeanDefinitionParser().parse(logoutElt, parserContext); - } + parseRememberMeAndLogout(element, autoConfig, parserContext); parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation); @@ -192,6 +179,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { return null; } + private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) { + // Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation. + Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME); + String rememberMeServices = null; + + if (rememberMeElt != null || autoConfig) { + RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser(); + rmbdp.parse(rememberMeElt, pc); + rememberMeServices = rmbdp.getServicesName(); + // Post processor to inject RememberMeServices into filters which need it + RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class); + rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor); + } + + Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT); + if (logoutElt != null || autoConfig) { + new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc); + } + } + private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) { if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) { pc.getReaderContext().error("Duplicate element detected", source); diff --git a/core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java index 72eb614d77..023bf7fa44 100644 --- a/core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java @@ -25,6 +25,12 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_LOGOUT_URL = "logout-url"; static final String DEF_LOGOUT_URL = "/j_spring_security_logout"; + + String rememberMeServices; + + public LogoutBeanDefinitionParser(String rememberMeServices) { + this.rememberMeServices = rememberMeServices; + } public BeanDefinition parse(Element element, ParserContext parserContext) { String logoutUrl = null; @@ -66,8 +72,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser { } handlers.add(sclh); - if (parserContext.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) { - handlers.add(new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES)); + if (rememberMeServices != null) { + handlers.add(new RuntimeBeanReference(rememberMeServices)); } builder.addConstructorArg(handlers); diff --git a/core/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java index 10372d989d..edff2b4855 100644 --- a/core/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/RememberMeBeanDefinitionParser.java @@ -32,6 +32,7 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_TOKEN_VALIDITY = "token-validity-seconds"; protected final Log logger = LogFactory.getLog(getClass()); + private String servicesName; public BeanDefinition parse(Element element, ParserContext parserContext) { String tokenRepository = null; @@ -102,8 +103,10 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { } services.setSource(source); services.getPropertyValues().addPropertyValue(ATT_KEY, key); - parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services); + parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services); + servicesName = BeanIds.REMEMBER_ME_SERVICES; } else { + servicesName = rememberMeServicesRef; parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES); } @@ -114,7 +117,11 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser { return null; } - private void registerProvider(ParserContext pc, Object source, String key) { + String getServicesName() { + return servicesName; + } + + private void registerProvider(ParserContext pc, Object source, String key) { BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc); RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class); provider.setSource(source); diff --git a/core/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java b/core/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java index b6cb81b72d..a1101dce39 100644 --- a/core/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java +++ b/core/src/main/java/org/springframework/security/config/RememberMeServicesInjectionBeanPostProcessor.java @@ -51,7 +51,8 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro Map beans = beanFactory.getBeansOfType(RememberMeServices.class); Assert.isTrue(beans.size() > 0, "No RememberMeServices configured"); - Assert.isTrue(beans.size() == 1, "More than one RememberMeServices bean found."); + Assert.isTrue(beans.size() == 1, "Use of '' requires a single instance of RememberMeServices " + + "in the application context, but more than one was found."); return (RememberMeServices) beans.values().toArray()[0]; } diff --git a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java index 170704e5ac..b6c1ad5c2f 100644 --- a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java +++ b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java @@ -34,6 +34,7 @@ import org.springframework.security.ui.SessionFixationProtectionFilter; import org.springframework.security.ui.WebAuthenticationDetails; import org.springframework.security.ui.basicauth.BasicProcessingFilter; import org.springframework.security.ui.logout.LogoutFilter; +import org.springframework.security.ui.logout.LogoutHandler; import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter; import org.springframework.security.ui.rememberme.NullRememberMeServices; import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices; @@ -378,7 +379,11 @@ public class HttpSecurityBeanDefinitionParserTests { AUTH_PROVIDER_XML); assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), - "tokenValiditySeconds")); + "tokenValiditySeconds")); + // SEC-909 + LogoutHandler[] logoutHandlers = (LogoutHandler[]) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers"); + assertEquals(2, logoutHandlers.length); + assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers[1]); } @Test