Explorar o código

SEC-1255: Modified UrlUtils. Full request URL for redirects uses the requestURI (which is encoded). The URL for path comparsions is built using the servletpath, as before.

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

+ 0 - 9
config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java

@@ -1056,14 +1056,5 @@ public class HttpSecurityBeanDefinitionParserTests {
         return ((RememberMeProcessingFilter)getFilter(RememberMeProcessingFilter.class)).getRememberMeServices();
     }
 
-//    @SuppressWarnings("unchecked")
-//    private ConcurrentSessionController getConcurrentSessionController() {
-//        Map beans = appContext.getBeansOfType(ConcurrentSessionController.class);
-//
-//        if (beans.size() == 0) {
-//            return null;
-//        }
-//        return (ConcurrentSessionController) new ArrayList(beans.values()).get(0);
-//    }
 
 }

+ 0 - 19
itest/web/src/main/webapp/WEB-INF/custom-filters.xml

@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-    xmlns:sec="http://www.springframework.org/schema/security"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
-                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
-
-    <!-- A second APF in addition to the standard namespace one -->
-    <bean name="formLoginFilter2" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter">
-        <sec:custom-filter after="AUTHENTICATION_PROCESSING_FILTER"/>
-        <property name="filterProcessesUrl" value="/j_spring_security_check_2"/>
-    </bean>
-
-
-    <bean name="switchUserFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserProcessingFilter">
-        <sec:custom-filter position="SWITCH_USER_FILTER"/>
-    </bean>
-</beans>

+ 12 - 0
itest/web/src/main/webapp/secure/file?with?special?chars.html

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html
+     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <title>Special Chars File</title>
+  </head>
+  <body>
+    <p>I'm file?with?special?chars.html</p>
+  </body>
+</html>

+ 9 - 1
itest/web/src/test/java/org/springframework/security/integration/InMemoryProviderWebAppTests.java

@@ -1,6 +1,6 @@
 package org.springframework.security.integration;
 
-import org.testng.annotations.*;
+import org.testng.annotations.Test;
 
 /**
  * @author Luke Taylor
@@ -39,4 +39,12 @@ public class InMemoryProviderWebAppTests extends AbstractWebServerIntegrationTes
         assertTextPresent("xcount=2");
     }
 
+    // SEC-1255
+    @Test
+    public void redirectToUrlWithSpecialCharsInFilenameWorksOk() throws Exception {
+        beginAt("secure/file%3Fwith%3Fspecial%3Fchars.html?someArg=1");
+        login("jimi", "jimispassword");
+        assertTextPresent("I'm file?with?special?chars.html");
+    }
+
 }

+ 1 - 2
web/src/main/java/org/springframework/security/web/savedrequest/DefaultSavedRequest.java

@@ -234,8 +234,7 @@ public class DefaultSavedRequest implements SavedRequest {
      * @return the full URL of this request
      */
     public String getRedirectUrl() {
-        return UrlUtils.buildFullRequestUrl(scheme, serverName, serverPort, contextPath, servletPath, requestURI,
-                pathInfo, queryString);
+        return UrlUtils.buildFullRequestUrl(scheme, serverName, serverPort, requestURI, queryString);
     }
 
     public Collection<String> getHeaderNames() {

+ 39 - 24
web/src/main/java/org/springframework/security/web/util/UrlUtils.java

@@ -29,8 +29,8 @@ public final class UrlUtils {
     //~ Methods ========================================================================================================
 
     public static String buildFullRequestUrl(HttpServletRequest r) {
-        return buildFullRequestUrl(r.getScheme(), r.getServerName(), r.getServerPort(), r.getContextPath(),
-            r.getServletPath(), r.getRequestURI(), r.getPathInfo(), r.getQueryString());
+        return buildFullRequestUrl(r.getScheme(), r.getServerName(), r.getServerPort(), r.getRequestURI(),
+                r.getQueryString());
     }
 
     /**
@@ -39,29 +39,53 @@ public final class UrlUtils {
      * Note that the server port will not be shown if it is the default server port for HTTP or HTTPS
      * (80 and 443 respectively).
      *
-     * @return the full URL
+     * @return the full URL, suitable for redirects (not decoded).
      */
-    public static String buildFullRequestUrl(String scheme, String serverName, int serverPort, String contextPath,
-        String servletPath, String requestURI, String pathInfo, String queryString) {
+    public static String buildFullRequestUrl(String scheme, String serverName, int serverPort, String requestURI,
+            String queryString) {
 
-        boolean includePort = true;
+        scheme = scheme.toLowerCase();
 
-        if ("http".equals(scheme.toLowerCase()) && (serverPort == 80)) {
-            includePort = false;
+        StringBuilder url = new StringBuilder();
+        url.append(scheme).append("://").append(serverName);
+
+        // Only add port if not default
+        if ("http".equals(scheme)) {
+            if (serverPort != 80) {
+                url.append(":").append(serverPort);
+            }
+        } else if ("https".equals(scheme)) {
+            if (serverPort != 443) {
+                url.append(":").append(serverPort);
+            }
         }
 
-        if ("https".equals(scheme.toLowerCase()) && (serverPort == 443)) {
-            includePort = false;
+        // Use the requestURI as it is encoded (RFC 3986) and hence suitable for redirects.
+        url.append(requestURI);
+
+        if (queryString != null) {
+            url.append("?").append(queryString);
         }
 
-        return scheme + "://" + serverName + ((includePort) ? (":" + serverPort) : "") + contextPath
-                + buildRequestUrl(servletPath, requestURI, contextPath, pathInfo, queryString);
+        return url.toString();
     }
 
     /**
      * Obtains the web application-specific fragment of the request URL.
+     * <p>
+     * Under normal spec conditions,
+     * <pre>
+     * requestURI = contextPath + servletPath + pathInfo
+     * </pre>
+     *
+     * But the requestURI is not decoded, whereas the servletPath and pathInfo are (SEC-1255).
+     * This method is typically used to return a URL for matching against secured paths, hence the decoded form is
+     * used in preference to the requestURI for building the returned value. But this method may also be called using
+     * dummy request objects which just have the requestURI and contextPatth set, for example, so it will fall back to
+     * using those.
+     *
+     * @return the decoded URL, excluding any server name, context path or servlet path
      *
-     * @return the URL, excluding any server name, context path or servlet path
      */
     public static String buildRequestUrl(HttpServletRequest r) {
         return buildRequestUrl(r.getServletPath(), r.getRequestURI(), r.getContextPath(), r.getPathInfo(),
@@ -70,18 +94,9 @@ public final class UrlUtils {
 
     /**
      * Obtains the web application-specific fragment of the URL.
-     * <p>
-     * Under normal spec conditions,
-     * <pre>
-     * requestURI = contextPath + servletPath + pathInfo
-     * </pre>
-     *
-     * But this method may also be called using dummy request objects which just have the requestURI and contextPath
-     * set, for example.
-     *
-     * @return the URL, excluding any server name, context path or servlet path
+
      */
-    public static String buildRequestUrl(String servletPath, String requestURI, String contextPath, String pathInfo,
+    private static String buildRequestUrl(String servletPath, String requestURI, String contextPath, String pathInfo,
         String queryString) {
 
         StringBuilder url = new StringBuilder();