Просмотр исходного кода

SEC-959: Converted SwitchUserFilter to use new Authentication success and failure strategies from SEC-745 for managing redirects.

Luke Taylor 17 лет назад
Родитель
Сommit
898ef36d02

+ 8 - 1
core/src/main/java/org/springframework/security/ui/SimpleUrlAuthenticationFailureHandler.java

@@ -29,10 +29,17 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
     private boolean forwardToDestination = false;
     private boolean useRelativeContext = false;
 
+    public SimpleUrlAuthenticationFailureHandler() {
+    }
+
+    public SimpleUrlAuthenticationFailureHandler(String defaultFailureUrl) {
+        setDefaultFailureUrl(defaultFailureUrl);
+    }
+
     public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
             AuthenticationException exception) throws IOException, ServletException {
         if (defaultFailureUrl == null) {
-            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + exception.getMessage());
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());
         } else {
             if (forwardToDestination) {
                 request.getRequestDispatcher(defaultFailureUrl).forward(request, response);

+ 8 - 1
core/src/main/java/org/springframework/security/ui/SimpleUrlAuthenticationSuccessHandler.java

@@ -25,6 +25,13 @@ public class SimpleUrlAuthenticationSuccessHandler implements AuthenticationSucc
     protected boolean alwaysUseDefaultTargetUrl = false;
     protected boolean useRelativeContext = false;
 
+    public SimpleUrlAuthenticationSuccessHandler() {
+    }
+
+    public SimpleUrlAuthenticationSuccessHandler(String defaultTargetUrl) {
+        setDefaultTargetUrl(defaultTargetUrl);
+    }
+
     public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
             Authentication authentication) throws IOException, ServletException {
 
@@ -103,7 +110,7 @@ public class SimpleUrlAuthenticationSuccessHandler implements AuthenticationSucc
      *  to "redirect".
      */
     public void setTargetUrlParameter(String targetUrlParameter) {
-        Assert.hasText("targetUrlParamete canot be null or empty");
+        Assert.hasText("targetUrlParameter canot be null or empty");
         this.targetUrlParameter = targetUrlParameter;
     }
 

+ 161 - 137
core/src/main/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilter.java

@@ -43,9 +43,12 @@ import org.springframework.security.SpringSecurityMessageSource;
 import org.springframework.security.context.SecurityContextHolder;
 import org.springframework.security.event.authentication.AuthenticationSwitchUserEvent;
 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
-import org.springframework.security.ui.AbstractProcessingFilter;
 import org.springframework.security.ui.AuthenticationDetailsSource;
+import org.springframework.security.ui.AuthenticationFailureHandler;
+import org.springframework.security.ui.AuthenticationSuccessHandler;
 import org.springframework.security.ui.FilterChainOrder;
+import org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler;
+import org.springframework.security.ui.SimpleUrlAuthenticationSuccessHandler;
 import org.springframework.security.ui.SpringSecurityFilter;
 import org.springframework.security.ui.WebAuthenticationDetailsSource;
 import org.springframework.security.userdetails.UserDetails;
@@ -53,8 +56,9 @@ import org.springframework.security.userdetails.UserDetailsChecker;
 import org.springframework.security.userdetails.UserDetailsService;
 import org.springframework.security.userdetails.UsernameNotFoundException;
 import org.springframework.security.userdetails.checker.AccountStatusUserDetailsChecker;
-import org.springframework.security.util.RedirectUtils;
+import org.springframework.security.util.UrlUtils;
 import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
 
 
 /**
@@ -66,12 +70,13 @@ import org.springframework.util.Assert;
  * <p>
  * This filter assumes that the user performing the switch will be required to be logged in as normal (i.e.
  * as a ROLE_ADMIN user). The user will then access a page/controller that enables the administrator to specify who they
- * wish to become (see <code>switchUserUrl</code>). <br>
- * <b>Note: This URL will be required to have to appropriate security contraints configured so that only users of that
- * role can access (e.g. ROLE_ADMIN).</b>
+ * wish to become (see <code>switchUserUrl</code>).
  * <p>
- * On successful switch, the user's  <code>SecurityContextHolder</code> will be updated to reflect the
- * specified user and will also contain an additinal
+ * <b>Note: This URL will be required to have appropriate security constraints configured so that only users of that
+ * role can access it (e.g. ROLE_ADMIN).</b>
+ * <p>
+ * On a successful switch, the user's  <code>SecurityContextHolder</code> will be updated to reflect the
+ * specified user and will also contain an additional
  * {@link org.springframework.security.ui.switchuser.SwitchUserGrantedAuthority} which contains the original user.
  * <p>
  * To 'exit' from a user context, the user will then need to access a URL (see <code>exitUserUrl</code>)  that
@@ -80,7 +85,8 @@ import org.springframework.util.Assert;
  * To configure the Switch User Processing Filter, create a bean definition for the Switch User processing
  * filter and add to the filterChainProxy. Note that the filter must come <b>after</b> the
  * <tt>FilterSecurityInteceptor</tt> in the chain, in order to apply the correct constraints to the <tt>switchUserUrl</tt>.
- * Example:<pre>
+ * Example:
+ * <pre>
  * &lt;bean id="switchUserProcessingFilter" class="org.springframework.security.ui.switchuser.SwitchUserProcessingFilter">
  *    &lt;property name="userDetailsService" ref="userDetailsService" />
  *    &lt;property name="switchUserUrl">&lt;value>/j_spring_security_switch_user&lt;/value>&lt;/property>
@@ -112,63 +118,61 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
     private SwitchUserAuthorityChanger switchUserAuthorityChanger;
     private UserDetailsService userDetailsService;
     private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
-    private boolean useRelativeContext;
+    private AuthenticationSuccessHandler successHandler;
+    private AuthenticationFailureHandler failureHandler;
 
     //~ Methods ========================================================================================================
 
     public void afterPropertiesSet() throws Exception {
-        Assert.hasLength(switchUserUrl, "switchUserUrl must be specified");
-        Assert.hasLength(exitUserUrl, "exitUserUrl must be specified");
-        Assert.hasLength(targetUrl, "targetUrl must be specified");
-        Assert.notNull(userDetailsService, "authenticationDao must be specified");
-        Assert.notNull(messages, "A message source must be set");
+        Assert.notNull(userDetailsService, "userDetailsService must be specified");
+        Assert.isTrue(successHandler != null || targetUrl != null, "You must set either a successHandler or the targetUrl");
+        if (targetUrl != null) {
+            Assert.isNull(successHandler, "You cannot set both successHandler and targetUrl");
+            successHandler = new SimpleUrlAuthenticationSuccessHandler(targetUrl);
+        }
+
+        if (failureHandler == null) {
+            failureHandler = switchFailureUrl == null ? new SimpleUrlAuthenticationFailureHandler() :
+                new SimpleUrlAuthenticationFailureHandler(switchFailureUrl);
+        } else {
+            Assert.isNull(switchFailureUrl, "You cannot set both a switchFailureUrl and a failureHandler");
+        }
     }
 
-    /**
-     * Attempt to exit from an already switched user.
-     *
-     * @param request The http servlet request
-     *
-     * @return The original <code>Authentication</code> object or <code>null</code> otherwise.
-     *
-     * @throws AuthenticationCredentialsNotFoundException If no <code>Authentication</code> associated with this
-     *         request.
-     */
-    protected Authentication attemptExitUser(HttpServletRequest request)
-            throws AuthenticationCredentialsNotFoundException {
-        // need to check to see if the current user has a SwitchUserGrantedAuthority
-        Authentication current = SecurityContextHolder.getContext().getAuthentication();
+    public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
 
-        if (null == current) {
-            throw new AuthenticationCredentialsNotFoundException(messages.getMessage(
-                    "SwitchUserProcessingFilter.noCurrentUser", "No current user associated with this request"));
-        }
+        // check for switch or exit request
+        if (requiresSwitchUser(request)) {
+            // if set, attempt switch and store original
+            try {
+                Authentication targetUser = attemptSwitchUser(request);
 
-        // check to see if the current user did actual switch to another user
-        // if so, get the original source user so we can switch back
-        Authentication original = getSourceAuthentication(current);
+                // update the current context to the new target user
+                SecurityContextHolder.getContext().setAuthentication(targetUser);
 
-        if (original == null) {
-            logger.error("Could not find original user Authentication object!");
-            throw new AuthenticationCredentialsNotFoundException(messages.getMessage(
-                    "SwitchUserProcessingFilter.noOriginalAuthentication",
-                    "Could not find original Authentication object"));
-        }
+                // redirect to target url
+                successHandler.onAuthenticationSuccess(request, response, targetUser);
+            } catch (AuthenticationException e) {
+                logger.debug("Switch User failed", e);
+                failureHandler.onAuthenticationFailure(request, response, e);
+            }
 
-        // get the source user details
-        UserDetails originalUser = null;
-        Object obj = original.getPrincipal();
+            return;
+        } else if (requiresExitUser(request)) {
+            // get the original authentication object (if exists)
+            Authentication originalUser = attemptExitUser(request);
 
-        if ((obj != null) && obj instanceof UserDetails) {
-            originalUser = (UserDetails) obj;
-        }
+            // update the current context back to the original user
+            SecurityContextHolder.getContext().setAuthentication(originalUser);
 
-        // publish event
-        if (this.eventPublisher != null) {
-            eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(current, originalUser));
+            // redirect to target url
+            successHandler.onAuthenticationSuccess(request, response, originalUser);
+
+            return;
         }
 
-        return original;
+        chain.doFilter(request, response);
     }
 
     /**
@@ -199,7 +203,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
         UserDetails targetUser = userDetailsService.loadUserByUsername(username);
         userDetailsChecker.check(targetUser);
 
-        // ok, create the switch user token
+        // OK, create the switch user token
         targetUserRequest = createSwitchUserToken(request, targetUser);
 
         if (logger.isDebugEnabled()) {
@@ -215,6 +219,53 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
         return targetUserRequest;
     }
 
+    /**
+     * Attempt to exit from an already switched user.
+     *
+     * @param request The http servlet request
+     *
+     * @return The original <code>Authentication</code> object or <code>null</code> otherwise.
+     *
+     * @throws AuthenticationCredentialsNotFoundException If no <code>Authentication</code> associated with this
+     *         request.
+     */
+    protected Authentication attemptExitUser(HttpServletRequest request)
+            throws AuthenticationCredentialsNotFoundException {
+        // need to check to see if the current user has a SwitchUserGrantedAuthority
+        Authentication current = SecurityContextHolder.getContext().getAuthentication();
+
+        if (null == current) {
+            throw new AuthenticationCredentialsNotFoundException(messages.getMessage(
+                    "SwitchUserProcessingFilter.noCurrentUser", "No current user associated with this request"));
+        }
+
+        // check to see if the current user did actual switch to another user
+        // if so, get the original source user so we can switch back
+        Authentication original = getSourceAuthentication(current);
+
+        if (original == null) {
+            logger.error("Could not find original user Authentication object!");
+            throw new AuthenticationCredentialsNotFoundException(messages.getMessage(
+                    "SwitchUserProcessingFilter.noOriginalAuthentication",
+                    "Could not find original Authentication object"));
+        }
+
+        // get the source user details
+        UserDetails originalUser = null;
+        Object obj = original.getPrincipal();
+
+        if ((obj != null) && obj instanceof UserDetails) {
+            originalUser = (UserDetails) obj;
+        }
+
+        // publish event
+        if (this.eventPublisher != null) {
+            eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(current, originalUser));
+        }
+
+        return original;
+    }
+
     /**
      * Create a switch user token that contains an additional <tt>GrantedAuthority</tt> that contains the
      * original <code>Authentication</code> object.
@@ -257,60 +308,6 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
         return targetUserRequest;
     }
 
-    public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
-            throws IOException, ServletException {
-
-        // check for switch or exit request
-        if (requiresSwitchUser(request)) {
-            // if set, attempt switch and store original
-
-            try {
-                Authentication targetUser = attemptSwitchUser(request);
-
-                // update the current context to the new target user
-                SecurityContextHolder.getContext().setAuthentication(targetUser);
-
-                // redirect to target url
-                sendRedirect(request, response, targetUrl);
-            } catch (AuthenticationException e) {
-                redirectToFailureUrl(request, response, e);
-            }
-
-            return;
-        } else if (requiresExitUser(request)) {
-            // get the original authentication object (if exists)
-            Authentication originalUser = attemptExitUser(request);
-
-            // update the current context back to the original user
-            SecurityContextHolder.getContext().setAuthentication(originalUser);
-
-            // redirect to target url
-            sendRedirect(request, response, targetUrl);
-
-            return;
-        }
-
-        chain.doFilter(request, response);
-    }
-
-    private void redirectToFailureUrl(HttpServletRequest request, HttpServletResponse response,
-            AuthenticationException failed) throws IOException {
-        logger.debug("Switch User failed", failed);
-
-        if (switchFailureUrl != null) {
-            sendRedirect(request, response, switchFailureUrl);
-        } else {
-            response.getWriter().print("Switch user failed: " + failed.getMessage());
-            response.flushBuffer();
-        }
-    }
-
-    protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
-            throws IOException {
-
-        RedirectUtils.sendRedirect(request, response, url, useRelativeContext);
-    }
-
     /**
      * Find the original <code>Authentication</code> object from the current user's granted authorities. A
      * successfully switched user should have a <code>SwitchUserGrantedAuthority</code> that contains the original
@@ -368,7 +365,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
     }
 
     public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher)
-        throws BeansException {
+            throws BeansException {
         this.eventPublisher = eventPublisher;
     }
 
@@ -377,30 +374,47 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
         this.authenticationDetailsSource = authenticationDetailsSource;
     }
 
+    public void setMessageSource(MessageSource messageSource) {
+        Assert.notNull(messageSource, "messageSource cannot be null");
+        this.messages = new MessageSourceAccessor(messageSource);
+    }
+
+    /**
+     * Sets the authentication data access object.
+     *
+     * @param userDetailsService The <tt>UserDetailService</tt> which will be used to load information for the user
+     *                           that is being switched to.
+     */
+    public void setUserDetailsService(UserDetailsService userDetailsService) {
+        this.userDetailsService = userDetailsService;
+    }
+
     /**
      * Set the URL to respond to exit user processing.
      *
      * @param exitUserUrl The exit user URL.
      */
     public void setExitUserUrl(String exitUserUrl) {
+        Assert.isTrue(UrlUtils.isValidRedirectUrl(exitUserUrl),
+                "exitUserUrl cannot be empty and must be a valid redirect URL");
         this.exitUserUrl = exitUserUrl;
     }
 
-    public void setMessageSource(MessageSource messageSource) {
-        this.messages = new MessageSourceAccessor(messageSource);
-    }
-
     /**
      * Set the URL to respond to switch user processing.
      *
      * @param switchUserUrl The switch user URL.
      */
     public void setSwitchUserUrl(String switchUserUrl) {
+        Assert.isTrue(UrlUtils.isValidRedirectUrl(switchUserUrl),
+                "switchUserUrl cannot be empty and must be a valid redirect URL");
         this.switchUserUrl = switchUserUrl;
     }
 
     /**
      * Sets the URL to go to after a successful switch / exit user request.
+     * Use {@link #setSuccessHandler(AuthenticationSuccessHandler) setSuccessHandler} instead if you need more
+     * customized behaviour.
      *
      * @param targetUrl The target url.
      */
@@ -409,36 +423,54 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
     }
 
     /**
-     * Sets the authentication data access object.
-     *
-     * @param userDetailsService The authentication dao
-     */
-    public void setUserDetailsService(UserDetailsService userDetailsService) {
-        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 set to true to exclude the context path from redirect URLs.
+     * Used to define custom behaviour on a successful switch or exit user.
+     * <p>
+     * Can be used instead of setting <tt>targetUrl</tt>.
      */
-    public void setUseRelativeContext(boolean useRelativeContext) {
-        this.useRelativeContext = useRelativeContext;
+    public void setSuccessHandler(AuthenticationSuccessHandler successHandler) {
+        Assert.notNull(successHandler, "successHandler cannot be null");
+        this.successHandler = successHandler;
     }
 
     /**
-     * Sets the URL to which a user should be redirected if the swittch fails. For example, this might happen because
+     * Sets the URL to which a user should be redirected if the switch fails. For example, this might happen because
      * the account they are attempting to switch to is invalid (the user doesn't exist, account is locked etc).
      * <p>
-     * If not set, an error essage wil be written to the response.
+     * If not set, an error message will be written to the response.
+     * <p>
+     * Use {@link #setFailureHandler(AuthenticationFailureHandler) failureHandler} instead if you need more
+     * customized behaviour.
      *
      * @param switchFailureUrl the url to redirect to.
      */
     public void setSwitchFailureUrl(String switchFailureUrl) {
+        Assert.isTrue(StringUtils.hasText(switchUserUrl) && UrlUtils.isValidRedirectUrl(switchFailureUrl),
+                "switchFailureUrl cannot be empty and must be a valid redirect URL");
         this.switchFailureUrl = switchFailureUrl;
     }
 
+    /**
+     * Used to define custom behaviour when a switch fails.
+     * <p>
+     * Can be used instead of setting <tt>switchFailureUrl</tt>.
+     */
+    public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
+        Assert.notNull(failureHandler, "failureHandler cannot be null");
+        this.failureHandler = failureHandler;
+    }
+
+    /**
+     * @param switchUserAuthorityChanger to use to fine-tune the authorities granted to subclasses (may be null if
+     * SwitchUserProcessingFilter should not fine-tune the authorities)
+     */
+    public void setSwitchUserAuthorityChanger(SwitchUserAuthorityChanger switchUserAuthorityChanger) {
+        this.switchUserAuthorityChanger = switchUserAuthorityChanger;
+    }
+
+    public void setUserDetailsChecker(UserDetailsChecker userDetailsChecker) {
+        this.userDetailsChecker = userDetailsChecker;
+    }
+
     /**
      * Strips any content after the ';' in the request URI
      *
@@ -446,7 +478,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
      *
      * @return The stripped uri
      */
-    private static String stripUri(HttpServletRequest request) {
+    private String stripUri(HttpServletRequest request) {
         String uri = request.getRequestURI();
         int idx = uri.indexOf(';');
 
@@ -457,14 +489,6 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
         return uri;
     }
 
-    /**
-     * @param switchUserAuthorityChanger to use to fine-tune the authorities granted to subclasses (may be null if
-     * SwitchUserProcessingFilter shoudl not fine-tune the authorities)
-     */
-    public void setSwitchUserAuthorityChanger(SwitchUserAuthorityChanger switchUserAuthorityChanger) {
-        this.switchUserAuthorityChanger = switchUserAuthorityChanger;
-    }
-
     public int getOrder() {
         return FilterChainOrder.SWITCH_USER_FILTER;
     }

+ 1 - 1
core/src/main/java/org/springframework/security/util/UrlUtils.java

@@ -105,6 +105,6 @@ public final class UrlUtils {
      * Returns true if the supplied URL starts with a "/" or "http".
      */
     public static boolean isValidRedirectUrl(String url) {
-        return url.startsWith("/") || url.toLowerCase().startsWith("http");
+        return url != null && url.startsWith("/") || url.toLowerCase().startsWith("http");
     }
 }

+ 16 - 6
core/src/test/java/org/springframework/security/ui/switchuser/SwitchUserProcessingFilterTests.java

@@ -36,6 +36,8 @@ import org.springframework.security.GrantedAuthority;
 import org.springframework.security.GrantedAuthorityImpl;
 import org.springframework.security.context.SecurityContextHolder;
 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
+import org.springframework.security.ui.SimpleUrlAuthenticationFailureHandler;
+import org.springframework.security.ui.SimpleUrlAuthenticationSuccessHandler;
 import org.springframework.security.userdetails.User;
 import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.UserDetailsService;
@@ -151,17 +153,23 @@ public class SwitchUserProcessingFilterTests {
         request.addParameter(SwitchUserProcessingFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "mcgarrett");
         MockHttpServletResponse response = new MockHttpServletResponse();
         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
+        filter.setTargetUrl("/target");
         filter.setUserDetailsService(new MockUserDetailsService());
+        filter.afterPropertiesSet();
 
         // Check it with no url set (should get a text response)
         filter.doFilterHttp(request, response, new MockFilterChain(false));
 
-        assertEquals("Switch user failed: User is disabled", response.getContentAsString());
+        assertEquals("Authentication Failed: User is disabled", response.getErrorMessage());
 
         // Now check for the redirect
         request.setContextPath("/mywebapp");
         request.setRequestURI("/mywebapp/j_spring_security_switch_user");
+        filter = new SwitchUserProcessingFilter();
+        filter.setTargetUrl("/target");
+        filter.setUserDetailsService(new MockUserDetailsService());
         filter.setSwitchFailureUrl("/switchfailed");
+        filter.afterPropertiesSet();
         response = new MockHttpServletResponse();
 
         filter.doFilterHttp(request, response, new MockFilterChain(true));
@@ -219,7 +227,7 @@ public class SwitchUserProcessingFilterTests {
         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
         filter.setUserDetailsService(new MockUserDetailsService());
         filter.setExitUserUrl("/j_spring_security_exit_user");
-        filter.setTargetUrl("/webapp/someOtherUrl");
+        filter.setSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/webapp/someOtherUrl"));
 
         // run 'exit'
         filter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain(false));
@@ -258,7 +266,7 @@ public class SwitchUserProcessingFilterTests {
 
         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
         filter.setSwitchUserUrl("/j_spring_security_switch_user");
-        filter.setTargetUrl("/someOtherUrl");
+        filter.setSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/someOtherUrl"));
         filter.setUserDetailsService(new MockUserDetailsService());
 
         filter.doFilter(request, response, new MockFilterChain(false));
@@ -281,9 +289,11 @@ public class SwitchUserProcessingFilterTests {
 
         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
         filter.setSwitchUserUrl("/j_spring_security_switch_user");
-        filter.setTargetUrl("/someOtherUrl");
+        SimpleUrlAuthenticationSuccessHandler switchSuccessHandler =
+            new SimpleUrlAuthenticationSuccessHandler("/someOtherUrl");
+        switchSuccessHandler.setUseRelativeContext(true);
+        filter.setSuccessHandler(switchSuccessHandler);
         filter.setUserDetailsService(new MockUserDetailsService());
-        filter.setUseRelativeContext(true);
 
         filter.doFilter(request, response, new MockFilterChain(false));
 
@@ -308,7 +318,7 @@ public class SwitchUserProcessingFilterTests {
         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
         filter.setUserDetailsService(new MockUserDetailsService());
         filter.setSwitchUserUrl("/j_spring_security_switch_user");
-        filter.setTargetUrl("/webapp/someOtherUrl");
+        filter.setSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/webapp/someOtherUrl"));
 
         MockFilterChain chain = new MockFilterChain(true);