KNOX-1381 - Fix logging
authorSandeep More <more@apache.org>
Tue, 10 Jul 2018 17:54:34 +0000 (13:54 -0400)
committerSandeep More <more@apache.org>
Tue, 10 Jul 2018 17:56:18 +0000 (13:56 -0400)
gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
gateway-util-common/src/main/java/org/apache/knox/gateway/audit/log4j/audit/Log4jAuditor.java

index 17e5c7c..de5c773 100644 (file)
@@ -43,6 +43,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.WebApplicationException;
 
+import org.apache.knox.gateway.audit.log4j.audit.Log4jAuditor;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
@@ -210,7 +211,7 @@ public class WebSSOResource {
       }
 
       if (!validRedirect) {
-        log.whiteListMatchFail(original, whitelist);
+        log.whiteListMatchFail(Log4jAuditor.maskTokenFromURL(original), whitelist);
         throw new WebApplicationException("Original URL not valid according to the configured whitelist.",
                                           Response.Status.BAD_REQUEST);
       }
@@ -236,7 +237,7 @@ public class WebSSOResource {
         removeOriginalUrlCookie(response);
       }
 
-      log.aboutToRedirectToOriginal(original);
+      log.aboutToRedirectToOriginal(Log4jAuditor.maskTokenFromURL(original));
       response.setStatus(statusCode);
       response.setHeader("Location", original);
       try {
index a631d73..28643e5 100644 (file)
@@ -18,6 +18,7 @@
 package org.apache.knox.gateway.service.knoxsso;
 
 import org.apache.http.HttpStatus;
+import org.apache.knox.gateway.audit.log4j.audit.Log4jAuditor;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.util.RegExUtils;
 import static org.junit.Assert.assertEquals;
@@ -826,6 +827,38 @@ public class WebSSOResourceTest {
 
   }
 
+  @Test
+  public void testRedactToken() throws Exception {
+
+    final String token = "eyJhbGciOiJSUzI1NiJ9."
+        + "eyJzdWIiOiJhZG1pbjEiLCJpc3MiOiJLTk9YU1NPIiwiZXhwIjoxNTMwNzkwMjkxfQ."
+        + "BdWDAzGvXVvBH_TiEhAqowH-K24GfH8rgb8HJLromVpGwBTkbijIfOZWcvT3a5uZx6r"
+        + "VEGAXqAKPEqrODBGTSV6l0uEJGeAfQj_7ulQD0YkXaPPJ_FYYntelSA814HzTU0X8UmY"
+        + "Wo6awEaBwRC_xgNoZ_bMqnkjgFAfTtdHiiEQ";
+
+    final String originalUrl1 = "http://loclahost:8080/?&knoxtoken="+token;
+    final String originalUrl2 = "http://loclahost:8080/?&test=value&knoxtoken="+token;
+    final String originalUrl3 = "http://loclahost:8080/?&knoxtoken="+token+"&test=value";
+
+    final String fragment1 = "/gateway/knoxsso/api/v1/websso?knoxtoken="+token;
+    final String fragment2 = "/gateway/knoxsso/api/v1/websso?knoxtoken="+token+
+        "&originalUrl=http%3A%2F%2Fwww.local.com%3A8443%2F%3Fgateway%3Done%26knoxtoken";
+    final String fragment3 = "/gateway/knoxsso/api/v1/websso?test=value"+
+        "&originalUrl=http%3A%2F%2Fwww.local.com%3A8443%2F%3Fgateway%3Done%26knoxtoken";
+
+    assertEquals("http://loclahost:8080/?&knoxtoken=***************", Log4jAuditor
+        .maskTokenFromURL(originalUrl1));
+    assertEquals("http://loclahost:8080/?&test=value&knoxtoken=***************", Log4jAuditor.maskTokenFromURL(originalUrl2));
+    assertEquals("http://loclahost:8080/?&knoxtoken=***************&test=value", Log4jAuditor.maskTokenFromURL(originalUrl3));
+
+    assertEquals("/gateway/knoxsso/api/v1/websso?knoxtoken=***************", Log4jAuditor.maskTokenFromURL(fragment1));
+    assertEquals("/gateway/knoxsso/api/v1/websso?knoxtoken=***************"+
+        "&originalUrl=http://www.local.com:8443/?gateway=one&knoxtoken", Log4jAuditor.maskTokenFromURL(fragment2));
+    assertEquals("/gateway/knoxsso/api/v1/websso?test=value"+
+        "&originalUrl=http://www.local.com:8443/?gateway=one&knoxtoken", Log4jAuditor.maskTokenFromURL(fragment3));
+
+  }
+
   /**
    * A wrapper for HttpServletResponseWrapper to store the cookies
    */
index ebf5859..30ea8d4 100644 (file)
@@ -28,19 +28,46 @@ import org.apache.knox.gateway.audit.log4j.correlation.Log4jCorrelationService;
 import org.apache.log4j.Logger;
 import org.apache.log4j.MDC;
 
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
 public class Log4jAuditor implements Auditor {
 
+  /** Comma seperated list of query parameters who's values will be masked
+  * e.g. -Dmasked_params=knoxtoken,ccNumber
+  **/
+  public static String MASKED_QUERY_PARAMS_OPTION = "masked_params";
   private Logger logger;
   private String componentName;
   private String serviceName;
   private AuditService auditService = new Log4jAuditService();
   private CorrelationService correlationService = new Log4jCorrelationService();
+  /* List of parameters to be masked */
+  private static List<String> maskedParams = new ArrayList<>();
+
+  static {
+    /* add defaults */
+    maskedParams.add("knoxtoken");
+  }
 
   public Log4jAuditor( String loggerName, String componentName, String serviceName ) {
     logger = Logger.getLogger( loggerName );
     logger.setAdditivity( false );
     this.componentName = componentName;
     this.serviceName = serviceName;
+
+    /* check for -Dmasked_params system property for params to mask */
+    final String masked_query_params = System.getProperty(MASKED_QUERY_PARAMS_OPTION);
+    /* Add the params to mask list */
+    if(masked_query_params != null) {
+      final String[] params = masked_query_params.split(",");
+      for(final String s: params) {
+        if(!maskedParams.contains(s)) {
+          maskedParams.add(s);
+        }
+      }
+    }
   }
 
   @Override
@@ -76,7 +103,7 @@ public class Log4jAuditor implements Auditor {
   private void auditLog( String action, String resourceName, String resourceType, String outcome, String message ) {
     if ( logger.isInfoEnabled() ) {
       MDC.put( AuditConstants.MDC_ACTION_KEY, action );
-      MDC.put( AuditConstants.MDC_RESOURCE_NAME_KEY, resourceName );
+      MDC.put( AuditConstants.MDC_RESOURCE_NAME_KEY, maskTokenFromURL(resourceName) );
       MDC.put( AuditConstants.MDC_RESOURCE_TYPE_KEY, resourceType );
       MDC.put( AuditConstants.MDC_OUTCOME_KEY, outcome );
       MDC.put( AuditConstants.MDC_SERVICE_KEY, serviceName );
@@ -108,4 +135,46 @@ public class Log4jAuditor implements Auditor {
     return logger.getName();
   }
 
+  /**
+   * If the url contains knoxtoken parameter, mask it when logging.
+   * @param originalUrl
+   * @return originalUrl masking token value
+   */
+  public static String maskTokenFromURL(final String originalUrl) {
+    try {
+      final URI original = new URI(originalUrl);
+
+      if( original.getQuery() != null &&
+          !original.getQuery().isEmpty()) {
+
+        final String[] query = original.getQuery().split("&");
+        final StringBuffer newQuery = new StringBuffer();
+
+        for(int i = 0; i < query.length; i++ ) {
+
+          for(final String s: maskedParams) {
+            /* mask "knoxtoken" param */
+            if(query[i].contains(s+"=")) {
+              newQuery.append(s+"=***************");
+            } else {
+              newQuery.append(query[i]);
+            }
+          }
+          if (i < (query.length -1) ) {
+            newQuery.append("&");
+          }
+        }
+
+        final URI newURI = new URI(original.getScheme(), original.getAuthority(),
+            original.getPath(), newQuery.toString(), original.getFragment());
+
+        return newURI.toString();
+      }
+
+    } catch (final Exception e) {
+      // malformed uri just log the original url
+    }
+    return originalUrl;
+  }
+
 }