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/04/27 22:30:16 UTC

archiva-redback-core git commit: Changing to list based request validation configuration

Repository: archiva-redback-core
Updated Branches:
  refs/heads/master 99a075f25 -> 1b13cbd01


Changing to list based request validation configuration


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/1b13cbd0
Tree: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/tree/1b13cbd0
Diff: http://git-wip-us.apache.org/repos/asf/archiva-redback-core/diff/1b13cbd0

Branch: refs/heads/master
Commit: 1b13cbd019f4d3c0e9f5b74d7bab68127bb81e09
Parents: 99a075f
Author: Martin Stockhammer <ma...@apache.org>
Authored: Tue Apr 25 20:46:04 2017 +0200
Committer: Martin Stockhammer <ma...@apache.org>
Committed: Fri Apr 28 00:29:50 2017 +0200

----------------------------------------------------------------------
 .../configuration/UserConfigurationKeys.java    |   7 +
 .../RequestValidationInterceptor.java           | 342 ++++++++++++++-----
 .../RequestValidationInterceptorTest.java       |  50 ++-
 .../services/mock/MockUserConfiguration.java    |  21 +-
 4 files changed, 319 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/1b13cbd0/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java
----------------------------------------------------------------------
diff --git a/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java b/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java
index a61802b..5bdde91 100644
--- a/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java
+++ b/redback-configuration/src/main/java/org/apache/archiva/redback/configuration/UserConfigurationKeys.java
@@ -162,4 +162,11 @@ public interface UserConfigurationKeys
 
     String POLICY_PASSWORD_RULE_NOWHITTESPACE_ENABLED = "security.policy.password.rule.nowhitespace.enabled";
 
+    String REST_BASE_URL = "rest.baseUrl";
+
+    String REST_CSRF_ABSENTORIGIN_DENY = "rest.csrffilter.absentorigin.deny";
+
+    String REST_CSRF_ENABLED = "rest.csrffilter.enabled";
+
+    String REST_CSRF_DISABLE_TOKEN_VALIDATION = "rest.csrffilter.disableTokenValidation";
 }

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/1b13cbd0/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 68c27dd..b36e8e4 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
@@ -26,6 +26,7 @@ import org.apache.archiva.redback.authentication.TokenData;
 import org.apache.archiva.redback.authentication.TokenManager;
 import org.apache.archiva.redback.authorization.RedbackAuthorization;
 import org.apache.archiva.redback.configuration.UserConfiguration;
+import org.apache.archiva.redback.configuration.UserConfigurationKeys;
 import org.apache.archiva.redback.integration.filter.authentication.basic.HttpBasicAuthentication;
 import org.apache.archiva.redback.policy.AccountLockedException;
 import org.apache.archiva.redback.policy.MustChangePasswordException;
@@ -47,6 +48,8 @@ import javax.ws.rs.ext.Provider;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Created by Martin Stockhammer on 19.01.17.
@@ -73,10 +76,8 @@ public class RequestValidationInterceptor extends AbstractInterceptor implements
     private static final String X_XSRF_TOKEN = "X-XSRF-TOKEN";
     private static final String ORIGIN = "Origin";
     private static final String REFERER = "Referer";
-    public static final String CFG_REST_BASE_URL = "rest.baseUrl";
-    public static final String CFG_REST_CSRF_ABSENTORIGIN_DENY = "rest.csrffilter.absentorigin.deny";
-    public static final String CFG_REST_CSRF_ENABLED = "rest.csrffilter.enabled";
-    public static final String CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION = "rest.csrffilter.disableTokenValidation";
+    private static final int DEFAULT_HTTP = 80;
+    private static final int DEFAULT_HTTPS = 443;
 
     private final Logger log = LoggerFactory.getLogger( getClass() );
 
@@ -84,11 +85,9 @@ public class RequestValidationInterceptor extends AbstractInterceptor implements
     private boolean checkToken = true;
     private boolean useStaticUrl = false;
     private boolean denyAbsentHeaders = true;
-    private URL baseUrl;
+    private List<URL> baseUrl = new ArrayList<URL>();
     private HttpServletRequest httpRequest = null;
 
-    private UserConfiguration config;
-
     @Inject
     @Named( value = "httpAuthenticator#basic" )
     private HttpBasicAuthentication httpAuthenticator;
@@ -97,31 +96,197 @@ public class RequestValidationInterceptor extends AbstractInterceptor implements
     @Named( value = "tokenManager#default")
     TokenManager tokenManager;
 
+    private UserConfiguration config;
+    
+    private class HeaderValidationInfo {
+
+        final static int UNKNOWN = -1;
+        final static int OK = 0;
+        final static int F_REFERER_HOST = 1;
+        final static int F_REFERER_PORT = 2;
+        final static int F_ORIGIN_HOST = 8;
+        final static int F_ORIGIN_PORT = 16;
+        final static int F_ORIGIN_PROTOCOL = 32;
+        boolean headerFound = false;
+
+        URL targetUrl;
+        URL originUrl;
+        URL refererUrl;
+        
+        String targetHost;
+        String originHost;
+        String refererHost;
+        
+        int targetPort;
+        int originPort;
+        int refererPort;
+
+        int status = UNKNOWN;
+        
+        public HeaderValidationInfo(URL targetUrl) {
+            setTargetUrl(targetUrl);
+        }
+
+        public URL getTargetUrl() {
+            return targetUrl;
+        }
+
+        public void setTargetUrl(URL targetUrl) {
+            this.targetUrl = targetUrl;
+            this.targetHost=getHost(targetUrl);
+            this.targetPort=getPort(targetUrl);
+        }
+
+        public URL getOriginUrl() {
+            return originUrl;
+        }
+
+        public void setOriginUrl(URL originUrl) {
+            this.originUrl=originUrl;
+            this.originHost=getHost(originUrl);
+            this.originPort=getPort(originUrl);
+            checkOrigin();
+            this.headerFound=true;
+        }
+
+        public URL getRefererUrl() {
+            return refererUrl;
+        }
+
+        public void setRefererUrl(URL refererUrl) {
+            this.refererUrl=refererUrl;
+            this.refererHost=getHost(refererUrl);
+            this.refererPort=getPort(refererUrl);
+            checkReferer();
+            this.headerFound=true;
+        }
+
+        public String getTargetHost() {
+            return targetHost;
+        }
+
+        public void setTargetHost(String targetHost) {
+            this.targetHost = targetHost;
+        }
+
+        public String getOriginHost() {
+            return originHost;
+        }
+
+        public void setOriginHost(String originHost) {
+            this.originHost = originHost;
+        }
+
+        public String getRefererHost() {
+            return refererHost;
+        }
+
+        public void setRefererHost(String refererHost) {
+            this.refererHost = refererHost;
+        }
+
+        public int getTargetPort() {
+            return targetPort;
+        }
+
+        public void setTargetPort(int targetPort) {
+            this.targetPort = targetPort;
+        }
+
+        public int getOriginPort() {
+            return originPort;
+        }
+
+        public void setOriginPort(int originPort) {
+            this.originPort = originPort;
+        }
+
+        public int getRefererPort() {
+            return refererPort;
+        }
+
+        public void setRefererPort(int refererPort) {
+            this.refererPort = refererPort;
+        }
+
+        public void setStatus(int status) {
+            this.status |= status;
+        }
+
+        public int getStatus() {
+            return this.status;
+        }
+
+        // Origin check for Protocol, Host, Port
+        public void checkOrigin() {
+            if (this.getStatus()==UNKNOWN) {
+                this.status=OK;
+            }
+            if (!targetUrl.getProtocol().equals(originUrl.getProtocol())) {
+                setStatus(F_ORIGIN_PROTOCOL);
+            }
+            if (!targetHost.equals(originHost)) {
+                setStatus(F_ORIGIN_HOST);
+            }
+            if (targetPort!=originPort) {
+                setStatus(F_ORIGIN_PORT);
+            }
+        }
+
+        // Referer check only for Host, Port
+        public void checkReferer() {
+            if (this.getStatus()==UNKNOWN) {
+                this.status=OK;
+            }
+            if (!targetHost.equals(refererHost)) {
+                setStatus(F_REFERER_HOST);
+            }
+            if (targetPort!=refererPort) {
+                setStatus(F_REFERER_PORT);
+            }
+        }
+
+        public boolean hasOriginError() {
+            return (status & (F_ORIGIN_PROTOCOL | F_ORIGIN_HOST | F_ORIGIN_PORT)) > 0;
+        }
+
+        public boolean hasRefererError() {
+            return (status & (F_REFERER_HOST | F_REFERER_PORT )) > 0;
+        }
+
+        @Override
+        public String toString() {
+            return "Stat="+status+", target="+targetUrl+", origin="+originUrl+", referer="+refererUrl;
+        }
+    }
+
     @Inject
-    public RequestValidationInterceptor(@Named( value = "userConfiguration#default" )
-                                                        UserConfiguration config) {
+    public RequestValidationInterceptor(
+            @Named(value = "userConfiguration#default") UserConfiguration config) {
         this.config = config;
     }
 
     @PostConstruct
     public void init() {
-        String baseUrlStr = config.getString(CFG_REST_BASE_URL, "");
-        if (!"".equals(baseUrlStr.trim())) {
-            try {
-                baseUrl = new URL(baseUrlStr);
-                useStaticUrl = true;
-            } catch (MalformedURLException ex) {
-                log.error("Configured baseUrl (rest.baseUrl={}) is invalid. Message: {}", baseUrlStr, ex.getMessage());
+        List<String> baseUrlList = config.getList(UserConfigurationKeys.REST_BASE_URL);
+        if (baseUrlList!=null) {
+            for (String baseUrlStr : baseUrlList) {
+                if (!"".equals(baseUrlStr.trim())) {
+                    try {
+                        baseUrl.add(new URL(baseUrlStr));
+                        useStaticUrl = true;
+                    } catch (MalformedURLException ex) {
+                        log.error("Configured baseUrl (rest.baseUrl={}) is invalid. Message: {}", baseUrlStr, ex.getMessage());
+                    }
+                }
             }
-        } else {
-            useStaticUrl = false;
         }
-        denyAbsentHeaders = config.getBoolean(CFG_REST_CSRF_ABSENTORIGIN_DENY,true);
-        enabled = config.getBoolean(CFG_REST_CSRF_ENABLED,true);
+        denyAbsentHeaders = config.getBoolean(UserConfigurationKeys.REST_CSRF_ABSENTORIGIN_DENY,true);
+        enabled = config.getBoolean(UserConfigurationKeys.REST_CSRF_ENABLED,true);
         if (!enabled) {
             log.info("CSRF Filter is disabled by configuration");
         }
-        checkToken = !config.getBoolean(CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION, false);
+        checkToken = !config.getBoolean(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION, false);
         if (!checkToken) {
             log.info("CSRF Token validation is disabled by configuration");
         }
@@ -131,24 +296,62 @@ public class RequestValidationInterceptor extends AbstractInterceptor implements
     public void filter(ContainerRequestContext containerRequestContext) throws IOException {
         if (enabled) {
             HttpServletRequest request = getRequest();
-            URL targetUrl = getTargetUrl(request);
-            if (targetUrl == null) {
+            List<URL> targetUrls = getTargetUrl(request);
+            if (targetUrls == null) {
                 log.error("Could not verify target URL.");
                 containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
                 return;
             }
-            if (!checkSourceRequestHeader(targetUrl, request)) {
+            List<HeaderValidationInfo> validationInfos = new ArrayList<HeaderValidationInfo>();
+            boolean targetMatch=false;
+            boolean noHeader = true;
+            for(URL targetUrl : targetUrls) {
+                log.trace("Checking against target URL: {}", targetUrl);
+                HeaderValidationInfo info = checkSourceRequestHeader(new HeaderValidationInfo(targetUrl), request);
+                // We need only one match
+                noHeader = noHeader && info.getStatus()==info.UNKNOWN;
+                if (info.getStatus()==info.OK) {
+                    targetMatch=true;
+                    break;
+                } else {
+                    validationInfos.add(info);
+                }
+            }
+            if (noHeader && denyAbsentHeaders) {
+                log.warn("Request denied. No Origin or Referer header found and {}=true", UserConfigurationKeys.REST_CSRF_ABSENTORIGIN_DENY);
+                containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                return;
+            }
+            if (!targetMatch) {
                 log.warn("HTTP Header check failed. Assuming CSRF attack.");
+                for(HeaderValidationInfo info : validationInfos) {
+                    if (info.hasOriginError()) {
+                        log.warn("Origin Header does not match: originUrl={}, targetUrl={}. Matches: Host={}, Port={}, Protocol={}",
+                                info.originUrl, info.targetUrl, (info.getStatus()&info.F_ORIGIN_HOST)==0,
+                                (info.getStatus()&info.F_ORIGIN_PORT)==0, (info.getStatus()&info.F_ORIGIN_PROTOCOL)==0);
+                    }
+                    if (info.hasRefererError()) {
+                        log.warn("Referer Header does not match: refererUrl={}, targetUrl={}. Matches: Host={}, Port={}",
+                                info.refererUrl, info.targetUrl, (info.getStatus()&info.F_REFERER_HOST)==0,
+                                (info.getStatus()&info.F_REFERER_PORT)==0);
+                    }
+                }
                 containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
                 return;
             }
-
             if (checkToken) {
                 checkValidationToken(containerRequestContext, request);
             }
         }
     }
 
+    /**
+     * Checks the request for a validation token header. It takes the encrypted token, decrypts it
+     * and compares the user information from the token to the logged in user.
+     *
+     * @param containerRequestContext
+     * @param request
+     */
     private void checkValidationToken(ContainerRequestContext containerRequestContext, HttpServletRequest request) {
         Message message = JAXRSUtils.getCurrentMessage();
         RedbackAuthorization redbackAuthorization = getRedbackAuthorization(message);
@@ -198,13 +401,15 @@ public class RequestValidationInterceptor extends AbstractInterceptor implements
         }
     }
 
-    private URL getTargetUrl(HttpServletRequest request) {
+    private List<URL> getTargetUrl(HttpServletRequest request) {
         if (useStaticUrl) {
             return baseUrl;
         } else {
+            List<URL> urls = new ArrayList<URL>();
             URL requestUrl;
             try {
                 requestUrl = new URL(request.getRequestURL().toString());
+                urls.add(requestUrl);
             } catch (MalformedURLException ex) {
                 log.error("Bad Request URL {}, Message: {}", request.getRequestURL(), ex.getMessage());
                 return null;
@@ -216,81 +421,52 @@ public class RequestValidationInterceptor extends AbstractInterceptor implements
             }
             if (xforwarded!=null) {
                 try {
-                    return new URL(xforwardedProto+"://"+xforwarded);
+                    urls.add(new URL(xforwardedProto+"://"+xforwarded));
                 } catch (MalformedURLException ex) {
                     log.warn("X-Forwarded-Host Header is malformed: {}", ex.getMessage());
                 }
             }
-            return requestUrl;
+            return urls;
         }
     }
 
     private int getPort(final URL url) {
-        return url.getPort() > 0 ? url.getPort() : url.getDefaultPort();
+        return url.getPort() > 0 ? url.getPort() : ("https".equals(url.getProtocol()) ? DEFAULT_HTTPS : DEFAULT_HTTP);
+    }
+
+    private String getHost(final URL url) {
+        return url.getHost().trim().toLowerCase();
     }
 
-    private boolean checkSourceRequestHeader(final URL targetUrl, final HttpServletRequest request) {
-        boolean headerFound=false;
+    /**
+     * Checks the validation headers. First the Origin header is checked, if this fails
+     * or is absent, the referer header is checked.
+     *
+     * @param info The info object that must be populated with the targetURL
+     * @param request The HTTP request object
+     * @return A info object with updated status information
+     */
+    private HeaderValidationInfo checkSourceRequestHeader(final HeaderValidationInfo info, final HttpServletRequest request) {
         String origin = request.getHeader(ORIGIN);
-        int targetPort = getPort(targetUrl);
         if (origin!=null) {
             try {
-                URL originUrl = new URL(origin);
-                headerFound=true;
-                log.debug("Origin Header URL found: {}", originUrl);
-                if (!targetUrl.getProtocol().equals(originUrl.getProtocol())) {
-                    log.warn("Origin Header Protocol does not match originUrl={}, targetUrl={}", //
-                             originUrl.getProtocol(), //
-                             targetUrl.getProtocol());
-                    return false;
-                }
-                if (!targetUrl.getHost().equals(originUrl.getHost())) {
-                    log.warn("Origin Header Host does not match originUrl='{}', targetUrl='{}'",
-                             originUrl.getProtocol(), //
-                             targetUrl.getProtocol());
-                    return false;
-                }
-                int originPort = getPort(originUrl);
-                if (targetPort != originPort) {
-                    log.warn("Origin Header Port does not match originUrl={}, targetUrl={}",
-                             originUrl.getPort(),
-                             targetUrl.getPort());
-                    return false;
-                }
-            } catch (MalformedURLException ex) {
-                log.warn("Bad URL in Origin HTTP-Header: {}. Message: {}",origin, ex.getMessage());
-                return false;
+                info.setOriginUrl(new URL(origin));
+            } catch (MalformedURLException e) {
+                log.warn("Bad origin header found: {}", origin);
             }
         }
-        String referer = request.getHeader(REFERER);
-        if (referer!=null) {
-            try {
-                URL refererUrl = new URL(referer);
-                headerFound=true;
-                log.debug("Referer Header URL found: {}",refererUrl);
-                if (!targetUrl.getHost().equals(refererUrl.getHost())) {
-                    log.warn("Referer Header Host does not match refererUrl='{}', targetUrl='{}'", //
-                             refererUrl.getHost(), //
-                             targetUrl.getHost());
-                    return false;
-                }
-                int refererPort = getPort(refererUrl);
-                if (targetPort != refererPort) {
-                    log.warn("Referer Header Port does not match refererUrl={}, targetUrl={}", //
-                             refererUrl.getPort(),
-                             targetUrl.getPort());
-                    return false;
+        // Check referer if Origin header dos not match or is not available
+        if (info.getStatus()!=info.OK) {
+            String referer = request.getHeader(REFERER);
+            if (referer != null) {
+                try {
+                    info.setRefererUrl(new URL(referer));
+                } catch (MalformedURLException ex) {
+                    log.warn("Bad URL in Referer HTTP-Header: {}, Message: {}", referer, ex.getMessage());
                 }
-            } catch (MalformedURLException ex) {
-                log.warn("Bad URL in Referer HTTP-Header: {}, Message: {}", referer, ex.getMessage());
-                return false;
             }
         }
-        if (!headerFound && denyAbsentHeaders) {
-            log.warn("Neither Origin nor Referer header found. Request is denied.");
-            return false;
-        }
-        return true;
+        return info;
     }
 
     public void setHttpRequest(HttpServletRequest request) {

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/1b13cbd0/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 27ab531..aad961a 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
@@ -22,17 +22,18 @@ package org.apache.archiva.redback.rest.services;
 import junit.framework.TestCase;
 import org.apache.archiva.redback.authentication.TokenManager;
 import org.apache.archiva.redback.configuration.UserConfigurationException;
+import org.apache.archiva.redback.configuration.UserConfigurationKeys;
 import org.apache.archiva.redback.rest.services.interceptors.RequestValidationInterceptor;
 import org.apache.archiva.redback.rest.services.mock.MockContainerRequestContext;
 import org.apache.archiva.redback.rest.services.mock.MockUserConfiguration;
-import org.apache.archiva.redback.system.SecuritySystem;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 import org.springframework.mock.web.MockHttpServletRequest;
 
 import java.io.IOException;
-
+import java.util.ArrayList;
+import java.util.List;
 
 
 /**
@@ -50,7 +51,7 @@ public class RequestValidationInterceptorTest extends TestCase {
     public void validateRequestWithoutHeader() throws UserConfigurationException, IOException {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        cfg.addValue(UserConfigurationKeys.REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest();
         interceptor.setHttpRequest(request);
@@ -64,7 +65,7 @@ public class RequestValidationInterceptorTest extends TestCase {
     public void validateRequestWithOrigin() throws UserConfigurationException, IOException {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
@@ -80,7 +81,7 @@ public class RequestValidationInterceptorTest extends TestCase {
     public void validateRequestWithBadOrigin() throws UserConfigurationException, IOException {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
@@ -96,7 +97,7 @@ public class RequestValidationInterceptorTest extends TestCase {
     public void validateRequestWithReferer() throws UserConfigurationException, IOException {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
@@ -112,7 +113,7 @@ public class RequestValidationInterceptorTest extends TestCase {
     public void validateRequestWithBadReferer() throws UserConfigurationException, IOException {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
@@ -128,7 +129,7 @@ public class RequestValidationInterceptorTest extends TestCase {
     public void validateRequestWithOriginAndReferer() throws UserConfigurationException, IOException {
         TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
@@ -145,8 +146,10 @@ public class RequestValidationInterceptorTest extends TestCase {
     @Test
     public void validateRequestWithOriginAndStaticUrl() throws UserConfigurationException, IOException {
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue("rest.baseUrl","http://test.archiva.org");
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
         TokenManager tm = new TokenManager();
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
@@ -162,8 +165,10 @@ public class RequestValidationInterceptorTest extends TestCase {
     @Test
     public void validateRequestWithBadOriginAndStaticUrl() throws UserConfigurationException, IOException {
         MockUserConfiguration cfg = new MockUserConfiguration();
-        cfg.addValue("rest.baseUrl","http://mytest.archiva.org");
-        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
+        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");
         TokenManager tm = new TokenManager();
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
@@ -177,4 +182,25 @@ public class RequestValidationInterceptorTest extends TestCase {
     }
 
 
+    @Test
+    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");
+        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);
+        interceptor.init();
+        MockContainerRequestContext ctx = new MockContainerRequestContext();
+        interceptor.filter(ctx);
+        assertFalse(ctx.isAborted());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/archiva-redback-core/blob/1b13cbd0/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java
----------------------------------------------------------------------
diff --git a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java
index 6eaaed8..69a3a83 100644
--- a/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java
+++ b/redback-integrations/redback-rest/redback-rest-services/src/test/java/org/apache/archiva/redback/rest/services/mock/MockUserConfiguration.java
@@ -34,13 +34,17 @@ import java.util.Map;
  */
 public class MockUserConfiguration implements UserConfiguration {
 
-    private Map<String, String> values = new java.util.HashMap<String,String>();
+    private Map<String, Object> values = new java.util.HashMap<String,Object>();
 
     @SuppressWarnings("SameParameterValue")
     public void addValue(String key, String value) {
         values.put(key,value);
     }
 
+    public void addList(String key, List<String> listValue) {
+        values.put(key, listValue);
+    }
+
     @Override
     public void initialize() throws UserConfigurationException {
 
@@ -48,13 +52,13 @@ public class MockUserConfiguration implements UserConfiguration {
 
     @Override
     public String getString(String key) {
-        return values.get(key);
+        return values.get(key).toString();
     }
 
     @Override
     public String getString(String key, String defaultValue) {
         if (values.containsKey(key)) {
-            return values.get(key);
+            return values.get(key).toString();
         } else {
             return defaultValue;
         }
@@ -68,7 +72,7 @@ public class MockUserConfiguration implements UserConfiguration {
     @Override
     public int getInt(String key, int defaultValue) {
         if (values.containsKey(key)) {
-            return Integer.parseInt(values.get(key));
+            return Integer.parseInt(values.get(key).toString());
         } else {
             return defaultValue;
         }
@@ -82,7 +86,7 @@ public class MockUserConfiguration implements UserConfiguration {
     @Override
     public boolean getBoolean(String key, boolean defaultValue) {
         if (values.containsKey(key)) {
-            return Boolean.parseBoolean(values.get(key));
+            return Boolean.parseBoolean(values.get(key).toString());
         } else {
             return defaultValue;
         }
@@ -90,7 +94,12 @@ public class MockUserConfiguration implements UserConfiguration {
 
     @Override
     public List<String> getList(String key) {
-        return null;
+        Object value = values.get(key);
+        if (value!=null && value instanceof List) {
+            return (List)value;
+        } else {
+            return null;
+        }
     }
 
     @Override