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);