Commits

Sebastian Sdorra committed cef08c9

normalize urls for BaseUrlFilter to prevent redirect loops, see issue #311

Comments (0)

Files changed (4)

scm-core/src/main/java/sonia/scm/util/HttpUtil.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.common.base.Strings;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
   /** the logger for HttpUtil */
   private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);
 
+  /** Field description */
+  private static final Pattern PATTERN_URLNORMALIZE =
+    Pattern.compile("(?:(http://[^:]+):80(/.+)?|(https://[^:]+):443(/.+)?)");
+
   //~--- methods --------------------------------------------------------------
 
   /**
   }
 
   /**
+   * Returns the normalized url.
+   *
+   *
+   * @param url to normalize
+   *
+   * @return normalized url
+   *
+   * @since 1.26
+   */
+  public static String normalizeUrl(String url)
+  {
+    if (!Strings.isNullOrEmpty(url))
+    {
+      Matcher m = PATTERN_URLNORMALIZE.matcher(url);
+
+      if (m.matches())
+      {
+        String prefix = m.group(1);
+        String suffix;
+
+        if (prefix == null)
+        {
+          prefix = m.group(3);
+          suffix = m.group(4);
+        }
+        else
+        {
+          suffix = m.group(2);
+        }
+
+        if (suffix != null)
+        {
+          url = prefix.concat(suffix);
+        }
+        else
+        {
+          url = prefix;
+        }
+      }
+    }
+
+    return url;
+  }
+
+  /**
    * Method description
    *
    *

scm-core/src/test/java/sonia/scm/util/HttpUtilTest.java

    *
    */
   @Test
+  public void normalizeUrlTest()
+  {
+    assertEquals("http://www.scm-manager/scm",
+      HttpUtil.normalizeUrl("http://www.scm-manager/scm"));
+    assertEquals("http://www.scm-manager/scm",
+      HttpUtil.normalizeUrl("http://www.scm-manager:80/scm"));
+    assertEquals("https://www.scm-manager/scm",
+      HttpUtil.normalizeUrl("https://www.scm-manager:443/scm"));
+    assertEquals("https://www.scm-manager:8181/scm",
+      HttpUtil.normalizeUrl("https://www.scm-manager:8181/scm"));
+    assertEquals("http://www.scm-manager:8080/scm",
+      HttpUtil.normalizeUrl("http://www.scm-manager:8080/scm"));
+    assertEquals("http://www.scm-manager",
+      HttpUtil.normalizeUrl("http://www.scm-manager:80"));
+    assertEquals("https://www.scm-manager",
+      HttpUtil.normalizeUrl("https://www.scm-manager:443"));
+    assertEquals("http://www.scm-manager:8080",
+      HttpUtil.normalizeUrl("http://www.scm-manager:8080"));
+  }
+
+  //~--- get methods ----------------------------------------------------------
+
+  /**
+   * Method description
+   *
+   */
+  @Test
   public void getCompleteUrlTest()
   {
     ScmConfiguration config = new ScmConfiguration();
 
     config.setBaseUrl("http://www.scm-manager.org/scm");
     assertEquals("http://www.scm-manager.org/scm/test/path",
-                 HttpUtil.getCompleteUrl(config, "test/path"));
+      HttpUtil.getCompleteUrl(config, "test/path"));
     assertEquals("http://www.scm-manager.org/scm/test/path",
-                 HttpUtil.getCompleteUrl(config, "/test/path"));
+      HttpUtil.getCompleteUrl(config, "/test/path"));
   }
 
   /**
     assertTrue(HttpUtil.getPortFromUrl("http://www.scm-manager.org") == 80);
     assertTrue(HttpUtil.getPortFromUrl("https://www.scm-manager.org") == 443);
     assertTrue(HttpUtil.getPortFromUrl("http://www.scm-manager.org:8080")
-               == 8080);
+      == 8080);
     assertTrue(
-        HttpUtil.getPortFromUrl("http://www.scm-manager.org:8181/test/folder")
-        == 8181);
+      HttpUtil.getPortFromUrl("http://www.scm-manager.org:8181/test/folder")
+      == 8181);
   }
 
   /**
     when(request.getRequestURI()).thenReturn("/scm/test/path");
     when(request.getContextPath()).thenReturn("/scm");
     assertEquals("/test/path",
-                 HttpUtil.getStrippedURI(request, "/scm/test/path"));
+      HttpUtil.getStrippedURI(request, "/scm/test/path"));
     assertEquals("/test/path", HttpUtil.getStrippedURI(request));
   }
 
     assertEquals("/test", HttpUtil.getUriWithoutEndSeperator("/test/"));
     assertEquals("/test/two", HttpUtil.getUriWithoutEndSeperator("/test/two/"));
     assertEquals("/test/two/three",
-                 HttpUtil.getUriWithoutEndSeperator("/test/two/three"));
+      HttpUtil.getUriWithoutEndSeperator("/test/two/three"));
   }
 
   /**
   {
     assertEquals("test/", HttpUtil.getUriWithoutStartSeperator("/test/"));
     assertEquals("test/two/",
-                 HttpUtil.getUriWithoutStartSeperator("/test/two/"));
+      HttpUtil.getUriWithoutStartSeperator("/test/two/"));
     assertEquals("test/two/three",
-                 HttpUtil.getUriWithoutStartSeperator("test/two/three"));
+      HttpUtil.getUriWithoutStartSeperator("test/two/three"));
   }
 }

scm-webapp/src/main/java/sonia/scm/filter/BaseUrlFilter.java

 
 //~--- non-JDK imports --------------------------------------------------------
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
    * Method description
    *
    *
+   * @param requestUrl
+   * @param baseUrl
+   *
+   * @return
+   */
+  @VisibleForTesting
+  boolean startsWith(String requestUrl, String baseUrl)
+  {
+    return HttpUtil.normalizeUrl(requestUrl).startsWith(
+      HttpUtil.normalizeUrl(baseUrl));
+  }
+
+  /**
+   * Method description
+   *
+   *
    * @param request
    * @param response
    * @param chain
    */
   @Override
   protected void doFilter(HttpServletRequest request,
-                          HttpServletResponse response, FilterChain chain)
-          throws IOException, ServletException
+    HttpServletResponse response, FilterChain chain)
+    throws IOException, ServletException
   {
     if (Util.isEmpty(configuration.getBaseUrl()))
     {
    */
   private boolean isBaseUrl(HttpServletRequest request)
   {
-    return request.getRequestURL().toString().startsWith(
-        configuration.getBaseUrl());
+    return startsWith(request.getRequestURL().toString(),
+      configuration.getBaseUrl());
   }
 
   //~--- fields ---------------------------------------------------------------

scm-webapp/src/test/java/sonia/scm/filter/BaseUrlFilterTest.java

+/**
+ * Copyright (c) 2010, Sebastian Sdorra All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. 2. Redistributions in
+ * binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution. 3. Neither the name of SCM-Manager;
+ * nor the names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.filter;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.junit.Test;
+
+import sonia.scm.config.ScmConfiguration;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class BaseUrlFilterTest
+{
+
+  /**
+   * Method description
+   *
+   */
+  @Test
+  public void startsWithTest()
+  {
+    BaseUrlFilter filter = new BaseUrlFilter(new ScmConfiguration());
+
+    assertTrue(filter.startsWith("http://www.scm-manager.org/scm",
+      "http://www.scm-manager.org/scm"));
+    assertTrue(filter.startsWith("http://www.scm-manager.org:80/scm",
+      "http://www.scm-manager.org/scm"));
+    assertTrue(filter.startsWith("https://www.scm-manager.org/scm",
+      "https://www.scm-manager.org:443/scm"));
+    assertFalse(filter.startsWith("http://www.scm-manager.org/acb",
+      "http://www.scm-manager.org/scm"));
+  }
+}