You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@archiva.apache.org by ma...@apache.org on 2017/05/10 21:04:43 UTC

archiva-redback-core git commit: Fixing X-Forwarded-Host header handling

Repository: archiva-redback-core
Updated Branches:
  refs/heads/master 396694765 -> 4e4e3428c


Fixing X-Forwarded-Host header handling


Project: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/commit/4e4e3428
Tree: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/tree/4e4e3428
Diff: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/diff/4e4e3428

Branch: refs/heads/master
Commit: 4e4e3428c4f7db396f36cc169c2a67c0d05ea6e7
Parents: 3966947
Author: Martin Stockhammer <ma...@apache.org>
Authored: Wed May 10 22:59:51 2017 +0200
Committer: Martin Stockhammer <ma...@apache.org>
Committed: Wed May 10 22:59:51 2017 +0200

----------------------------------------------------------------------
 .../RequestValidationInterceptor.java           |  28 ++-
 .../RequestValidationInterceptorTest.java       | 249 ++++++++++++-------
 2 files changed, 175 insertions(+), 102 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/4e4e3428/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java
----------------------------------------------------------------------
diff --git a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java
index 0351348..2b8f1c6 100644
--- a/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java
+++ b/redback-integrations/redback-rest/redback-rest-services/src/main/java/org/apache/archiva/redback/rest/services/interceptors/RequestValidationInterceptor.java
@@ -31,6 +31,7 @@ import org.apache.archiva.redback.integration.filter.authentication.basic.HttpBa
 import org.apache.archiva.redback.policy.AccountLockedException;
 import org.apache.archiva.redback.policy.MustChangePasswordException;
 import org.apache.archiva.redback.users.User;
+import org.apache.commons.lang.StringUtils;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.message.Message;
 import org.slf4j.Logger;
@@ -343,7 +344,7 @@ public class RequestValidationInterceptor
                     catch ( MalformedURLException ex )
                     {
                         log.error( "Configured baseUrl (rest.baseUrl={}) is invalid. Message: {}", baseUrlStr,
-                                   ex.getMessage() );
+                            ex.getMessage() );
                     }
                 }
             }
@@ -405,7 +406,7 @@ public class RequestValidationInterceptor
             if ( noHeader && denyAbsentHeaders )
             {
                 log.warn( "Request denied. No Origin or Referer header found and {}=true",
-                          UserConfigurationKeys.REST_CSRF_ABSENTORIGIN_DENY );
+                    UserConfigurationKeys.REST_CSRF_ABSENTORIGIN_DENY );
                 containerRequestContext.abortWith( Response.status( Response.Status.FORBIDDEN ).build() );
                 return;
             }
@@ -483,7 +484,7 @@ public class RequestValidationInterceptor
                 if ( !td.isValid() || !td.getUser().equals( username ) )
                 {
                     log.error( "Invalid data in validation token header {} for user {}: isValid={}, username={}",
-                               X_XSRF_TOKEN, username, td.isValid(), td.getUser() );
+                        X_XSRF_TOKEN, username, td.isValid(), td.getUser() );
                     containerRequestContext.abortWith( Response.status( Response.Status.FORBIDDEN ).build() );
                 }
             }
@@ -535,15 +536,22 @@ public class RequestValidationInterceptor
             {
                 xforwardedProto = requestUrl.getProtocol();
             }
-            if ( xforwarded != null )
+
+            if ( xforwarded != null && !StringUtils.isEmpty( xforwarded ) )
             {
-                try
-                {
-                    urls.add( new URL( xforwardedProto + "://" + xforwarded ) );
-                }
-                catch ( MalformedURLException ex )
+                // X-Forwarded-Host header may contain multiple hosts if there is
+                // more than one proxy between the client and the server
+                String[] forwardedList = xforwarded.split( "\\s*,\\s*" );
+                for ( String hostname : forwardedList )
                 {
-                    log.warn( "X-Forwarded-Host Header is malformed: {}", ex.getMessage() );
+                    try
+                    {
+                        urls.add( new URL( xforwardedProto + "://" + hostname ) );
+                    }
+                    catch ( MalformedURLException ex )
+                    {
+                        log.warn( "X-Forwarded-Host Header is malformed: {}", ex.getMessage() );
+                    }
                 }
             }
             return urls;

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/4e4e3428/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java
----------------------------------------------------------------------
diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java
index aad961a..4668c4a 100644
--- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java
+++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/RequestValidationInterceptorTest.java
@@ -38,169 +38,234 @@ import java.util.List;
 
 /**
  * Created by Martin Stockhammer on 21.01.17.
- *
+ * <p>
  * Unit Test for RequestValidationInterceptor. The unit tests are all without token validation.
- *
  */
-@RunWith(JUnit4.class)
-public class RequestValidationInterceptorTest extends TestCase {
-
+@RunWith( JUnit4.class )
+public class RequestValidationInterceptorTest extends TestCase
+{
 
 
     @Test
-    public void validateRequestWithoutHeader() throws UserConfigurationException, IOException {
+    public void validateRequestWithoutHeader() throws UserConfigurationException, IOException
+    {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
         MockHttpServletRequest request = new MockHttpServletRequest();
-        interceptor.setHttpRequest(request);
+        interceptor.setHttpRequest( request );
+        interceptor.init();
+        MockContainerRequestContext ctx = new MockContainerRequestContext();
+        interceptor.filter( ctx );
+        assertTrue( ctx.isAborted() );
+    }
+
+    @Test
+    public void validateRequestWithOrigin() throws UserConfigurationException, IOException
+    {
+        TokenManager tm = new TokenManager();
+        MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "test.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        interceptor.setHttpRequest( request );
+        interceptor.init();
+        MockContainerRequestContext ctx = new MockContainerRequestContext();
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
+    }
+
+    @Test
+    public void validateRequestWithBadOrigin() throws UserConfigurationException, IOException
+    {
+        TokenManager tm = new TokenManager();
+        MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "test.archiva.org" );
+        request.addHeader( "Origin", "http://test2.archiva.org/myservlet" );
+        interceptor.setHttpRequest( request );
+        interceptor.init();
+        MockContainerRequestContext ctx = new MockContainerRequestContext();
+        interceptor.filter( ctx );
+        assertTrue( ctx.isAborted() );
+    }
+
+    @Test
+    public void validateRequestWithReferer() throws UserConfigurationException, IOException
+    {
+        TokenManager tm = new TokenManager();
+        MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "test.archiva.org" );
+        request.addHeader( "Referer", "http://test.archiva.org/myservlet2" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertTrue(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
     }
 
     @Test
-    public void validateRequestWithOrigin() throws UserConfigurationException, IOException {
+    public void validateRequestWithBadReferer() throws UserConfigurationException, IOException
+    {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("test.archiva.org");
-        request.addHeader("Origin","http://test.archiva.org/myservlet");
-        interceptor.setHttpRequest(request);
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "test.archiva.org" );
+        request.addHeader( "Referer", "http://test3.archiva.org/myservlet2" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertFalse(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertTrue( ctx.isAborted() );
     }
 
     @Test
-    public void validateRequestWithBadOrigin() throws UserConfigurationException, IOException {
+    public void validateRequestWithOriginAndReferer() throws UserConfigurationException, IOException
+    {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("test.archiva.org");
-        request.addHeader("Origin","http://test2.archiva.org/myservlet");
-        interceptor.setHttpRequest(request);
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "test.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        request.addHeader( "Referer", "http://test.archiva.org/myservlet2" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertTrue(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
     }
 
     @Test
-    public void validateRequestWithReferer() throws UserConfigurationException, IOException {
+    public void validateRequestWithOriginAndRefererAndXForwarded() throws UserConfigurationException, IOException
+    {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("test.archiva.org");
-        request.addHeader("Referer","http://test.archiva.org/myservlet2");
-        interceptor.setHttpRequest(request);
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "xxx.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        request.addHeader( "Referer", "http://test.archiva.org/myservlet2" );
+        request.addHeader( "X-Forwarded-Host", "test.archiva.org" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertFalse(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
     }
 
     @Test
-    public void validateRequestWithBadReferer() throws UserConfigurationException, IOException {
+    public void validateRequestWithOriginAndRefererAndWrongXForwarded() throws UserConfigurationException, IOException
+    {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("test.archiva.org");
-        request.addHeader("Referer","http://test3.archiva.org/myservlet2");
-        interceptor.setHttpRequest(request);
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "xxx.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        request.addHeader( "Referer", "http://test.archiva.org/myservlet2" );
+        request.addHeader( "X-Forwarded-Host", "test2.archiva.org" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertTrue(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertTrue( ctx.isAborted() );
     }
 
     @Test
-    public void validateRequestWithOriginAndReferer() throws UserConfigurationException, IOException {
+    public void validateRequestWithOriginAndRefererAndXForwardedMultiple() throws UserConfigurationException, IOException
+    {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("test.archiva.org");
-        request.addHeader("Origin","http://test.archiva.org/myservlet");
-        request.addHeader("Referer","http://test.archiva.org/myservlet2");
-        interceptor.setHttpRequest(request);
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "xxx.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        request.addHeader( "Referer", "http://test.archiva.org/myservlet2" );
+        request.addHeader( "X-Forwarded-Host", "my.proxy.org, test.archiva.org:80" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertFalse(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
     }
 
 
     @Test
-    public void validateRequestWithOriginAndStaticUrl() throws UserConfigurationException, IOException {
+    public void validateRequestWithOriginAndStaticUrl() throws UserConfigurationException, IOException
+    {
         MockUserConfiguration cfg = new MockUserConfiguration();
         List<String> urls = new ArrayList<String>();
-        urls.add("http://test.archiva.org");
-        cfg.addList("rest.baseUrl",urls);
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        urls.add( "http://test.archiva.org" );
+        cfg.addList( "rest.baseUrl", urls );
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
         TokenManager tm = new TokenManager();
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("test4.archiva.org");
-        request.addHeader("Origin","http://test.archiva.org/myservlet");
-        interceptor.setHttpRequest(request);
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "test4.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertFalse(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
     }
 
     @Test
-    public void validateRequestWithBadOriginAndStaticUrl() throws UserConfigurationException, IOException {
+    public void validateRequestWithBadOriginAndStaticUrl() throws UserConfigurationException, IOException
+    {
         MockUserConfiguration cfg = new MockUserConfiguration();
         List<String> urls = new ArrayList<String>();
-        urls.add("http://mytest.archiva.org");
-        cfg.addList("rest.baseUrl",urls);
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        urls.add( "http://mytest.archiva.org" );
+        cfg.addList( "rest.baseUrl", urls );
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
         TokenManager tm = new TokenManager();
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("mytest.archiva.org");
-        request.addHeader("Origin","http://test.archiva.org/myservlet");
-        interceptor.setHttpRequest(request);
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "mytest.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertTrue(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertTrue( ctx.isAborted() );
     }
 
 
     @Test
-    public void validateRequestWithOriginListAndStaticUrl() throws UserConfigurationException, IOException {
+    public void validateRequestWithOriginListAndStaticUrl() throws UserConfigurationException, IOException
+    {
         MockUserConfiguration cfg = new MockUserConfiguration();
         List<String> urls = new ArrayList<String>();
-        urls.add("http://mytest.archiva.org");
-        urls.add("http://mytest2.archiva.org");
-        urls.add("http://test.archiva.org");
-        cfg.addList("rest.baseUrl",urls);
-        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        urls.add( "http://mytest.archiva.org" );
+        urls.add( "http://mytest2.archiva.org" );
+        urls.add( "http://test.archiva.org" );
+        cfg.addList( "rest.baseUrl", urls );
+        cfg.addValue( UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, "true" );
         TokenManager tm = new TokenManager();
-        RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
-        MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
-        request.setServerName("mytest.archiva.org");
-        request.addHeader("Origin","http://test.archiva.org/myservlet");
-        interceptor.setHttpRequest(request);
+        RequestValidationInterceptor interceptor = new RequestValidationInterceptor( cfg );
+        MockHttpServletRequest request = new MockHttpServletRequest( "GET", "/api/v1/userService" );
+        request.setServerName( "mytest.archiva.org" );
+        request.addHeader( "Origin", "http://test.archiva.org/myservlet" );
+        interceptor.setHttpRequest( request );
         interceptor.init();
         MockContainerRequestContext ctx = new MockContainerRequestContext();
-        interceptor.filter(ctx);
-        assertFalse(ctx.isAborted());
+        interceptor.filter( ctx );
+        assertFalse( ctx.isAborted() );
     }
 
 }