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(