Adding token validation to interceptor
diff --git a/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties b/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties
index 9fa02ce..4b3e6fa 100644
--- a/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties
+++ b/redback-configuration/src/main/resources/org/apache/archiva/redback/config-defaults.properties
@@ -136,7 +136,11 @@
 # REST security settings
 
 # REST base url is for avoiding CSRF attacks
+# Enable CSRF filtering
+rest.csrffilter.enabled=true
 # If it is not set or empty it tries to determine the base url automatically
 rest.baseUrl=
 # If true, requests without Origin or Referer Header are denied
-rest.csrf.absentorigin.deny=true
\ No newline at end of file
+rest.csrffilter.absentorigin.deny=true
+# If true, the validation of the CSRF tokens will be disabled
+rest.csrffilter.disableTokenValidation=false
\ No newline at end of file
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 182d23a..a9afede 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
@@ -19,7 +19,17 @@
  */
 
 
+import org.apache.archiva.redback.authentication.AuthenticationException;
+import org.apache.archiva.redback.authentication.AuthenticationResult;
+import org.apache.archiva.redback.authentication.InvalidTokenException;
+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.integration.filter.authentication.basic.HttpBasicAuthentication;
+import org.apache.archiva.redback.policy.AccountLockedException;
+import org.apache.archiva.redback.policy.MustChangePasswordException;
+import org.apache.archiva.redback.users.User;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.message.Message;
 import org.slf4j.Logger;
@@ -60,15 +70,18 @@
 
     private static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
     private static final String X_FORWARDED_HOST = "X-Forwarded-Host";
+    private static final String X_XSRF_TOKEN = "X-XSRF-TOKEN";
     private static final String ORIGIN = "Origin";
     private static final String REFERER = "Referer";
-    private static final String CFG_REST_BASE_URL = "rest.baseUrl";
-    private static final String CFG_REST_CSRF_ABSENTORIGIN_DENY = "rest.csrffilter.absentorigin.deny";
-    private static final String CFG_REST_CSRF_ENABLED = "rest.csrffilter.enabled";
+    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 final Logger log = LoggerFactory.getLogger( getClass() );
 
     private boolean enabled = true;
+    private boolean checkToken = true;
     private boolean useStaticUrl = false;
     private boolean denyAbsentHeaders = true;
     private URL baseUrl;
@@ -77,6 +90,14 @@
     private UserConfiguration config;
 
     @Inject
+    @Named( value = "httpAuthenticator#basic" )
+    private HttpBasicAuthentication httpAuthenticator;
+
+    @Inject
+    @Named( value = "tokenManager#default")
+    TokenManager tokenManager;
+
+    @Inject
     public RequestValidationInterceptor(@Named( value = "userConfiguration#default" )
                                                         UserConfiguration config) {
         this.config = config;
@@ -100,6 +121,7 @@
         if (!enabled) {
             log.info("CSRF Filter is disabled by configuration");
         }
+        checkToken = !config.getBoolean(CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION, false);
     }
 
     @Override
@@ -110,14 +132,60 @@
             if (targetUrl == null) {
                 log.error("Could not verify target URL.");
                 containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                return;
             }
             if (!checkSourceRequestHeader(targetUrl, request)) {
                 log.warn("HTTP Header check failed. Assuming CSRF attack.");
                 containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                return;
+            }
+
+            if (checkToken) {
+                checkValidationToken(containerRequestContext, request);
             }
         }
     }
 
+    private void checkValidationToken(ContainerRequestContext containerRequestContext, HttpServletRequest request) {
+        Message message = JAXRSUtils.getCurrentMessage();
+        RedbackAuthorization redbackAuthorization = getRedbackAuthorization(message);
+        // We check only services that are restricted
+        if (!redbackAuthorization.noRestriction()) {
+            String tokenString = request.getHeader(X_XSRF_TOKEN);
+            if (tokenString==null || tokenString.length()==0) {
+                log.warn("No validation token header found: {}",X_XSRF_TOKEN);
+                containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                return;
+            }
+
+            try {
+                TokenData td = tokenManager.decryptToken(tokenString);
+                AuthenticationResult auth = getAuthenticationResult(message, request);
+                if (auth==null) {
+                    log.error("Not authentication data found");
+                    containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                    return;
+                }
+                User loggedIn = auth.getUser();
+                if (loggedIn==null) {
+                    log.error("User not logged in");
+                    containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                    return;
+                }
+                String username = loggedIn.getUsername();
+                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());
+                    containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+                }
+            } catch (InvalidTokenException e) {
+                log.error("Token validation failed {}", e.getMessage());
+                containerRequestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
+            }
+        }
+        log.debug("Token validated");
+    }
+
     private HttpServletRequest getRequest() {
         if (httpRequest!=null) {
             return httpRequest;
@@ -215,4 +283,33 @@
     public void setHttpRequest(HttpServletRequest request) {
         this.httpRequest = request;
     }
+
+    private AuthenticationResult getAuthenticationResult(Message message, HttpServletRequest request) {
+        AuthenticationResult authenticationResult = message.get(AuthenticationResult.class);
+
+        log.debug("authenticationResult from message: {}", authenticationResult);
+        if ( authenticationResult == null )
+        {
+            try
+            {
+                authenticationResult =
+                        httpAuthenticator.getAuthenticationResult( request, getHttpServletResponse( message ) );
+
+                log.debug( "authenticationResult from request: {}", authenticationResult );
+            }
+            catch ( AuthenticationException e )
+            {
+                log.debug( "failed to authenticate for path {}", message.get( Message.REQUEST_URI ) );
+            }
+            catch ( AccountLockedException e )
+            {
+                log.debug( "account locked for path {}", message.get( Message.REQUEST_URI ) );
+            }
+            catch ( MustChangePasswordException e )
+            {
+                log.debug( "must change password for path {}", message.get( Message.REQUEST_URI ) );
+            }
+        }
+        return authenticationResult;
+    }
 }
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 c88492a..27ab531 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
@@ -20,10 +20,12 @@
 
 
 import junit.framework.TestCase;
+import org.apache.archiva.redback.authentication.TokenManager;
 import org.apache.archiva.redback.configuration.UserConfigurationException;
 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;
@@ -36,7 +38,7 @@
 /**
  * Created by Martin Stockhammer on 21.01.17.
  *
- * Unit Test for RequestValidationInterceptor.
+ * Unit Test for RequestValidationInterceptor. The unit tests are all without token validation.
  *
  */
 @RunWith(JUnit4.class)
@@ -46,7 +48,9 @@
 
     @Test
     public void validateRequestWithoutHeader() throws UserConfigurationException, IOException {
+        TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest();
         interceptor.setHttpRequest(request);
@@ -58,7 +62,9 @@
 
     @Test
     public void validateRequestWithOrigin() throws UserConfigurationException, IOException {
+        TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("test.archiva.org");
@@ -72,7 +78,9 @@
 
     @Test
     public void validateRequestWithBadOrigin() throws UserConfigurationException, IOException {
+        TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("test.archiva.org");
@@ -86,7 +94,9 @@
 
     @Test
     public void validateRequestWithReferer() throws UserConfigurationException, IOException {
+        TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("test.archiva.org");
@@ -100,7 +110,9 @@
 
     @Test
     public void validateRequestWithBadReferer() throws UserConfigurationException, IOException {
+        TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("test.archiva.org");
@@ -114,7 +126,9 @@
 
     @Test
     public void validateRequestWithOriginAndReferer() throws UserConfigurationException, IOException {
+        TokenManager tm = new TokenManager();
         MockUserConfiguration cfg = new MockUserConfiguration();
+        cfg.addValue(RequestValidationInterceptor.CFG_REST_CSRF_DISABLE_TOKEN_VALIDATION,"true");
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("test.archiva.org");
@@ -132,6 +146,8 @@
     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");
+        TokenManager tm = new TokenManager();
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("test4.archiva.org");
@@ -147,6 +163,8 @@
     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");
+        TokenManager tm = new TokenManager();
         RequestValidationInterceptor interceptor = new RequestValidationInterceptor(cfg);
         MockHttpServletRequest request = new MockHttpServletRequest("GET","/api/v1/userService");
         request.setServerName("mytest.archiva.org");