Explorar o código

SEC-1226: Introduce RedirectStrategy to replace RedirectUtils. Implemented strategy and applied throughout relevant classes.

Luke Taylor %!s(int64=16) %!d(string=hai) anos
pai
achega
ab0d66071a

+ 8 - 6
openid/src/main/java/org/springframework/security/openid/OpenIDAuthenticationProcessingFilter.java

@@ -167,15 +167,17 @@ public class OpenIDAuthenticationProcessingFilter extends AbstractAuthentication
 
         if (mapping == null) {
             try {
-
                 URL url = new URL(returnToUrl);
-                int port = (url.getPort() == -1) ? 80 : url.getPort();
-                StringBuffer realmBuffer = new StringBuffer(returnToUrl.length())
+                int port = url.getPort();
+
+                StringBuilder realmBuffer = new StringBuilder(returnToUrl.length())
                         .append(url.getProtocol())
                         .append("://")
-                        .append(url.getHost())
-                        .append(":").append(port)
-                        .append("/");
+                        .append(url.getHost());
+                if (port > 0) {
+                    realmBuffer.append(":").append(port);
+                }
+                realmBuffer.append("/");
                 mapping = realmBuffer.toString();
             } catch (MalformedURLException e) {
                 logger.warn("returnToUrl was not a valid URL: [" + returnToUrl + "]", e);

+ 58 - 0
web/src/main/java/org/springframework/security/web/DefaultRedirectStrategy.java

@@ -0,0 +1,58 @@
+package org.springframework.security.web;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Simple implementation of <tt>RedirectStrategy</tt> which is the default used throughout the framework.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 3.0
+ */
+public class DefaultRedirectStrategy implements RedirectStrategy {
+    private boolean useRelativeContext;
+
+    /**
+     * Redirects the response to the supplied URL.
+     * <p>
+     * If <tt>useRelativeContext</tt> is set, the redirect value will be the value after the request context path.
+     */
+    public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
+        String finalUrl;
+        if (!url.startsWith("http://") && !url.startsWith("https://")) {
+            if (useRelativeContext) {
+                finalUrl = url;
+            }
+            else {
+                finalUrl = request.getContextPath() + url;
+            }
+        }
+        else if (useRelativeContext) {
+            // Calculate the relative URL from the fully qualifed URL, minus the protocol and base context.
+            int len = request.getContextPath().length();
+            int index = url.indexOf(request.getContextPath()) + len;
+            finalUrl = url.substring(index);
+
+            if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') {
+                finalUrl = finalUrl.substring(1);
+            }
+        }
+        else {
+            finalUrl = url;
+        }
+
+        response.sendRedirect(response.encodeRedirectURL(finalUrl));
+    }
+
+    /**
+     * If <tt>true</tt>, causes any redirection URLs to be calculated minus the protocol
+     * and context path (defaults to <tt>false</tt>).
+     */
+    public void setUseRelativeContext(boolean useRelativeContext) {
+        this.useRelativeContext = useRelativeContext;
+    }
+
+}

+ 24 - 0
web/src/main/java/org/springframework/security/web/RedirectStrategy.java

@@ -0,0 +1,24 @@
+package org.springframework.security.web;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Encapsulates the redirection logic for all classes in the framework which perform redirects.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 3.0
+ */
+public interface RedirectStrategy {
+
+    /**
+     * Performs a redirect to the supplied URL
+     * @param request the current request
+     * @param response the response to redirect
+     * @param url the target URL to redirect to, for example "/login"
+     */
+    void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException;
+}

+ 9 - 9
web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationTargetUrlRequestHandler.java

@@ -11,7 +11,8 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.web.util.RedirectUtils;
+import org.springframework.security.web.DefaultRedirectStrategy;
+import org.springframework.security.web.RedirectStrategy;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
@@ -50,8 +51,8 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
     private String targetUrlParameter = DEFAULT_TARGET_PARAMETER;
     private String defaultTargetUrl = "/";
     private boolean alwaysUseDefaultTargetUrl = false;
-    private boolean useRelativeContext = false;
     private boolean useReferer = false;
+    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
 
     protected AbstractAuthenticationTargetUrlRequestHandler() {
     }
@@ -60,7 +61,7 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
             throws IOException, ServletException {
         String targetUrl = determineTargetUrl(request, response);
 
-        RedirectUtils.sendRedirect(request, response, targetUrl, useRelativeContext);
+        redirectStrategy.sendRedirect(request, response, targetUrl);
     }
 
     private String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
@@ -149,15 +150,14 @@ public abstract class AbstractAuthenticationTargetUrlRequestHandler {
     }
 
     /**
-     * If <tt>true</tt>, causes any redirection URLs to be calculated minus the protocol
-     * and context path (defaults to <tt>false</tt>).
+     * Allows overriding of the behaviour when redirecting to a target URL.
      */
-    public void setUseRelativeContext(boolean useRelativeContext) {
-        this.useRelativeContext = useRelativeContext;
+    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
+        this.redirectStrategy = redirectStrategy;
     }
 
-    protected boolean isUseRelativeContext() {
-        return useRelativeContext;
+    protected RedirectStrategy getRedirectStrategy() {
+        return redirectStrategy;
     }
 
     /**

+ 1 - 2
web/src/main/java/org/springframework/security/web/authentication/ExceptionMappingAuthenticationFailureHandler.java

@@ -9,7 +9,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.util.RedirectUtils;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.util.Assert;
 
@@ -35,7 +34,7 @@ public class ExceptionMappingAuthenticationFailureHandler extends SimpleUrlAuthe
         String url = failureUrlMap.get(exception.getClass().getName());
 
         if (url != null) {
-            RedirectUtils.sendRedirect(request, response, url, isUseRelativeContext());
+            getRedirectStrategy().sendRedirect(request, response, url);
         } else {
             super.onAuthenticationFailure(request, response, exception);
         }

+ 19 - 15
web/src/main/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.java

@@ -17,31 +17,30 @@ package org.springframework.security.web.authentication;
 
 
 
+import java.io.IOException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.DefaultRedirectStrategy;
 import org.springframework.security.web.PortMapper;
 import org.springframework.security.web.PortMapperImpl;
 import org.springframework.security.web.PortResolver;
 import org.springframework.security.web.PortResolverImpl;
+import org.springframework.security.web.RedirectStrategy;
 import org.springframework.security.web.access.ExceptionTranslationFilter;
 import org.springframework.security.web.util.RedirectUrlBuilder;
 import org.springframework.security.web.util.UrlUtils;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.beans.factory.InitializingBean;
-
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
-import java.io.IOException;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 /**
  * Used by the {@link ExceptionTranslationFilter} to commence a form login
  * authentication via the {@link UsernamePasswordAuthenticationProcessingFilter}. This object
@@ -80,6 +79,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
 
     private boolean useForward = false;
 
+    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
+
     //~ Methods ========================================================================================================
 
     public void afterPropertiesSet() throws Exception {
@@ -117,6 +118,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
         if (useForward) {
 
             if (forceHttps && "http".equals(request.getScheme())) {
+                // First redirect the current request to HTTPS.
+                // When that request is received, the forward to the login page will be used.
                 redirectUrl = buildHttpsRedirectUrlForRequest(httpRequest);
             }
 
@@ -140,7 +143,7 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
 
         }
 
-        httpResponse.sendRedirect(httpResponse.encodeRedirectURL(redirectUrl));
+        redirectStrategy.sendRedirect(httpRequest, httpResponse, redirectUrl);
     }
 
     protected String buildRedirectUrlToLoginPage(HttpServletRequest request, HttpServletResponse response,
@@ -174,7 +177,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
     }
 
     /**
-     * Builds a URL to redirect the supplied request to HTTPS.
+     * Builds a URL to redirect the supplied request to HTTPS. Used to redirect the current request
+     * to HTTPS, before doing a forward to the login page.
      */
     protected String buildHttpsRedirectUrlForRequest(HttpServletRequest request)
             throws IOException, ServletException {

+ 1 - 2
web/src/main/java/org/springframework/security/web/authentication/SavedRequestAwareAuthenticationSuccessHandler.java

@@ -13,7 +13,6 @@ import org.springframework.security.web.access.ExceptionTranslationFilter;
 import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
 import org.springframework.security.web.savedrequest.RequestCache;
 import org.springframework.security.web.savedrequest.SavedRequest;
-import org.springframework.security.web.util.RedirectUtils;
 import org.springframework.util.StringUtils;
 
 /**
@@ -76,7 +75,7 @@ public class SavedRequestAwareAuthenticationSuccessHandler extends SimpleUrlAuth
         // Use the SavedRequest URL
         String targetUrl = savedRequest.getFullRequestUrl();
         logger.debug("Redirecting to SavedRequest Url: " + targetUrl);
-        RedirectUtils.sendRedirect(request, response, targetUrl, isUseRelativeContext());
+        getRedirectStrategy().sendRedirect(request, response, targetUrl);
     }
 
     public void setRequestCache(RequestCache requestCache) {

+ 10 - 11
web/src/main/java/org/springframework/security/web/authentication/SimpleUrlAuthenticationFailureHandler.java

@@ -7,7 +7,8 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.util.RedirectUtils;
+import org.springframework.security.web.DefaultRedirectStrategy;
+import org.springframework.security.web.RedirectStrategy;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.util.Assert;
 
@@ -27,7 +28,7 @@ import org.springframework.util.Assert;
 public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler {
     private String defaultFailureUrl;
     private boolean forwardToDestination = false;
-    private boolean useRelativeContext = false;
+    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
 
     public SimpleUrlAuthenticationFailureHandler() {
     }
@@ -44,7 +45,7 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
             if (forwardToDestination) {
                 request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
             } else {
-                RedirectUtils.sendRedirect(request, response, defaultFailureUrl, useRelativeContext);
+                redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
             }
         }
     }
@@ -71,16 +72,14 @@ public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFail
         this.forwardToDestination = forwardToDestination;
     }
 
-    protected boolean isUseRelativeContext() {
-        return useRelativeContext;
-    }
-
     /**
-     * If true, causes any redirection URLs to be calculated minus the protocol
-     * and context path (defaults to false).
+     * Allows overriding of the behaviour when redirecting to a target URL.
      */
-    public void setUseRelativeContext(boolean useRelativeContext) {
-        this.useRelativeContext = useRelativeContext;
+    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
+        this.redirectStrategy = redirectStrategy;
     }
 
+    protected RedirectStrategy getRedirectStrategy() {
+        return redirectStrategy;
+    }
 }

+ 0 - 62
web/src/main/java/org/springframework/security/web/util/RedirectUtils.java

@@ -1,62 +0,0 @@
-package org.springframework.security.web.util;
-
-import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
-import org.springframework.security.web.authentication.logout.LogoutFilter;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * @author Luke Taylor
- * @version $Id$
- */
-public abstract class RedirectUtils {
-    //~ Constructors ===================================================================================================
-
-    private RedirectUtils() {
-    }
-
-    //~ Methods ========================================================================================================
-
-    /**
-     * Encapsulates the redirect logic used in classes like {@link AbstractAuthenticationProcessingFilter} and {@link LogoutFilter}.
-     *
-     * @param request the incoming request
-     * @param response the response to redirect
-     * @param url the target url to redirect to
-     * @param useRelativeContext if true, causes any redirection URLs to be calculated minus the protocol
-     * and context path.
-     *
-     * @see AbstractAuthenticationProcessingFilter#setUseRelativeContext(boolean)
-     */
-    public static final void sendRedirect(HttpServletRequest request,
-                                          HttpServletResponse response,
-                                          String url,
-                                          boolean useRelativeContext) throws IOException {
-        String finalUrl;
-        if (!url.startsWith("http://") && !url.startsWith("https://")) {
-            if (useRelativeContext) {
-                finalUrl = url;
-            }
-            else {
-                finalUrl = request.getContextPath() + url;
-            }
-        }
-        else if (useRelativeContext) {
-            // Calculate the relative URL from the fully qualifed URL, minus the protocol and base context.
-            int len = request.getContextPath().length();
-            int index = url.indexOf(request.getContextPath()) + len;
-            finalUrl = url.substring(index);
-
-            if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') {
-                finalUrl = finalUrl.substring(1);
-            }
-        }
-        else {
-            finalUrl = url;
-        }
-
-        response.sendRedirect(response.encodeRedirectURL(finalUrl));
-    }
-}

+ 4 - 1
web/src/test/java/org/springframework/security/web/authentication/switchuser/SwitchUserProcessingFilterTests.java

@@ -43,6 +43,7 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.util.FieldUtils;
+import org.springframework.security.web.DefaultRedirectStrategy;
 import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.switchuser.SwitchUserAuthorityChanger;
 import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority;
@@ -306,7 +307,9 @@ public class SwitchUserProcessingFilterTests {
         filter.setSwitchUserUrl("/j_spring_security_switch_user");
         SimpleUrlAuthenticationSuccessHandler switchSuccessHandler =
             new SimpleUrlAuthenticationSuccessHandler("/someOtherUrl");
-        switchSuccessHandler.setUseRelativeContext(true);
+        DefaultRedirectStrategy contextRelativeRedirector = new DefaultRedirectStrategy();
+        contextRelativeRedirector.setUseRelativeContext(true);
+        switchSuccessHandler.setRedirectStrategy(contextRelativeRedirector);
         filter.setSuccessHandler(switchSuccessHandler);
         filter.setUserDetailsService(new MockUserDetailsService());