diff --git a/config/src/main/java/org/springframework/security/config/http/LogoutBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/LogoutBeanDefinitionParser.java index 14b8a7f3fa..4976e2cd47 100644 --- a/config/src/main/java/org/springframework/security/config/http/LogoutBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/LogoutBeanDefinitionParser.java @@ -25,6 +25,7 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser { static final String ATT_LOGOUT_URL = "logout-url"; static final String DEF_LOGOUT_URL = "/j_spring_security_logout"; + static final String ATT_LOGOUT_HANDLER = "success-handler-ref"; String rememberMeServices; @@ -33,20 +34,22 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser { } @SuppressWarnings("unchecked") - public BeanDefinition parse(Element element, ParserContext parserContext) { + public BeanDefinition parse(Element element, ParserContext pc) { String logoutUrl = null; + String successHandlerRef = null; String logoutSuccessUrl = null; String invalidateSession = null; BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class); if (element != null) { - Object source = parserContext.extractSource(element); + Object source = pc.extractSource(element); builder.getRawBeanDefinition().setSource(source); logoutUrl = element.getAttribute(ATT_LOGOUT_URL); - WebConfigUtils.validateHttpRedirect(logoutUrl, parserContext, source); + successHandlerRef = element.getAttribute(ATT_LOGOUT_HANDLER); + WebConfigUtils.validateHttpRedirect(logoutUrl, pc, source); logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL); - WebConfigUtils.validateHttpRedirect(logoutSuccessUrl, parserContext, source); + WebConfigUtils.validateHttpRedirect(logoutSuccessUrl, pc, source); invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION); } @@ -55,10 +58,19 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser { } builder.addPropertyValue("filterProcessesUrl", logoutUrl); - if (!StringUtils.hasText(logoutSuccessUrl)) { - logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL; + if (StringUtils.hasText(successHandlerRef)) { + if (StringUtils.hasText(logoutSuccessUrl)) { + pc.getReaderContext().error("Use " + ATT_LOGOUT_URL + " or " + ATT_LOGOUT_HANDLER + ", but not both", + pc.extractSource(element)); + } + builder.addConstructorArgReference(successHandlerRef); + } else { + // Use the logout URL if no handler set + if (!StringUtils.hasText(logoutSuccessUrl)) { + logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL; + } + builder.addConstructorArgValue(logoutSuccessUrl); } - builder.addConstructorArgValue(logoutSuccessUrl); if (!StringUtils.hasText(invalidateSession)) { invalidateSession = DEF_INVALIDATE_SESSION; diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc index 3906994e73..53639277c6 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.rnc @@ -327,6 +327,10 @@ logout.attlist &= logout.attlist &= ## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true. attribute invalidate-session {boolean}? +logout.attlist &= + ## A reference to a LogoutSuccessHandler implementation which will be used to determine the destination to which the user is taken after logging out. + attribute success-handler-ref {xsd:token}? + request-cache = ## Allow the RequestCache used for saving requests during the login process to be set diff --git a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd index e29e1ad191..c3159594cb 100644 --- a/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd +++ b/config/src/main/resources/org/springframework/security/config/spring-security-3.0.xsd @@ -800,6 +800,11 @@ Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true. + + + A reference to a LogoutSuccessHandler implementation which will be used to determine the destination to which the user is taken after logging out. + + Allow the RequestCache used for saving requests during the login process to be set diff --git a/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java index 9371b7dba6..dbc2b907eb 100644 --- a/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java @@ -1,19 +1,9 @@ package org.springframework.security.config.http; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML; -import static org.springframework.security.config.http.AuthenticationConfigBuilder.AUTHENTICATION_PROCESSING_FILTER_CLASS; -import static org.springframework.security.config.http.AuthenticationConfigBuilder.OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS; -import static org.springframework.security.config.http.AuthenticationConfigBuilder.OPEN_ID_AUTHENTICATION_PROVIDER_CLASS; +import static org.springframework.security.config.http.AuthenticationConfigBuilder.*; import java.lang.reflect.Method; import java.util.ArrayList; @@ -70,6 +60,7 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor; import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter; import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl; @@ -300,6 +291,21 @@ public class HttpSecurityBeanDefinitionParserTests { "" + AUTH_PROVIDER_XML); } + @Test + public void logoutSuccessHandlerIsSetCorrectly() throws Exception { + setContext( + "" + + " " + + " " + + "" + + "" + + AUTH_PROVIDER_XML); + + LogoutFilter filter = (LogoutFilter) getFilter(LogoutFilter.class); + LogoutSuccessHandler handler = (LogoutSuccessHandler) FieldUtils.getFieldValue(filter, "logoutSuccessHandler"); + assertSame(appContext.getBean("logoutHandler"), handler); + } + @Test public void lowerCaseComparisonIsRespectedBySecurityFilterInvocationDefinitionSource() throws Exception { setContext(