diff --git a/core/src/main/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilter.java b/core/src/main/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilter.java
index 38ff8d7dbd..9dfc6a1403 100644
--- a/core/src/main/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilter.java
+++ b/core/src/main/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilter.java
@@ -24,6 +24,7 @@ import org.springframework.security.CredentialsExpiredException;
import org.springframework.security.DisabledException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.LockedException;
+import org.springframework.security.util.RedirectUtils;
import org.springframework.security.context.SecurityContextHolder;
@@ -35,6 +36,7 @@ import org.springframework.security.ui.AuthenticationDetailsSource;
import org.springframework.security.ui.AuthenticationDetailsSourceImpl;
import org.springframework.security.ui.SpringSecurityFilter;
import org.springframework.security.ui.FilterChainOrderUtils;
+import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
@@ -120,6 +122,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
private String targetUrl;
private SwitchUserAuthorityChanger switchUserAuthorityChanger;
private UserDetailsService userDetailsService;
+ private boolean useRelativeContext;
//~ Methods ========================================================================================================
@@ -311,7 +314,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
SecurityContextHolder.getContext().setAuthentication(targetUser);
// redirect to target url
- response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + targetUrl));
+ sendRedirect(request, response, targetUrl);
return;
} else if (requiresExitUser(request)) {
@@ -322,7 +325,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
SecurityContextHolder.getContext().setAuthentication(originalUser);
// redirect to target url
- response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + targetUrl));
+ sendRedirect(request, response, targetUrl);
return;
}
@@ -330,6 +333,12 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
chain.doFilter(request, response);
}
+ protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
+ throws IOException {
+
+ RedirectUtils.sendRedirect(request, response, url, useRelativeContext);
+ }
+
/**
* Find the original Authentication object from the current user's granted authorities. A
* successfully switched user should have a SwitchUserGrantedAuthority that contains the original
@@ -436,6 +445,16 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
this.userDetailsService = userDetailsService;
}
+ /**
+ * Analogous to the same property in {@link AbstractProcessingFilter}. If set, redirects will
+ * be context-relative (they won't include the context path).
+ *
+ * @param useRelativeContext
+ */
+ public void setUseRelativeContext(boolean useRelativeContext) {
+ this.useRelativeContext = useRelativeContext;
+ }
+
/**
* Strips any content after the ';' in the request URI
*
diff --git a/core/src/test/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilterTests.java b/core/src/test/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilterTests.java
index 3ce4f70a6a..d548b2d6c7 100644
--- a/core/src/test/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilterTests.java
+++ b/core/src/test/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilterTests.java
@@ -260,6 +260,7 @@ public class SwitchUserProcessingFilterTests extends TestCase {
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
filter.setExitUserUrl("/j_spring_security_exit_user");
+ filter.setTargetUrl("/webapp/someOtherUrl");
MockFilterChain chain = new MockFilterChain(true);
@@ -304,6 +305,7 @@ public class SwitchUserProcessingFilterTests extends TestCase {
SecurityContextHolder.getContext().setAuthentication(auth);
MockHttpServletRequest request = createMockSwitchRequest();
+ request.setContextPath("/webapp");
request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "jacklord");
request.setRequestURI("/webapp/j_spring_security_switch_user");
@@ -312,7 +314,7 @@ public class SwitchUserProcessingFilterTests extends TestCase {
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
filter.setSwitchUserUrl("/j_spring_security_switch_user");
- filter.setTargetUrl("/webapp/someOtherUrl");
+ filter.setTargetUrl("/someOtherUrl");
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
filter.doFilter(request, response, chain);
@@ -320,6 +322,30 @@ public class SwitchUserProcessingFilterTests extends TestCase {
assertEquals("/webapp/someOtherUrl", response.getRedirectedUrl());
}
+ public void testRedirectOmitsContextPathIfUseRelativeContextSet() throws Exception {
+ // set current user
+ UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", "hawaii50");
+ SecurityContextHolder.getContext().setAuthentication(auth);
+
+ MockHttpServletRequest request = createMockSwitchRequest();
+ request.setContextPath("/webapp");
+ request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "jacklord");
+ request.setRequestURI("/webapp/j_spring_security_switch_user");
+
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ MockFilterChain chain = new MockFilterChain(true);
+
+ SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
+ filter.setSwitchUserUrl("/j_spring_security_switch_user");
+ filter.setTargetUrl("/someOtherUrl");
+ filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
+ filter.setUseRelativeContext(true);
+
+ filter.doFilter(request, response, chain);
+
+ assertEquals("/someOtherUrl", response.getRedirectedUrl());
+ }
+
public void testRequiresExitUser() {
// filter
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
@@ -360,6 +386,7 @@ public class SwitchUserProcessingFilterTests extends TestCase {
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
filter.setSwitchUserUrl("/j_spring_security_switch_user");
+ filter.setTargetUrl("/webapp/someOtherUrl");
MockFilterChain chain = new MockFilterChain(true);