You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by km...@apache.org on 2014/01/27 18:00:39 UTC
[2/2] git commit: KNOX-23: Generate audit log of all gateway activity
KNOX-23: Generate audit log of all gateway activity
Project: http://git-wip-us.apache.org/repos/asf/incubator-knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-knox/commit/f69acbbc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-knox/tree/f69acbbc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-knox/diff/f69acbbc
Branch: refs/heads/master
Commit: f69acbbc4d02c12884101e7c8145efb77ef98f59
Parents: a9e7dea
Author: Kevin Minder <ke...@hortonworks.com>
Authored: Mon Jan 27 11:58:55 2014 -0500
Committer: Kevin Minder <ke...@hortonworks.com>
Committed: Mon Jan 27 11:58:55 2014 -0500
----------------------------------------------------------------------
.../gateway/filter/AclsAuthorizationFilter.java | 13 +-
.../filter/AclsAuthorizationResources.java | 27 ++
.../filter/ShiroSubjectIdentityAdapter.java | 16 ++
.../home/conf/gateway-log4j.properties | 8 +
.../apache/hadoop/gateway/GatewayFactory.java | 2 +-
.../apache/hadoop/gateway/GatewayFilter.java | 70 ++++-
.../apache/hadoop/gateway/GatewayResources.java | 4 +
.../apache/hadoop/gateway/GatewayServer.java | 12 +
.../apache/hadoop/gateway/GatewayServlet.java | 15 +
.../gateway/dispatch/AppCookieManager.java | 11 +-
.../hadoop/gateway/dispatch/HdfsDispatch.java | 12 +
.../gateway/dispatch/HttpClientDispatch.java | 13 +
.../gateway/dispatch/UrlConnectionDispatch.java | 16 ++
.../apache/hadoop/gateway/AuditLoggingTest.java | 226 +++++++++++++++
.../hadoop/gateway/GatewayFilterTest.java | 2 +-
.../src/test/resources/log4j.properties | 3 +
.../gateway/filter/AbstractGatewayFilter.java | 1 +
.../AbstractIdentityAssertionFilter.java | 18 ++
.../gateway/i18n/GatewaySpiResources.java | 28 ++
.../apache/hadoop/test/log/CollectAppender.java | 51 ++++
gateway-util-common/pom.xml | 12 +
.../apache/hadoop/gateway/audit/api/Action.java | 33 +++
.../hadoop/gateway/audit/api/ActionOutcome.java | 36 +++
.../hadoop/gateway/audit/api/AuditContext.java | 51 ++++
.../hadoop/gateway/audit/api/AuditService.java | 77 +++++
.../gateway/audit/api/AuditServiceFactory.java | 43 +++
.../hadoop/gateway/audit/api/Auditor.java | 86 ++++++
.../gateway/audit/api/CorrelationContext.java | 74 +++++
.../gateway/audit/api/CorrelationService.java | 99 +++++++
.../audit/api/CorrelationServiceFactory.java | 44 +++
.../hadoop/gateway/audit/api/ResourceType.java | 28 ++
.../gateway/audit/log4j/appender/JdbmQueue.java | 171 +++++++++++
.../appender/JdbmStoreAndForwardAppender.java | 115 ++++++++
.../audit/log4j/audit/AuditConstants.java | 35 +++
.../audit/log4j/audit/Log4jAuditContext.java | 116 ++++++++
.../audit/log4j/audit/Log4jAuditService.java | 84 ++++++
.../gateway/audit/log4j/audit/Log4jAuditor.java | 111 ++++++++
.../correlation/Log4jCorrelationContext.java | 105 +++++++
.../correlation/Log4jCorrelationService.java | 128 +++++++++
.../gateway/audit/log4j/layout/AuditLayout.java | 78 ++++++
.../hadoop/gateway/audit/AuditLayoutTest.java | 141 ++++++++++
.../hadoop/gateway/audit/AuditServiceTest.java | 167 +++++++++++
.../hadoop/gateway/audit/JdbmQueueTest.java | 280 +++++++++++++++++++
.../audit/StoreAndForwardAppenderTest.java | 61 ++++
.../src/test/resources/log4j.properties | 25 ++
pom.xml | 6 +-
46 files changed, 2742 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationFilter.java b/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationFilter.java
index 78ee5fa..6f31193 100644
--- a/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationFilter.java
+++ b/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationFilter.java
@@ -27,11 +27,18 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.security.GroupPrincipal;
import org.apache.hadoop.gateway.security.ImpersonatedPrincipal;
import org.apache.hadoop.gateway.security.PrimaryPrincipal;
import org.apache.hadoop.gateway.util.IpAddressValidator;
+import org.apache.hadoop.gateway.util.urltemplate.Template;
import java.io.IOException;
import java.security.AccessController;
@@ -41,6 +48,8 @@ import java.util.Collections;
public class AclsAuthorizationFilter implements Filter {
private static AclsAuthorizationMessages log = MessagesFactory.get( AclsAuthorizationMessages.class );
+ private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
private String resourceRole = null;
private ArrayList<String> users;
@@ -126,11 +135,13 @@ public class AclsAuthorizationFilter implements Filter {
FilterChain chain) throws IOException, ServletException {
boolean accessGranted = enforceAclAuthorizationPolicy(request, response, chain);
log.accessGranted(accessGranted);
-
+ String sourceUrl = (String)request.getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME );
if (accessGranted) {
+ auditor.audit( Action.AUTHORIZATION, sourceUrl, ResourceType.URI, ActionOutcome.SUCCESS );
chain.doFilter(request, response);
}
else {
+ auditor.audit( Action.AUTHORIZATION, sourceUrl, ResourceType.URI, ActionOutcome.FAILURE );
sendUnauthorized((HttpServletResponse) response);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationResources.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationResources.java b/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationResources.java
new file mode 100644
index 0000000..370336b
--- /dev/null
+++ b/gateway-provider-security-authz-acls/src/main/java/org/apache/hadoop/gateway/filter/AclsAuthorizationResources.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.filter;
+
+import org.apache.hadoop.gateway.i18n.resources.Resource;
+import org.apache.hadoop.gateway.i18n.resources.Resources;
+
+@Resources
+public interface AclsAuthorizationResources {
+ @Resource( text = "Response status: {0}" )
+ String responseStatus( int status );
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
index 7812056..352e4c7 100644
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
@@ -31,6 +31,13 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditService;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.security.GroupPrincipal;
import org.apache.hadoop.gateway.security.PrimaryPrincipal;
import org.apache.shiro.SecurityUtils;
@@ -39,6 +46,11 @@ import org.apache.shiro.subject.Subject;
public class ShiroSubjectIdentityAdapter implements Filter {
private static final String SUBJECT_USER_GROUPS = "subject.userGroups";
+ private static AuditService auditService = AuditServiceFactory.getAuditService();
+ private static Auditor auditor = auditService.getAuditor(
+ AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
+ AuditConstants.KNOX_COMPONENT_NAME );
+
@Override
public void init( FilterConfig filterConfig ) throws ServletException {
@@ -88,6 +100,9 @@ public class ShiroSubjectIdentityAdapter implements Filter {
Set<Principal> principals = new HashSet<Principal>();
Principal p = new PrimaryPrincipal(principal);
principals.add(p);
+ auditService.createContext().setUsername( principal );
+ String sourceUri = (String)request.getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME );
+ auditor.audit( Action.AUTHENTICATION , sourceUri, ResourceType.URI, ActionOutcome.SUCCESS );
// map ldap groups saved in session to Java Subject GroupPrincipal(s)
if (SecurityUtils.getSubject().getSession().getAttribute(SUBJECT_USER_GROUPS) != null) {
@@ -96,6 +111,7 @@ public class ShiroSubjectIdentityAdapter implements Filter {
Principal gp = new GroupPrincipal(userRole);
principals.add(gp);
}
+ auditor.audit( Action.AUTHENTICATION , sourceUri, ResourceType.URI, ActionOutcome.SUCCESS, "Groups: " + userRoles );
}
// TODO: add groups through extended JndiLdapRealm implementation once Jira KNOX-4 is resolved
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-release/home/conf/gateway-log4j.properties
----------------------------------------------------------------------
diff --git a/gateway-release/home/conf/gateway-log4j.properties b/gateway-release/home/conf/gateway-log4j.properties
index 5844f2c..3ad09a9 100644
--- a/gateway-release/home/conf/gateway-log4j.properties
+++ b/gateway-release/home/conf/gateway-log4j.properties
@@ -16,6 +16,7 @@
app.log.dir=${launcher.dir}/../logs
app.log.file=${launcher.name}.log
+app.audit.file=${launcher.name}-audit.log
log4j.rootLogger=ERROR, drfa
@@ -39,3 +40,10 @@ log4j.appender.drfa.DatePattern=.yyyy-MM-dd
log4j.appender.drfa.layout=org.apache.log4j.PatternLayout
log4j.appender.drfa.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+log4j.logger.audit=INFO, auditfile
+log4j.appender.auditfile=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.auditfile.File=${app.log.dir}/${app.audit.file}
+log4j.appender.auditfile.Append = true
+log4j.appender.auditfile.DatePattern = '.'yyyy-MM-dd
+log4j.appender.auditfile.layout = org.apache.hadoop.gateway.audit.log4j.layout.AuditLayout
+
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFactory.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFactory.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFactory.java
index 197b274..8e978a2 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFactory.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFactory.java
@@ -74,7 +74,7 @@ public class GatewayFactory {
if( name == null ) {
name = filter.role();
}
- gateway.addFilter( filter.up().pattern(), name, filter.impl(), createParams( filter ) );
+ gateway.addFilter( filter.up().pattern(), name, filter.impl(), createParams( filter ), filter.up().role() );
}
private static Map<String, String> createParams( FilterDescriptor filter ) {
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java
index 87dd8f2..7b9281a 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayFilter.java
@@ -17,8 +17,19 @@
*/
package org.apache.hadoop.gateway;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditContext;
+import org.apache.hadoop.gateway.audit.api.AuditService;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.CorrelationContext;
+import org.apache.hadoop.gateway.audit.api.CorrelationServiceFactory;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.filter.AbstractGatewayFilter;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.hadoop.gateway.util.urltemplate.Matcher;
import org.apache.hadoop.gateway.util.urltemplate.Parser;
import org.apache.hadoop.gateway.util.urltemplate.Template;
@@ -32,6 +43,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -41,6 +53,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
/**
*
@@ -53,6 +66,11 @@ public class GatewayFilter implements Filter {
};
private static final GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
+ private static final GatewayResources RES = ResourcesFactory.get( GatewayResources.class );
+ private static AuditService auditService = AuditServiceFactory.getAuditService();
+ private static Auditor auditor = auditService.getAuditor(
+ AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
+ AuditConstants.KNOX_COMPONENT_NAME );
private Set<Holder> holders;
private Matcher<Chain> chains;
@@ -88,34 +106,50 @@ public class GatewayFilter implements Filter {
} catch( URISyntaxException e ) {
throw new ServletException( e );
}
-
+ String pathWithContext = httpRequest.getContextPath() + path;
LOG.receivedRequest( httpRequest.getMethod(), pathTemplate );
servletRequest.setAttribute( AbstractGatewayFilter.SOURCE_REQUEST_URL_ATTRIBUTE_NAME, pathTemplate );
+ servletRequest.setAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME, pathWithContext );
Matcher<Chain>.Match match = chains.match( pathTemplate );
+
+ assignCorrelationRequestId();
+ // Populate Audit/correlation parameters
+ AuditContext auditContext = auditService.createContext();
+ auditContext.setTargetServiceName( match == null ? null : match.getValue().getResourceRole() );
+ auditContext.setRemoteIp( servletRequest.getRemoteAddr() );
+ auditContext.setRemoteHostname( servletRequest.getRemoteHost() );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.UNAVAILABLE );
+
if( match != null ) {
Chain chain = match.getValue();
try {
chain.doFilter( servletRequest, servletResponse );
} catch( IOException e ) {
LOG.failedToExecuteFilter( e );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.FAILURE );
throw e;
} catch( ServletException e ) {
LOG.failedToExecuteFilter( e );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.FAILURE );
throw e;
} catch( RuntimeException e ) {
LOG.failedToExecuteFilter( e );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.FAILURE );
throw e;
} catch( ThreadDeath e ) {
LOG.failedToExecuteFilter( e );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.FAILURE );
throw e;
} catch( Throwable e ) {
LOG.failedToExecuteFilter( e );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.FAILURE );
throw new ServletException( e );
}
} else {
httpResponse.setStatus( HttpServletResponse.SC_NOT_FOUND );
+ auditor.audit( Action.ACCESS, pathWithContext, ResourceType.URI, ActionOutcome.SUCCESS, RES.responseStatus( HttpServletResponse.SC_NOT_FOUND ) );
}
//KAM[ Don't do this or the Jetty default servlet will overwrite any response setup by the filter.
// filterChain.doFilter( servletRequest, servletResponse );
@@ -134,13 +168,14 @@ public class GatewayFilter implements Filter {
Chain chain = chains.get( holder.template );
if( chain == null ) {
chain = new Chain();
+ chain.setResourceRole( holder.getResourceRole() );
chains.add( holder.template, chain );
}
chain.chain.add( holder );
}
- public void addFilter( String path, String name, Filter filter, Map<String,String> params ) throws URISyntaxException {
- Holder holder = new Holder( path, name, filter, params );
+ public void addFilter( String path, String name, Filter filter, Map<String,String> params, String resourceRole ) throws URISyntaxException {
+ Holder holder = new Holder( path, name, filter, params, resourceRole );
addHolder( holder );
}
@@ -149,14 +184,20 @@ public class GatewayFilter implements Filter {
// addHolder( holder );
// }
- public void addFilter( String path, String name, String clazz, Map<String,String> params ) throws URISyntaxException {
- Holder holder = new Holder( path, name, clazz, params );
+ public void addFilter( String path, String name, String clazz, Map<String,String> params, String resourceRole ) throws URISyntaxException {
+ Holder holder = new Holder( path, name, clazz, params, resourceRole );
addHolder( holder );
}
+
+ private void assignCorrelationRequestId() {
+ CorrelationContext correlationContext = CorrelationServiceFactory.getCorrelationService().createContext();
+ correlationContext.setRequestId( UUID.randomUUID().toString() );
+ }
private class Chain implements FilterChain {
private List<Holder> chain;
+ private String resourceRole;
private Chain() {
this.chain = new ArrayList<Holder>();
@@ -180,6 +221,14 @@ public class GatewayFilter implements Filter {
}
}
+ private String getResourceRole() {
+ return resourceRole;
+ }
+
+ private void setResourceRole( String resourceRole ) {
+ this.resourceRole = resourceRole;
+ }
+
}
private class Holder implements Filter, FilterConfig {
@@ -190,8 +239,9 @@ public class GatewayFilter implements Filter {
private Filter instance;
private Class<? extends Filter> clazz;
private String type;
+ private String resourceRole;
- private Holder( String path, String name, Filter filter, Map<String,String> params ) throws URISyntaxException {
+ private Holder( String path, String name, Filter filter, Map<String,String> params, String resourceRole ) throws URISyntaxException {
// this.path = path;
this.template = Parser.parse( path );
this.name = name;
@@ -199,6 +249,7 @@ public class GatewayFilter implements Filter {
this.instance = filter;
this.clazz = filter.getClass();
this.type = clazz.getCanonicalName();
+ this.resourceRole = resourceRole;
}
// private Holder( String path, String name, Class<WarDirFilter> clazz, Map<String,String> params ) throws URISyntaxException {
@@ -211,7 +262,7 @@ public class GatewayFilter implements Filter {
// this.type = clazz.getCanonicalName();
// }
- private Holder( String path, String name, String clazz, Map<String,String> params ) throws URISyntaxException {
+ private Holder( String path, String name, String clazz, Map<String,String> params, String resourceRole ) throws URISyntaxException {
// this.path = path;
this.template = Parser.parse( path );
this.name = name;
@@ -219,6 +270,7 @@ public class GatewayFilter implements Filter {
this.instance = null;
this.clazz = null;
this.type = clazz;
+ this.resourceRole = resourceRole;
}
@Override
@@ -293,6 +345,10 @@ public class GatewayFilter implements Filter {
}
return instance;
}
+
+ private String getResourceRole() {
+ return resourceRole;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayResources.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayResources.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayResources.java
index 44e6267..ce4b6c7 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayResources.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayResources.java
@@ -67,4 +67,8 @@ public interface GatewayResources {
@Resource( text="Failed to create keystore directory: {0}" )
String failedToCreateKeyStoreDirectory( String name );
+
+ @Resource( text="Response status: {0}" )
+ String responseStatus( int status );
+
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
index 794a50f..fee50dd 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServer.java
@@ -21,6 +21,12 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl;
import org.apache.hadoop.gateway.deploy.DeploymentFactory;
@@ -63,6 +69,8 @@ import java.util.regex.Pattern;
public class GatewayServer {
private static GatewayResources res = ResourcesFactory.get( GatewayResources.class );
private static GatewayMessages log = MessagesFactory.get( GatewayMessages.class );
+ private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
private static GatewayServer server;
private static GatewayServices services;
@@ -350,6 +358,7 @@ public class GatewayServer {
File[] files = topoDir.listFiles( new WarDirFilter( topology.getName() + "\\.war\\.[0-9A-Fa-f]+" ) );
if( files != null ) {
for( File file : files ) {
+ auditor.audit( Action.UNDEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
log.deletingDeployment( file.getAbsolutePath() );
internalUndeploy( topology );
FileUtils.deleteQuietly( file );
@@ -358,6 +367,7 @@ public class GatewayServer {
} else {
try {
if( !warDir.exists() ) {
+ auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
log.deployingTopology( topology.getName(), warDir.getAbsolutePath() );
internalUndeploy( topology ); // KNOX-152
WebArchive war = null;
@@ -370,11 +380,13 @@ public class GatewayServer {
internalDeploy( topology, warDir );
//log.deployedTopology( topology.getName());
} else {
+ auditor.audit( Action.REDEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
log.redeployingTopology( topology.getName(), warDir.getAbsolutePath() );
internalDeploy( topology, warDir );
//log.redeployedTopology( topology.getName() );
}
} catch( Throwable e ) {
+ auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE );
log.failedToDeployTopology( topology.getName(), e );
}
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServlet.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServlet.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServlet.java
index 0764663..b25ec17 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServlet.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayServlet.java
@@ -17,8 +17,15 @@
*/
package org.apache.hadoop.gateway;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.descriptor.GatewayDescriptor;
import org.apache.hadoop.gateway.descriptor.GatewayDescriptorFactory;
+import org.apache.hadoop.gateway.filter.AbstractGatewayFilter;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.hadoop.gateway.services.GatewayServices;
@@ -32,6 +39,7 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -45,6 +53,10 @@ public class GatewayServlet implements Servlet {
private static final GatewayResources res = ResourcesFactory.get( GatewayResources.class );
private static final GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
+
+ private static Auditor auditor = AuditServiceFactory.getAuditService()
+ .getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
private FilterConfigAdapter filterConfig;
private volatile GatewayFilter filter;
@@ -113,6 +125,9 @@ public class GatewayServlet implements Servlet {
} else {
((HttpServletResponse)servletResponse).setStatus( HttpServletResponse.SC_SERVICE_UNAVAILABLE );
}
+ String requestUri = (String)servletRequest.getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME );
+ int status = ((HttpServletResponse)servletResponse).getStatus();
+ auditor.audit( Action.ACCESS, requestUri, ResourceType.URI, ActionOutcome.SUCCESS, res.responseStatus( status ) );
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
index 50c120e..a316f3c 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
@@ -22,6 +22,12 @@ import java.net.URI;
import java.security.Principal;
import org.apache.hadoop.gateway.GatewayMessages;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
@@ -52,7 +58,8 @@ public class AppCookieManager {
private static final String SET_COOKIE = "Set-Cookie";
private static GatewayMessages LOG = MessagesFactory.get(GatewayMessages.class);
-
+ private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
private static final EmptyJaasCredentials EMPTY_JAAS_CREDENTIALS = new EmptyJaasCredentials();
String appCookie;
@@ -115,6 +122,7 @@ public class AppCookieManager {
hadoopAuthCookie = getHadoopAuthCookieValue(headers);
if (hadoopAuthCookie == null) {
LOG.failedSPNegoAuthn(uri.toString());
+ auditor.audit( Action.AUTHENTICATION, uri.toString(), ResourceType.URI, ActionOutcome.FAILURE );
throw new IOException(
"SPNego authn failed, can not get hadoop.auth cookie");
}
@@ -128,6 +136,7 @@ public class AppCookieManager {
}
LOG.successfulSPNegoAuthn(uri.toString());
+ auditor.audit( Action.AUTHENTICATION, uri.toString(), ResourceType.URI, ActionOutcome.SUCCESS);
hadoopAuthCookie = HADOOP_AUTH_EQ + quote(hadoopAuthCookie);
setAppCookie(hadoopAuthCookie);
return appCookie;
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HdfsDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HdfsDispatch.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HdfsDispatch.java
index e8116ea..4deeffb 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HdfsDispatch.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HdfsDispatch.java
@@ -17,6 +17,12 @@
*/
package org.apache.hadoop.gateway.dispatch;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
@@ -29,12 +35,16 @@ import org.eclipse.jetty.http.HttpStatus;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class HdfsDispatch extends HttpClientDispatch {
+ private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
+
public HdfsDispatch() throws ServletException {
super();
}
@@ -44,6 +54,8 @@ public class HdfsDispatch extends HttpClientDispatch {
throws IOException, URISyntaxException {
HttpEntity entity = createRequestEntity( request );
URI requestUri = getDispatchUrl( request );
+
+ auditor.audit( Action.DISPATCH, request.getRequestURI(), ResourceType.URI, ActionOutcome.UNAVAILABLE );
if( "CREATE".equals( request.getParameter( "op" ) ) ) {
HttpPut clientRequest = new HttpPut( requestUri );
HttpClient client = new DefaultHttpClient();
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
index 546c1d0..0e0ffe8 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
@@ -29,6 +29,12 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.gateway.GatewayMessages;
import org.apache.hadoop.gateway.GatewayResources;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.config.GatewayConfig;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
@@ -66,6 +72,8 @@ public class HttpClientDispatch extends AbstractGatewayDispatch {
private static GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
private static GatewayResources RES = ResourcesFactory.get( GatewayResources.class );
+ private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
private static final int DEFAULT_REPLAY_BUFFER_SIZE = 4 * 1024; // 4K
private AppCookieManager appCookieManager = new AppCookieManager();
@@ -108,6 +116,7 @@ public class HttpClientDispatch extends AbstractGatewayDispatch {
} catch (IOException e) {
// we do not want to expose back end host. port end points to clients, see JIRA KNOX-58
LOG.dispatchServiceConnectionException( outboundRequest.getURI(), e );
+ auditor.audit( Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.FAILURE );
throw new IOException( RES.dispatchConnectionError() );
} finally {
if (inboundResponse != null) {
@@ -122,7 +131,11 @@ public class HttpClientDispatch extends AbstractGatewayDispatch {
LOG.dispatchResponseCreatedStatusCode( statusCode, location.getValue() );
}
}
+ auditor.audit( Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.SUCCESS, RES.responseStatus( statusCode ) );
+ } else {
+ auditor.audit( Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.UNAVAILABLE );
}
+
}
// Copy the client respond header to the server respond.
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
index 8e2145b..5b02221 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/UrlConnectionDispatch.java
@@ -19,7 +19,15 @@ package org.apache.hadoop.gateway.dispatch;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.gateway.GatewayMessages;
+import org.apache.hadoop.gateway.GatewayResources;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.hadoop.gateway.util.urltemplate.Parser;
import org.apache.hadoop.gateway.util.urltemplate.Resolver;
import org.apache.hadoop.gateway.util.urltemplate.Rewriter;
@@ -30,6 +38,7 @@ import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -47,6 +56,9 @@ import java.util.Enumeration;
public class UrlConnectionDispatch extends AbstractGatewayDispatch {
private static final GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
+ private static final GatewayResources RES = ResourcesFactory.get( GatewayResources.class );
+ private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
@Override
public void doGet( URI url, HttpServletRequest request, HttpServletResponse response ) throws IOException, URISyntaxException {
@@ -95,6 +107,7 @@ public class UrlConnectionDispatch extends AbstractGatewayDispatch {
//System.out.println( "Resolved query: " + clientUrl );
AuthenticatedURL.Token token = new AuthenticatedURL.Token();
KerberosAuthenticator authenticator = new KerberosAuthenticator();
+ auditor.audit( Action.DISPATCH, urlStr, ResourceType.URI, ActionOutcome.UNAVAILABLE );
HttpURLConnection conn = new AuthenticatedURL( authenticator ).openConnection( clientUrl, token );
//System.out.println( "STATUS=" + conn.getResponseCode() );
InputStream input = conn.getInputStream();
@@ -107,12 +120,15 @@ public class UrlConnectionDispatch extends AbstractGatewayDispatch {
input.close();
}
}
+ auditor.audit( Action.DISPATCH, urlStr, ResourceType.URI, ActionOutcome.SUCCESS );
} catch( AuthenticationException e ) {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED );
LOG.failedToEstablishConnectionToUrl( urlStr, e );
+ auditor.audit( Action.DISPATCH, urlStr, ResourceType.URI, ActionOutcome.FAILURE, RES.responseStatus( HttpServletResponse.SC_UNAUTHORIZED ) );
} catch( FileNotFoundException e ) {
response.sendError( HttpServletResponse.SC_NOT_FOUND );
LOG.failedToEstablishConnectionToUrl( urlStr, e );
+ auditor.audit( Action.DISPATCH, urlStr, ResourceType.URI, ActionOutcome.FAILURE, RES.responseStatus( HttpServletResponse.SC_NOT_FOUND ) );
}
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/test/java/org/apache/hadoop/gateway/AuditLoggingTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/AuditLoggingTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/AuditLoggingTest.java
new file mode 100644
index 0000000..82a2da0
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/AuditLoggingTest.java
@@ -0,0 +1,226 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditContext;
+import org.apache.hadoop.gateway.audit.api.CorrelationContext;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
+import org.apache.hadoop.gateway.audit.log4j.audit.Log4jAuditService;
+import org.apache.hadoop.gateway.audit.log4j.correlation.Log4jCorrelationService;
+import org.apache.hadoop.gateway.dispatch.HttpClientDispatch;
+import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
+import org.apache.hadoop.test.log.CollectAppender;
+import org.apache.log4j.spi.LoggingEvent;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AuditLoggingTest {
+ private static final String PATH = "path";
+ private static final String CONTEXT_PATH = "contextPath/";
+ private static final String ADDRESS = "address";
+ private static final String HOST = "host";
+
+ private static final GatewayResources RES = ResourcesFactory.get( GatewayResources.class );
+
+ @Before
+ public void loggingSetup() {
+ CollectAppender.queue.clear();
+ }
+
+ @Test
+ /**
+ * Empty filter chain. Two events with same correlation ID are expected:
+ *
+ * action=access request_type=uri outcome=unavailable
+ * action=access request_type=uri outcome=success message=Response status: 404
+ */
+ public void testNoFiltersAudit() throws ServletException, IOException {
+ FilterConfig config = EasyMock.createNiceMock( FilterConfig.class );
+ EasyMock.replay( config );
+
+ HttpServletRequest request = EasyMock.createNiceMock( HttpServletRequest.class );
+ EasyMock.expect( request.getPathInfo() ).andReturn( PATH ).anyTimes();
+ EasyMock.expect( request.getContextPath() ).andReturn( CONTEXT_PATH ).anyTimes();
+ EasyMock.expect( request.getRemoteAddr() ).andReturn( ADDRESS ).anyTimes();
+ EasyMock.expect( request.getRemoteHost() ).andReturn( HOST ).anyTimes();
+
+ EasyMock.replay( request );
+
+ HttpServletResponse response = EasyMock.createNiceMock( HttpServletResponse.class );
+ EasyMock.replay( response );
+
+ FilterChain chain = EasyMock.createNiceMock( FilterChain.class );
+ EasyMock.replay( chain );
+
+ GatewayFilter gateway = new GatewayFilter();
+ gateway.init( config );
+ gateway.doFilter( request, response, chain );
+ gateway.destroy();
+
+ assertThat( CollectAppender.queue.size(), is( 2 ) );
+ Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
+ LoggingEvent accessEvent = iterator.next();
+ verifyAuditEvent( accessEvent, CONTEXT_PATH + PATH, ResourceType.URI, Action.ACCESS, ActionOutcome.UNAVAILABLE, null, null );
+
+ LoggingEvent responseEvent = iterator.next();
+ verifyAuditEvent( responseEvent, CONTEXT_PATH + PATH, ResourceType.URI, Action.ACCESS, ActionOutcome.SUCCESS, null,
+ RES.responseStatus( HttpServletResponse.SC_NOT_FOUND ) );
+ assertThat( getRequestId( accessEvent ), is( getRequestId( responseEvent ) ) );
+ }
+
+ @Test
+ /**
+ * One NoOp filter in chain. Single audit event with same with specified request URI is expected:
+ *
+ * action=access request_type=uri outcome=unavailable
+ */
+ public void testNoopFilter() throws ServletException, IOException,
+ URISyntaxException {
+
+ FilterConfig config = EasyMock.createNiceMock( FilterConfig.class );
+ EasyMock.replay( config );
+
+ HttpServletRequest request = EasyMock.createNiceMock( HttpServletRequest.class );
+ EasyMock.expect( request.getPathInfo() ).andReturn( PATH ).anyTimes();
+ EasyMock.expect( request.getContextPath() ).andReturn( CONTEXT_PATH ).anyTimes();
+ EasyMock.expect( request.getRemoteAddr() ).andReturn( ADDRESS ).anyTimes();
+ EasyMock.expect( request.getRemoteHost() ).andReturn( HOST ).anyTimes();
+ EasyMock.replay( request );
+
+ HttpServletResponse response = EasyMock.createNiceMock( HttpServletResponse.class );
+ EasyMock.replay( response );
+
+ FilterChain chain = EasyMock.createNiceMock( FilterChain.class );
+ EasyMock.replay( chain );
+
+ Filter filter = EasyMock.createNiceMock( Filter.class );
+ EasyMock.replay( filter );
+
+ GatewayFilter gateway = new GatewayFilter();
+ gateway.addFilter( "path", "filter", filter, null, null );
+ gateway.init( config );
+ gateway.doFilter( request, response, chain );
+ gateway.destroy();
+
+ assertThat( CollectAppender.queue.size(), is( 1 ) );
+ Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
+ LoggingEvent accessEvent = iterator.next();
+ verifyAuditEvent( accessEvent, CONTEXT_PATH + PATH, ResourceType.URI,
+ Action.ACCESS, ActionOutcome.UNAVAILABLE, null, null );
+
+ }
+
+ @Test
+ /**
+ * Dispatching outbound request. Remote host is unreachable. Two log events is expected:
+ *
+ * action=dispatch request_type=uri outcome=FAILED
+ * action=dispatch request_type=uri outcome=unavailable
+ */
+ public void testHttpClientOutboundException() throws IOException,
+ URISyntaxException {
+ String uri = "http://outbound-host:port/path";
+
+ HttpServletRequest inboundRequest = EasyMock.createNiceMock( HttpServletRequest.class );
+ EasyMock.expect( inboundRequest.getHeaderNames() ).andReturn( Collections.enumeration( new ArrayList<String>() ) ).anyTimes();
+ EasyMock.replay( inboundRequest );
+
+ HttpServletResponse outboundResponse = EasyMock.createNiceMock( HttpServletResponse.class );
+ EasyMock.replay( outboundResponse );
+
+ HttpClientDispatch dispatch = new HttpClientDispatch();
+ try {
+ dispatch.doGet( new URI( uri ), inboundRequest, outboundResponse );
+ fail( "Expected exception while accessing to unreachable host" );
+ } catch ( IOException e ) {
+ Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
+ LoggingEvent failureEvent = iterator.next();
+ verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_RESOURCE_NAME_KEY ), uri );
+ verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_RESOURCE_TYPE_KEY ), ResourceType.URI );
+ verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_ACTION_KEY ), Action.DISPATCH );
+ verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_OUTCOME_KEY ), ActionOutcome.FAILURE );
+
+ LoggingEvent unavailableEvent = iterator.next();
+ verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_RESOURCE_NAME_KEY ), uri );
+ verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_RESOURCE_TYPE_KEY ), ResourceType.URI );
+ verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_ACTION_KEY ), Action.DISPATCH );
+ verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_OUTCOME_KEY ), ActionOutcome.UNAVAILABLE );
+ }
+ }
+
+ private void verifyAuditEvent( LoggingEvent event, String resourceName,
+ String resourceType, String action, String outcome, String targetService,
+ String message ) {
+ event.getMDCCopy();
+ CorrelationContext cc = (CorrelationContext) event.getMDC( Log4jCorrelationService.MDC_CORRELATION_CONTEXT_KEY );
+ assertThat( cc, notNullValue() );
+ assertThat( cc.getRequestId(), is( notNullValue() ) );
+ AuditContext ac = (AuditContext) event.getMDC( Log4jAuditService.MDC_AUDIT_CONTEXT_KEY );
+ assertThat( ac, notNullValue() );
+ assertThat( ac.getRemoteIp(), is( ADDRESS ) );
+ assertThat( ac.getRemoteHostname(), is( HOST ) );
+ assertThat( (String) event.getMDC( AuditConstants.MDC_SERVICE_KEY ), is( AuditConstants.KNOX_SERVICE_NAME ) );
+ assertThat( (String) event.getMDC( AuditConstants.MDC_COMPONENT_KEY ), is( AuditConstants.KNOX_COMPONENT_NAME ) );
+ assertThat( (String) event.getLoggerName(), is( AuditConstants.DEFAULT_AUDITOR_NAME ) );
+ verifyValue( (String) event.getMDC( AuditConstants.MDC_RESOURCE_NAME_KEY ), resourceName );
+ verifyValue( (String) event.getMDC( AuditConstants.MDC_RESOURCE_TYPE_KEY ), resourceType );
+ verifyValue( (String) event.getMDC( AuditConstants.MDC_ACTION_KEY ), action );
+ verifyValue( (String) event.getMDC( AuditConstants.MDC_OUTCOME_KEY ), outcome );
+ verifyValue( ac.getTargetServiceName(), targetService );
+ verifyValue( event.getRenderedMessage(), message );
+ }
+
+ private void verifyValue( String actual, String expected ) {
+ if( expected == null ) {
+ assertThat( actual, nullValue() );
+ } else {
+ assertThat( actual, is( expected ) );
+ }
+ }
+
+ private String getRequestId( LoggingEvent event ) {
+ CorrelationContext cc = (CorrelationContext) event
+ .getMDC( Log4jCorrelationService.MDC_CORRELATION_CONTEXT_KEY );
+ return cc == null ? null : cc.getRequestId();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayFilterTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayFilterTest.java
index bd9ca31..0ce0886 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayFilterTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/GatewayFilterTest.java
@@ -77,7 +77,7 @@ public class GatewayFilterTest {
EasyMock.replay( filter );
GatewayFilter gateway = new GatewayFilter();
- gateway.addFilter( "path", "filter", filter, null );
+ gateway.addFilter( "path", "filter", filter, null, null );
gateway.init( config );
gateway.doFilter( request, response, chain );
gateway.destroy();
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-server/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/log4j.properties b/gateway-server/src/test/resources/log4j.properties
index c64be2f..7474633 100644
--- a/gateway-server/src/test/resources/log4j.properties
+++ b/gateway-server/src/test/resources/log4j.properties
@@ -23,6 +23,9 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%c] %m%n
+log4j.logger.audit = INFO, collectappender
+log4j.appender.collectappender = org.apache.hadoop.test.log.CollectAppender
+
#log4j.logger.org.apache.hadoop.gateway=DEBUG
#log4j.logger.org.eclipse.jetty=DEBUG
#log4j.logger.org.apache.shiro=DEBUG
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/AbstractGatewayFilter.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/AbstractGatewayFilter.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/AbstractGatewayFilter.java
index 83dfb6f..6ce985d 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/AbstractGatewayFilter.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/AbstractGatewayFilter.java
@@ -38,6 +38,7 @@ public abstract class AbstractGatewayFilter implements Filter {
public static final String SOURCE_REQUEST_URL_ATTRIBUTE_NAME = "sourceRequestUrl";
public static final String TARGET_REQUEST_URL_ATTRIBUTE_NAME = "targetRequestUrl";
+ public static final String SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME = "sourceRequestContextUrl";
// public static final String RESPONSE_STREAMER_ATTRIBUTE_NAME = "responseStreamer";
private static final GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/security/AbstractIdentityAssertionFilter.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/security/AbstractIdentityAssertionFilter.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/security/AbstractIdentityAssertionFilter.java
index fdd1e06..6d54246 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/security/AbstractIdentityAssertionFilter.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/filter/security/AbstractIdentityAssertionFilter.java
@@ -17,8 +17,17 @@
*/
package org.apache.hadoop.gateway.filter.security;
+import org.apache.hadoop.gateway.audit.api.Action;
+import org.apache.hadoop.gateway.audit.api.ActionOutcome;
+import org.apache.hadoop.gateway.audit.api.AuditService;
+import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
+import org.apache.hadoop.gateway.audit.api.Auditor;
+import org.apache.hadoop.gateway.audit.api.ResourceType;
+import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
import org.apache.hadoop.gateway.i18n.GatewaySpiMessages;
+import org.apache.hadoop.gateway.i18n.GatewaySpiResources;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.hadoop.gateway.security.GroupPrincipal;
import org.apache.hadoop.gateway.security.ImpersonatedPrincipal;
import org.apache.hadoop.gateway.security.PrimaryPrincipal;
@@ -42,11 +51,17 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletException;
+import java.util.Arrays;
import java.util.Set;
public abstract class AbstractIdentityAssertionFilter extends AbstractIdentityAssertionBase implements Filter {
private static final GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
+ private static final GatewaySpiResources RES = ResourcesFactory.get( GatewaySpiResources.class );
+ private static AuditService auditService = AuditServiceFactory.getAuditService();
+ private static Auditor auditor = auditService.getAuditor(
+ AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
+ AuditConstants.KNOX_COMPONENT_NAME );
protected PrincipalMapper mapper = new SimplePrincipalMapper();
public AbstractIdentityAssertionFilter() {
@@ -103,6 +118,8 @@ public abstract class AbstractIdentityAssertionFilter extends AbstractIdentityAs
if (primaryPrincipal != null) {
if (!primaryPrincipal.getName().equals(mappedPrincipalName)) {
impersonationNeeded = true;
+ auditService.getContext().setProxyUsername( mappedPrincipalName );
+ auditor.audit( Action.IDENTITY_MAPPING, primaryPrincipal.getName(), ResourceType.PRINCIPAL, ActionOutcome.SUCCESS );
}
}
else {
@@ -172,6 +189,7 @@ public abstract class AbstractIdentityAssertionFilter extends AbstractIdentityAs
private void addMappedGroupsToSubject(String mappedPrincipalName, Subject subject) {
String[] groups = mapper.mapGroupPrincipal(mappedPrincipalName);
if (groups != null) {
+ auditor.audit( Action.IDENTITY_MAPPING, mappedPrincipalName, ResourceType.PRINCIPAL, ActionOutcome.SUCCESS, RES.groupsList( Arrays.toString( groups ) ) );
for (int i = 0; i < groups.length; i++) {
subject.getPrincipals().add(new GroupPrincipal(groups[i]));
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiResources.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiResources.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiResources.java
new file mode 100644
index 0000000..b48cfb5
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/i18n/GatewaySpiResources.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.i18n;
+
+import org.apache.hadoop.gateway.i18n.resources.Resource;
+import org.apache.hadoop.gateway.i18n.resources.Resources;
+
+@Resources
+public interface GatewaySpiResources {
+ @Resource(text = "Groups: {0}")
+ String groupsList( String groups );
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-test-utils/src/main/java/org/apache/hadoop/test/log/CollectAppender.java
----------------------------------------------------------------------
diff --git a/gateway-test-utils/src/main/java/org/apache/hadoop/test/log/CollectAppender.java b/gateway-test-utils/src/main/java/org/apache/hadoop/test/log/CollectAppender.java
new file mode 100644
index 0000000..d14ab7b
--- /dev/null
+++ b/gateway-test-utils/src/main/java/org/apache/hadoop/test/log/CollectAppender.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.test.log;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.spi.LoggingEvent;
+
+public class CollectAppender extends AppenderSkeleton {
+
+ public CollectAppender() {
+ super();
+ }
+
+ public static BlockingQueue<LoggingEvent> queue = new LinkedBlockingQueue<LoggingEvent>();
+ public static boolean closed = false;
+
+ @Override
+ protected void append( LoggingEvent event ) {
+ event.getProperties();
+ queue.add( event );
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ }
+
+ @Override
+ public boolean requiresLayout() {
+ return false;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-util-common/pom.xml b/gateway-util-common/pom.xml
index f8c9e54..e8743b4 100644
--- a/gateway-util-common/pom.xml
+++ b/gateway-util-common/pom.xml
@@ -66,6 +66,10 @@
<groupId>${gateway-group}</groupId>
<artifactId>gateway-i18n</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-jdbm</artifactId>
+ </dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
@@ -89,6 +93,14 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Action.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Action.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Action.java
new file mode 100644
index 0000000..b60b367
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Action.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+public abstract class Action {
+ private Action() {
+ }
+
+ public static final String AUTHENTICATION = "authentication";
+ public static final String AUTHORIZATION = "authorization";
+ public static final String REDEPLOY = "redeploy";
+ public static final String DEPLOY = "deploy";
+ public static final String UNDEPLOY = "undeploy";
+ public static final String IDENTITY_MAPPING = "identity-mapping";
+ public static final String DISPATCH = "dispatch";
+ public static final String ACCESS = "access";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/ActionOutcome.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/ActionOutcome.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/ActionOutcome.java
new file mode 100644
index 0000000..0c864ba
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/ActionOutcome.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+/**
+ * Contains a list of possible action outcomes. It may be used to keep audit
+ * records consistent across services and components. For example, to avoid the
+ * following: "Success", "success", "SUCCESS", "Succeed" Action outcomes doesn't
+ * restricted to this list and any constants from component's source code may be
+ * used.
+ *
+ */
+public abstract class ActionOutcome {
+ private ActionOutcome() {
+ }
+
+ public static final String SUCCESS = "success";
+ public static final String FAILURE = "failure";
+ public static final String UNAVAILABLE = "unavailable";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditContext.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditContext.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditContext.java
new file mode 100644
index 0000000..be2414b
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditContext.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+/**
+ * Holds the context of the current request for auditing purposes.
+ */
+public interface AuditContext {
+
+ String getUsername();
+
+ void setUsername( String username );
+
+ String getProxyUsername();
+
+ void setProxyUsername( String proxyUsername );
+
+ String getSystemUsername();
+
+ void setSystemUsername( String systemUsername );
+
+ String getTargetServiceName();
+
+ void setTargetServiceName( String targetServiceName );
+
+ String getRemoteIp();
+
+ void setRemoteIp( String remoteIp );
+
+ String getRemoteHostname();
+
+ void setRemoteHostname( String remoteHostname );
+
+ void destroy();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditService.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditService.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditService.java
new file mode 100644
index 0000000..efc77a1
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditService.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Manipulates the audit context associated with the current thread.
+ */
+public interface AuditService {
+
+ /**
+ * Creates and attaches an "empty" audit context.
+ *
+ * @return A new, empty, attached audit context. Will never be null.
+ */
+ AuditContext createContext();
+
+ /**
+ * Retrieves the current attached audit context, if any.
+ *
+ * @return The current attached audit context if any. May be null.
+ */
+ AuditContext getContext();
+
+ /**
+ * Attaches the provided audit context to the current thread.
+ * Providing a null value will have no effect and the currently attached context if any will remain.
+ *
+ * @param context The audit context to attach to the current thread. May be null.
+ */
+ void attachContext( AuditContext context );
+
+ /**
+ * Detaches the current audit context, if any, from the current thread.
+ * This will typically be used when an audit context needs to be propagated between threads.
+ *
+ * @return The now detached audit context, if any. May be null.
+ */
+ AuditContext detachContext();
+
+ /**
+ * Retrieves an auditor configured with the the provided component and service names. Will never be null.
+ *
+ * @param auditorName The name of auditor. Can be used to separate audit events to different destinations. For example security audit, operations audit, etc
+ * @param componentName The name of component that will be placed used in every audit event generated by {@link org.apache.hadoop.gateway.audit.api.Auditor Auditor} instance
+ * @param serviceName The name of service that will be placed used in every audit event generated by {@link org.apache.hadoop.gateway.audit.api.Auditor Auditor} instance
+ */
+ Auditor getAuditor( String auditorName, String componentName, String serviceName );
+
+ /**
+ * Executes the callable within the provided audit context.
+ * The provided context is attached and detached around the invocation of the callable.
+ *
+ * @param context The context to establish around the invocation of the callable. May not be null.
+ * @param callable The callable to invoke after establishing the correlation context. May not be null.
+ * @return The result of the callable's call method.
+ * @throws Exception Thrown if thrown by the callable's call method.
+ */
+ <T> T execute( AuditContext context, Callable<T> callable ) throws Exception;
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditServiceFactory.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditServiceFactory.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditServiceFactory.java
new file mode 100644
index 0000000..ed0222b
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/AuditServiceFactory.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+import org.apache.hadoop.gateway.audit.log4j.audit.Log4jAuditService;
+
+public abstract class AuditServiceFactory {
+
+ // The global audit service instance.
+ private static AuditService auditService = null;
+
+ // To prevent instantiation.
+ private AuditServiceFactory() {
+ }
+
+ /**
+ * Provides access to the default audit service implementation.
+ * @return The default audit service implementation. Will not be null.
+ */
+ public static AuditService getAuditService() {
+ // Race condition acceptable and will only result in multiple service instantiations.
+ if( auditService == null ) {
+ auditService = new Log4jAuditService();
+ }
+ return auditService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Auditor.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Auditor.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Auditor.java
new file mode 100644
index 0000000..80d2dd3
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/Auditor.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+/**
+ * Used to record audit events.
+ */
+public interface Auditor {
+
+ /**
+ * Records a single audit event.
+ *
+ * @param correlationContext The explicit correlation context to use when recording this audit event. May not be null.
+ * @param auditContext The explicit audit context to use when recording this audit event. May not be null.
+ * @param action The action being recorded for this audit event. May not be null.
+ * @param resourceName The resource identifier to record for this audit event. May not be null.
+ * @param resourceType The resource type to record for this audit event. May not be null.
+ * @param outcome The outcome to record for this audit event. Typically the result of a authorization check. May not be null.
+ * @param message An arbitrary message to record with the audit event. May be null.
+ */
+ void audit( CorrelationContext correlationContext, AuditContext auditContext, String action,
+ String resourceName, String resourceType, String outcome, String message );
+
+ /**
+ * Records a single audit event using context information associated with the current thread.
+ *
+ * @param action The action being recorded for this audit event. May not be null.
+ * @param resourceName The resource identifier to record for this audit event. May not be null.
+ * @param resourceType The resource type to record for this audit event. May not be null.
+ * @param outcome The outcome to record for this audit event. Typically the result of a authorization check. May not be null.
+ * @param message An arbitrary message to record with the audit event. May be null.
+ */
+ void audit( String action, String resourceName, String resourceType, String outcome, String message );
+
+ /**
+ * Records a single audit event using context information associated with the current thread.
+ *
+ * @param action The action being recorded for this audit event. May not be null.
+ * @param resourceName The resource identifier to record for this audit event. May not be null.
+ * @param resourceType The resource type to record for this audit event. May not be null.
+ * @param outcome The outcome to record for this audit event. Typically the result of a authorization check. May not be null.
+ */
+ void audit( String action, String resourceName, String resourceType, String outcome );
+
+
+ /**
+ * The service name established when the Auditor was acquired.
+ * Every event logged by auditor instance will contain data about service that generated event.
+ *
+ * @return The service name established when the Auditor was acquired.
+ */
+ String getServiceName();
+
+ /**
+ * The component name established when the Auditor was acquired.
+ *
+ * @return The component name established when the Auditor was acquired.
+ */
+ String getComponentName();
+
+ /**
+ * The auditor name established when the Auditor was acquired.
+ * As an example, authentication/authorization operations may be logged to separate security log.
+ * Or actions on some resources shouldn't be logged into central storage.
+ * Auditor name provide an ability to logically group audit events, configure theirs filtration and persistence
+ *
+ * @return The auditor name established when the Auditor was acquired.
+ */
+ String getAuditorName();
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationContext.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationContext.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationContext.java
new file mode 100644
index 0000000..29b6706
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationContext.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+public interface CorrelationContext {
+
+ /**
+ * A unique value representing the current, active request.
+ *
+ * @return A unique value representing the current, active request.
+ */
+ String getRequestId();
+
+ /**
+ * A unique value representing the current, active request.
+ * If the current request id value is different from the current parent request id value then
+ * the current request id value is moved to the parent request id before it is replaced by the provided request id.
+ * If the root request id is not set it will be set with the first non-null value of either the parent request id or the passed request id.
+ *
+ * @param requestId A unique value representing the current, active request.
+ */
+ void setRequestId( String requestId );
+
+ /**
+ * The parent request ID if this is a sub-request.
+ *
+ * @return The parent request ID.
+ */
+ String getParentRequestId();
+
+ /**
+ * Sets the parent request ID if this is a sub-request.
+ *
+ * @param parentRequestId The parent request ID.
+ */
+ void setParentRequestId( String parentRequestId );
+
+ /**
+ * The root request ID if this is a sub-request.
+ *
+ * @return The root request ID.
+ */
+ String getRootRequestId();
+
+ /**
+ * Sets the root request ID if this is a sub-request.
+ *
+ * @param rootRequestId The root request ID.
+ */
+ void setRootRequestId( String rootRequestId );
+
+ /**
+ * Would be used to indicate that the context can be cleaned and reused.
+ * This is only important if the service would like to maintain a pool of available "empty" context
+ * that can be reused to limit memory allocation and garbage collection.
+ */
+ void destroy();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/f69acbbc/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationService.java
----------------------------------------------------------------------
diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationService.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationService.java
new file mode 100644
index 0000000..896298d
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/audit/api/CorrelationService.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.gateway.audit.api;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Manipulates the correlations context associated with the current thread.
+ */
+public interface CorrelationService {
+
+ /**
+ * The recommended protocol header name used to transmit the correlation context over the network.
+ */
+ static String PROTOCOL_HEADER = "X-Correlation-Context";
+
+ /**
+ * Creates a new correlation context. The context is attached and empty.
+ *
+ * @return A new correlation context.
+ */
+ CorrelationContext createContext();
+
+ /**
+ * Returns the current attached correlation context if any.
+ *
+ * @return The current attached correlation context. May be null.
+ */
+ CorrelationContext getContext();
+
+ /**
+ * Sets the current attached correlation context.
+ * Will overwrite any existing attached context if any.
+ * Null contexts are ignored and any existing attached context will remain.
+ *
+ * @param context The correlation context to attach.
+ */
+ void attachContext( CorrelationContext context );
+
+ /**
+ * Detaches the existing attached context if any.
+ * This will typically be done so that the context can be persisted or attached to a different thread.
+ *
+ * @return The now detached correlation context. May be null.
+ */
+ CorrelationContext detachContext();
+
+ /**
+ * Executes the callable within the provided correlation context.
+ * The provided context is attached and detached around the invocation of the callable.
+ * @param context The correlation context to establish around the invocation of the callable. May not be null.
+ * @param callable The callable to invoke after establishing the correlation context. May not be null.
+ * @return The result of the callable's call method.
+ * @throws Exception Thrown if thrown by the callable's call method.
+ */
+ <T> T execute( CorrelationContext context, Callable<T> callable ) throws Exception;
+
+ /**
+ * Attaches the externalized correlation context
+ * @param externalizedContext The externalized correlation context
+ * @return An attached instance of correlation context that was restored form externalized context
+ */
+ CorrelationContext attachExternalizedContext( byte[] externalizedContext );
+
+ /**
+ * Detaches the existing attached correlation context and returns it in externalized form.
+ * @return The detached externalized context
+ */
+ byte[] detachExternalizedContext();
+
+ /**
+ * Restores correlation context from externalized form.
+ * @param externalizedContext The externalized correlation context. May not be null.
+ * @return the correlation context that is not attached yet
+ */
+ CorrelationContext readExternalizedContext( byte[] externalizedContext );
+
+ /**
+ * Returns externalized correlation context without detaching it from execution scope.
+ * @return The externalized correlation context
+ */
+ byte[] getExternalizedContext();
+
+}