Selaa lähdekoodia

SEC-909: custom remember me services doesn't get registered as logout handler
http://jira.springframework.org/browse/SEC-909. HttpSecurityBeanDefinitionParser now passes the resolved RememberMeServices bean name to the LogoutBeanDefinitionparser so that it an use it explicitly.

Luke Taylor 17 vuotta sitten
vanhempi
commit
f453264bde

+ 22 - 14
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 <http> element detected", source);

+ 8 - 2
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);

+ 9 - 2
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);

+ 2 - 1
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 '<remember-me />' requires a single instance of RememberMeServices " +
+        		"in the application context, but more than one was found.");
 
         return (RememberMeServices) beans.values().toArray()[0];
     }

+ 6 - 1
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