Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 328AE200C73 for ; Wed, 10 May 2017 23:04:45 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 2A546160BB4; Wed, 10 May 2017 21:04:45 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id EEFC1160B99 for ; Wed, 10 May 2017 23:04:43 +0200 (CEST) Received: (qmail 761 invoked by uid 500); 10 May 2017 21:04:43 -0000 Mailing-List: contact commits-help@archiva.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@archiva.apache.org Delivered-To: mailing list commits@archiva.apache.org Received: (qmail 751 invoked by uid 99); 10 May 2017 21:04:43 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 10 May 2017 21:04:43 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 11C1EDFBC8; Wed, 10 May 2017 21:04:43 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: martin_s@apache.org To: commits@archiva.apache.org Message-Id: <027073cf05f0402e85a6b2e5e257353a@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: archiva-redback-core git commit: Fixing X-Forwarded-Host header handling Date: Wed, 10 May 2017 21:04:43 +0000 (UTC) archived-at: Wed, 10 May 2017 21:04:45 -0000 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 Authored: Wed May 10 22:59:51 2017 +0200 Committer: Martin Stockhammer 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. - * + *

* 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 urls = new ArrayList(); - 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 urls = new ArrayList(); - 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 urls = new ArrayList(); - 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() ); } }