You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2017/02/27 12:49:06 UTC

[03/50] [abbrv] tinkerpop git commit: Added audit logging wih tests and docs

Added audit logging wih tests and docs


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/68eff1db
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/68eff1db
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/68eff1db

Branch: refs/heads/TINKERPOP-1612
Commit: 68eff1dbdcca69fe74ba968ff6d30c5db0feeec3
Parents: cb75d9b
Author: HadoopMarc <vt...@xs4all.nl>
Authored: Thu Dec 22 20:33:40 2016 +0100
Committer: HadoopMarc <vt...@xs4all.nl>
Committed: Wed Jan 18 20:05:40 2017 +0100

----------------------------------------------------------------------
 .../src/reference/gremlin-applications.asciidoc |   1 +
 .../tinkerpop/gremlin/server/GremlinServer.java |   1 +
 .../tinkerpop/gremlin/server/Settings.java      |   5 +
 .../gremlin/server/channel/HttpChannelizer.java |   2 +-
 .../gremlin/server/channel/NioChannelizer.java  |   2 +-
 .../server/channel/WebSocketChannelizer.java    |   2 +-
 .../handler/HttpBasicAuthenticationHandler.java |  19 +-
 .../handler/HttpGremlinEndpointHandler.java     |   5 +
 .../handler/SaslAuthenticationHandler.java      |  17 +-
 .../server/op/AbstractEvalOpProcessor.java      |   6 +
 .../kerby/kerberos/kerb/server/KdcTestBase.java | 172 ----------
 .../kerberos/kerb/server/LoginTestBase.java     |  90 ------
 .../kerberos/kerb/server/TestKdcServer.java     |  61 ----
 .../AbstractGremlinServerIntegrationTest.java   |   1 +
 .../tinkerpop/gremlin/server/AuditLogTest.java  | 322 +++++++++++++++++++
 .../tinkerpop/gremlin/server/AuthKrb5Test.java  | 172 +++++-----
 .../gremlin/server/AuthKrb5TestBase.java        | 130 --------
 .../tinkerpop/gremlin/server/KdcFixture.java    | 152 +++++++++
 .../gremlin/util/Log4jRecordingAppender.java    |  20 +-
 .../src/test/resources/log4j-test.properties    |   2 +-
 20 files changed, 634 insertions(+), 548 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/docs/src/reference/gremlin-applications.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index 57f43e0..70e46e5 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -1035,6 +1035,7 @@ The following table describes the various YAML configuration options that Gremli
 |=========================================================
 |Key |Description |Default
 |authentication.className |The fully qualified classname of an `Authenticator` implementation to use.  If this setting is not present, then authentication is effectively disabled. |`AllowAllAuthenticator`
+|authentication.enableAuditLog |The available authenticators can issue audit logging messages, binding the authenticated user to his remote socket address and binding requests with a gremlin query to the remote socket address. For privacy reasons, the default value of this setting is false. The audit logging messages are logged at the INFO level via the `audit.org.apache.tinkerpop.gremlin.server` logger, which can be configured using the log4j.properties file. |false
 |authentication.config |A `Map` of configuration settings to be passes to the `Authenticator` when it is constructed.  The settings available are dependent on the implementation. |_none_
 |channelizer |The fully qualified classname of the `Channelizer` implementation to use.  A `Channelizer` is a "channel initializer" which Gremlin Server uses to define the type of processing pipeline to use.  By allowing different `Channelizer` implementations, Gremlin Server can support different communication protocols (e.g. Websockets, Java NIO, etc.). |`WebSocketChannelizer`
 |graphs |A `Map` of `Graph` configuration files where the key of the `Map` becomes the name to which the `Graph` will be bound and the value is the file name of a `Graph` configuration file. |_none_

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
index ed0fd7c..703b7b1 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java
@@ -62,6 +62,7 @@ public class GremlinServer {
     }
 
     private static final String SERVER_THREAD_PREFIX = "gremlin-server-";
+    public static final String AUDIT_LOGGER_NAME = "audit.org.apache.tinkerpop.gremlin.server";
 
     private static final Logger logger = LoggerFactory.getLogger(GremlinServer.class);
     private final Settings settings;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
index 97e2875..fc0560f 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
@@ -383,6 +383,11 @@ public class Settings {
         public String className = AllowAllAuthenticator.class.getName();
 
         /**
+         * Enable audit logging of authenticated users and gremlin evaluation requests.
+         */
+        public boolean enableAuditLog = false;
+
+        /**
          * A {@link Map} containing {@link Authenticator} specific configurations. Consult the
          * {@link Authenticator} implementation for specifics on what configurations are expected.
          */

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
index 5c632e6..b509e2d 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/HttpChannelizer.java
@@ -68,7 +68,7 @@ public class HttpChannelizer extends AbstractChannelizer {
             // not occur. It may not be a safe assumption that the handler
             // is sharable so create a new handler each time.
             authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
-                    null : new HttpBasicAuthenticationHandler(authenticator);
+                    null : new HttpBasicAuthenticationHandler(authenticator, settings.authentication);
             if (authenticationHandler != null)
                 pipeline.addLast(PIPELINE_AUTHENTICATOR, authenticationHandler);
         }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java
index d2ba520..4baad23 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/NioChannelizer.java
@@ -52,7 +52,7 @@ public class NioChannelizer extends AbstractChannelizer {
         // configure authentication - null means don't bother to add authentication to the pipeline
         if (authenticator != null)
             authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
-                    null : new SaslAuthenticationHandler(authenticator);
+                    null : new SaslAuthenticationHandler(authenticator, settings.authentication);
 
         gremlinResponseFrameEncoder = new GremlinResponseFrameEncoder();
         nioGremlinResponseFrameEncoder = new NioGremlinResponseFrameEncoder();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
index 2373819..ea59e8f 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/channel/WebSocketChannelizer.java
@@ -67,7 +67,7 @@ public class WebSocketChannelizer extends AbstractChannelizer {
         // configure authentication - null means don't bother to add authentication to the pipeline
         if (authenticator != null)
             authenticationHandler = authenticator.getClass() == AllowAllAuthenticator.class ?
-                    null : new SaslAuthenticationHandler(authenticator);
+                    null : new SaslAuthenticationHandler(authenticator, settings.authentication);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
index bf3b674..1beb7cf 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpBasicAuthenticationHandler.java
@@ -24,8 +24,13 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.handler.codec.http.DefaultFullHttpResponse;
 import io.netty.handler.codec.http.FullHttpMessage;
 import io.netty.util.ReferenceCountUtil;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.Settings;
+import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.nio.charset.Charset;
 import java.util.Base64;
@@ -43,12 +48,17 @@ import static org.apache.tinkerpop.gremlin.groovy.plugin.dsl.credential.Credenti
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class HttpBasicAuthenticationHandler extends ChannelInboundHandlerAdapter {
+    private static final Logger logger = LoggerFactory.getLogger(HttpBasicAuthenticationHandler.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
     private final Authenticator authenticator;
+    private final Settings.AuthenticationSettings authenticationSettings;
 
     private final Base64.Decoder decoder = Base64.getUrlDecoder();
 
-    public HttpBasicAuthenticationHandler(final Authenticator authenticator) {
+    public HttpBasicAuthenticationHandler(final Authenticator authenticator,
+                                          final Settings.AuthenticationSettings authenticationSettings) {
         this.authenticator = authenticator;
+        this.authenticationSettings = authenticationSettings;
     }
 
     @Override
@@ -92,6 +102,13 @@ public class HttpBasicAuthenticationHandler extends ChannelInboundHandlerAdapter
             try {
                 authenticator.authenticate(credentials);
                 ctx.fireChannelRead(request);
+
+                // User name logged with the remote socket address and authenticator classname for audit logging
+                if (authenticationSettings.enableAuditLog) {
+                    String[] authClassParts = authenticator.getClass().toString().split("[.]");
+                    auditLogger.info("User {} with address {} authenticated by {}", credentials.get(PROPERTY_USERNAME),
+                            ctx.channel().remoteAddress().toString().substring(1), authClassParts[authClassParts.length - 1]);
+                }
             } catch (AuthenticationException ae) {
                 sendError(ctx, msg);
             }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
index ad11834..2afe4b5 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/HttpGremlinEndpointHandler.java
@@ -100,6 +100,7 @@ import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
 @ChannelHandler.Sharable
 public class HttpGremlinEndpointHandler extends ChannelInboundHandlerAdapter {
     private static final Logger logger = LoggerFactory.getLogger(HttpGremlinEndpointHandler.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
     private static final Charset UTF8 = Charset.forName("UTF-8");
     static final Meter errorMeter = MetricManager.INSTANCE.getMeter(name(GremlinServer.class, "errors"));
 
@@ -188,6 +189,10 @@ public class HttpGremlinEndpointHandler extends ChannelInboundHandlerAdapter {
             try {
                 logger.debug("Processing request containing script [{}] and bindings of [{}] on {}",
                         requestArguments.getValue0(), requestArguments.getValue1(), Thread.currentThread().getName());
+                if (settings.authentication.enableAuditLog) {
+                    final String address = ctx.channel().remoteAddress().toString().substring(1);
+                    auditLogger.info("User with address {} requested: {}", address, requestArguments.getValue0());
+                }
                 final ChannelPromise promise = ctx.channel().newPromise();
                 final AtomicReference<Object> resultHolder = new AtomicReference<>();
                 promise.addListener(future -> {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
index 6cb0ddb..0878246 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
@@ -35,6 +35,8 @@ import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.server.GremlinServer;
+import org.apache.tinkerpop.gremlin.server.Settings;
 import org.apache.tinkerpop.gremlin.server.auth.AuthenticatedUser;
 import org.apache.tinkerpop.gremlin.server.auth.AuthenticationException;
 import org.apache.tinkerpop.gremlin.server.auth.Authenticator;
@@ -55,11 +57,14 @@ public class SaslAuthenticationHandler extends ChannelInboundHandlerAdapter {
     private static final Logger logger = LoggerFactory.getLogger(SaslAuthenticationHandler.class);
     private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
     private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
 
     private final Authenticator authenticator;
+    private final Settings.AuthenticationSettings authenticationSettings;
 
-    public SaslAuthenticationHandler(final Authenticator authenticator) {
+    public SaslAuthenticationHandler(final Authenticator authenticator, final Settings.AuthenticationSettings authenticationSettings) {
         this.authenticator = authenticator;
+        this.authenticationSettings = authenticationSettings;
     }
 
     @Override
@@ -93,13 +98,17 @@ public class SaslAuthenticationHandler extends ChannelInboundHandlerAdapter {
                         ctx.writeAndFlush(error);
                         return;
                     }
-                    
+
                     try {
                         final byte[] saslMessage = negotiator.get().evaluateResponse(saslResponse);
                         if (negotiator.get().isComplete()) {
-                            // todo: do something with this user
                             final AuthenticatedUser user = negotiator.get().getAuthenticatedUser();
-
+                            // User name logged with the remote socket address and authenticator classname for audit logging
+                            if (authenticationSettings.enableAuditLog) {
+                                String[] authClassParts = authenticator.getClass().toString().split("[.]");
+                                auditLogger.info("User {} with address {} authenticated by {}", user.getName(),
+                                        ctx.channel().remoteAddress().toString().substring(1), authClassParts[authClassParts.length - 1]);
+                            }
                             // If we have got here we are authenticated so remove the handler and pass
                             // the original message down the pipeline for processing
                             ctx.pipeline().remove(this);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
index 48de830..baff5b7 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
@@ -46,6 +46,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.script.Bindings;
 import javax.script.SimpleBindings;
+import java.net.SocketAddress;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -67,6 +68,7 @@ import static com.codahale.metrics.MetricRegistry.name;
  */
 public abstract class AbstractEvalOpProcessor extends AbstractOpProcessor {
     private static final Logger logger = LoggerFactory.getLogger(AbstractEvalOpProcessor.class);
+    private static final Logger auditLogger = LoggerFactory.getLogger(GremlinServer.AUDIT_LOGGER_NAME);
     public static final Timer evalOpTimer = MetricManager.INSTANCE.getTimer(name(GremlinServer.class, "op", "eval"));
 
     /**
@@ -243,6 +245,10 @@ public abstract class AbstractEvalOpProcessor extends AbstractOpProcessor {
                     final Iterator itty = IteratorUtils.asIterator(o);
 
                     logger.debug("Preparing to iterate results from - {} - in thread [{}]", msg, Thread.currentThread().getName());
+                    if (settings.authentication.enableAuditLog) {
+                        final String address = context.getChannelHandlerContext().channel().remoteAddress().toString().substring(1);
+                        auditLogger.info("User with address {} requested: {}", address, script);
+                    }
 
                     try {
                         handleIterator(context, itty);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java b/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
deleted file mode 100644
index 15663cb..0000000
--- a/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- *  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.kerby.kerberos.kerb.server;
-
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.client.KrbClient;
-import org.apache.kerby.kerberos.kerb.client.KrbPkinitClient;
-import org.apache.kerby.kerberos.kerb.client.KrbTokenClient;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-
-import java.io.File;
-import java.io.IOException;
-
-/*
- * This file is based on:
- *     https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2/
- *         kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/KdcTestBase.java
- * but with the following changes:
- *   - added this comment
- *   - made allowUdp() return false because of issues with UDP in the RC2 release, see directory-kerby on JIRA
- *
- * See also: gremlin-server/src/main/static/NOTICE
- */
-public abstract class KdcTestBase {
-    private static File testDir;
-
-    private final String clientPassword = "123456";
-    private final String hostname = "localhost";
-    private final String clientPrincipalName = "drankye";
-    private final String clientPrincipal =
-            clientPrincipalName + "@" + TestKdcServer.KDC_REALM;
-    private final String serverPrincipalName = "test-service";
-    private final String serverPrincipal =
-            serverPrincipalName + "/" + hostname + "@" + TestKdcServer.KDC_REALM;
-
-    private SimpleKdcServer kdcServer;
-
-    @BeforeClass
-    public static void createTestDir() throws IOException {
-        String basedir = System.getProperty("basedir");
-        if (basedir == null) {
-            basedir = new File(".").getCanonicalPath();
-        }
-        File targetdir = new File(basedir, "target");
-        testDir = new File(targetdir, "tmp");
-        testDir.mkdirs();
-    }
-
-    @AfterClass
-    public static void deleteTestDir() throws IOException {
-        testDir.delete();
-    }
-
-    protected File getTestDir() {
-        return testDir;
-    }
-
-    protected SimpleKdcServer getKdcServer() {
-        return kdcServer;
-    }
-
-    protected KrbClient getKrbClient() {
-        return kdcServer.getKrbClient();
-    }
-
-    protected KrbPkinitClient getPkinitClient() {
-        return kdcServer.getPkinitClient();
-    }
-
-    protected KrbTokenClient getTokenClient() {
-        return kdcServer.getTokenClient();
-    }
-
-    protected String getClientPrincipalName() {
-        return clientPrincipalName;
-    }
-
-    protected String getClientPrincipal() {
-        return clientPrincipal;
-    }
-
-    protected String getServerPrincipalName() {
-        return serverPrincipalName;
-    }
-
-    protected String getClientPassword() {
-        return clientPassword;
-    }
-
-    protected String getServerPrincipal() {
-        return serverPrincipal;
-    }
-
-    protected String getHostname() {
-        return hostname;
-    }
-
-    protected boolean allowUdp() {
-        return false;
-    }   // originally: true
-
-    protected boolean allowTcp() {
-        return true;
-    }
-    
-    @Before
-    public void setUp() throws Exception {
-        setUpKdcServer();
-
-        createPrincipals();
-
-        setUpClient();
-    }
-
-    protected void prepareKdc() throws KrbException {
-        kdcServer.init();
-    }
-
-    protected void configKdcSeverAndClient() {
-        kdcServer.setWorkDir(testDir);
-    }
-
-    protected void setUpKdcServer() throws Exception {
-        kdcServer = new TestKdcServer(allowTcp(), allowUdp());
-
-        configKdcSeverAndClient();
-
-        prepareKdc();
-
-        kdcServer.start();
-    }
-
-    protected void setUpClient() throws Exception {
-    }
-
-    protected void createPrincipals() throws KrbException {
-        kdcServer.createPrincipals(serverPrincipal);
-        kdcServer.createPrincipal(clientPrincipal, clientPassword);
-    }
-
-    protected void deletePrincipals() throws KrbException {
-        kdcServer.getKadmin().deleteBuiltinPrincipals();
-        kdcServer.deletePrincipals(serverPrincipal);
-        kdcServer.deletePrincipal(clientPrincipal);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        deletePrincipals();
-        kdcServer.stop();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java b/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
deleted file mode 100644
index ed805fa..0000000
--- a/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- *  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.kerby.kerberos.kerb.server;
-
-import org.apache.kerby.kerberos.kerb.client.JaasKrbUtil;
-import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-import java.io.File;
-import java.security.Principal;
-import java.util.Set;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import org.junit.After;
-import org.junit.Before;
-
-/*
- * Except for this comment and the removal of the org.assertj.core.api.Assertions.assertThat import statement,
- * this file is a literal copy from:
- *     https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2/
- *         kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/LoginTestBase.java
- *
- * See also: gremlin-server/src/main/static/NOTICE
- */
-public class LoginTestBase extends KdcTestBase {
-
-    protected File ticketCacheFile;
-    protected File serviceKeytabFile;
-
-    @Before
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-
-        ticketCacheFile = new File(getTestDir(), "test-tkt.cc");
-        serviceKeytabFile = new File(getTestDir(), "test-service.keytab");
-    }
-
-    protected Subject loginClientUsingPassword() throws LoginException {
-        return JaasKrbUtil.loginUsingPassword(getClientPrincipal(),
-            getClientPassword());
-    }
-
-    protected Subject loginClientUsingTicketCache() throws Exception {
-        TgtTicket tgt = getKrbClient().requestTgt(getClientPrincipal(),
-            getClientPassword());
-        getKrbClient().storeTicket(tgt, ticketCacheFile);
-
-        return JaasKrbUtil.loginUsingTicketCache(getClientPrincipal(),
-            ticketCacheFile);
-    }
-
-    protected Subject loginServiceUsingKeytab() throws Exception {
-        getKdcServer().exportPrincipal(getServerPrincipal(), serviceKeytabFile);
-        return JaasKrbUtil.loginUsingKeytab(getServerPrincipal(),
-            serviceKeytabFile);
-    }
-
-    protected void checkSubject(Subject subject) {
-        Set<Principal> clientPrincipals = subject.getPrincipals();
-        assertThat("The subject has minimally one principal", clientPrincipals.size() > 0);
-    }
-
-    @After
-    @Override
-    public void tearDown() throws Exception {
-        ticketCacheFile.delete();
-        serviceKeytabFile.delete();
-
-        super.tearDown();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcServer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcServer.java b/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcServer.java
deleted file mode 100644
index 3addc88..0000000
--- a/gremlin-server/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcServer.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- *  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.kerby.kerberos.kerb.server;
-
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.client.KrbClient;
-import org.apache.kerby.kerberos.kerb.client.KrbConfig;
-import org.apache.kerby.kerberos.kerb.client.KrbConfigKey;
-import org.apache.kerby.util.NetworkUtil;
-
-/*
- * Except for this comment, this file is a literal copy from:
- *     https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2/
- *         kerby-kerb/kerb-kdc-test/src/test/java/org/apache/kerby/kerberos/kerb/server/TestKdcServer.java
- *
- * See also: gremlin-server/src/main/static/NOTICE
- */
-public class TestKdcServer extends SimpleKdcServer {
-    public static final String KDC_REALM = "TEST.COM";
-    public static final String HOSTNAME = "localhost";
-
-    public TestKdcServer(boolean allowTcp, boolean allowUdp) throws KrbException {
-        super();
-
-        setKdcRealm(KDC_REALM);
-        setKdcHost(HOSTNAME);
-        setAllowTcp(allowTcp);
-        setAllowUdp(allowUdp);
-
-        if (allowTcp) {
-            setKdcTcpPort(NetworkUtil.getServerPort());
-        }
-        if (allowUdp) {
-            setKdcUdpPort(NetworkUtil.getServerPort());
-        }
-
-        KrbClient krbClnt = getKrbClient();
-        KrbConfig krbConfig = krbClnt.getKrbConfig();
-        krbConfig.setString(KrbConfigKey.PERMITTED_ENCTYPES,
-                "aes128-cts-hmac-sha1-96 des-cbc-crc des-cbc-md5 des3-cbc-sha1");
-
-        krbClnt.setTimeout(10 * 1000);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
index 12fadb6..56a599f 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuditLogTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuditLogTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuditLogTest.java
new file mode 100644
index 0000000..d8337e8
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuditLogTest.java
@@ -0,0 +1,322 @@
+/*
+ * 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.tinkerpop.gremlin.server;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import static org.apache.log4j.Level.INFO;
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.Channelizer;
+import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
+import org.apache.tinkerpop.gremlin.server.channel.NioChannelizer;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.gremlin.server.auth.AllowAllAuthenticator;
+import org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator;
+import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
+import static org.apache.tinkerpop.gremlin.server.AuthKrb5Test.TESTCONSOLE;
+import static org.apache.tinkerpop.gremlin.server.GremlinServer.AUDIT_LOGGER_NAME;
+import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
+import org.slf4j.LoggerFactory;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+/**
+ * @author Marc de Lignie
+ *
+ * Note: like other descendents of AbstractGremlinServerIntegrationTest this testsuite assumes that tests are
+ *       run sequentially and thus the server variable can be reused.
+ */
+public class AuditLogTest extends AbstractGremlinServerIntegrationTest {
+    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AuditLogTest.class);
+    private Log4jRecordingAppender recordingAppender = null;
+
+    private final ObjectMapper mapper = new ObjectMapper();
+    private final Base64.Encoder encoder = Base64.getUrlEncoder();
+
+    private static final boolean AUDIT_LOG_ENABLED = true;
+    private static final boolean AUDIT_LOG_DISABLED = false;
+
+    private KdcFixture kdcServer;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        try {
+            final String buildDir = System.getProperty("build.dir");
+            kdcServer = new KdcFixture(buildDir +
+                    "/test-classes/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf");
+            kdcServer.setUp();
+        } catch(Exception e)  {
+            logger.warn(e.getMessage());
+        }
+        super.setUp();
+    }
+
+    @Before
+    public void setupForEachTest() {
+        recordingAppender = new Log4jRecordingAppender();
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.addAppender(recordingAppender);
+    }
+
+    @After
+    public void teardownForEachTest() {
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.removeAppender(recordingAppender);
+    }
+
+    /**
+     * Configure specific Gremlin Server settings for specific tests.
+     */
+    @Override
+    public Settings overrideSettings(final Settings settings) {
+        settings.host = kdcServer.hostname;
+        final Settings.SslSettings sslConfig = new Settings.SslSettings();
+        sslConfig.enabled = false;
+        settings.ssl = sslConfig;
+        final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
+        settings.authentication = authSettings;
+        authSettings.enableAuditLog = AUDIT_LOG_ENABLED;
+        authSettings.className = Krb5Authenticator.class.getName();
+        final Map<String,Object> authConfig = new HashMap<>();
+        authSettings.config = authConfig;
+
+        final String nameOfTest = name.getMethodName();
+        switch (nameOfTest) {
+            case "shouldAuditLogWithAllowAllAuthenticator":
+                authSettings.className = AllowAllAuthenticator.class.getName();
+                break;
+            case "shouldAuditLogWithSimpleAuthenticator":
+                authSettings.className = SimpleAuthenticator.class.getName();
+                authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
+                break;
+            case "shouldNotAuditLogWhenDisabled":
+                authSettings.enableAuditLog = AUDIT_LOG_DISABLED;
+            case "shouldAuditLogWithKrb5Authenticator":
+                authConfig.put("keytab", kdcServer.serviceKeytabFile.getAbsolutePath());
+                authConfig.put("principal", kdcServer.serverPrincipal);
+                break;
+            case "shouldAuditLogWithNioTransport":
+                settings.channelizer = NioChannelizer.class.getName();
+                authConfig.put("keytab", kdcServer.serviceKeytabFile.getAbsolutePath());
+                authConfig.put("principal", kdcServer.serverPrincipal);
+                break;
+            case "shouldAuditLogWithHttpTransport":
+                settings.host = "localhost";
+                settings.channelizer = HttpChannelizer.class.getName();
+                authSettings.className = SimpleAuthenticator.class.getName();
+                authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_DB, "conf/tinkergraph-credentials.properties");
+                break;
+        }
+        return settings;
+    }
+
+    @Test
+    public void shouldAuditLogWithAllowAllAuthenticator() throws Exception {
+
+        final Cluster cluster = TestClientFactory.build().credentials("sdfsdf", "")
+                .addContactPoint(kdcServer.hostname).create();
+        final Client client = cluster.connect();
+
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        // WebSocketChannelizer does not add SaslAuthenticationHandler, so no authenticated user log line available
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .*? requested: 1\\+1"));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .*? requested: 1\\+2"));
+        assertTrue(recordingAppender.logMatchesAny(AUDIT_LOGGER_NAME, INFO, "User with address .*? requested: 1\\+3"));
+    }
+
+    @Test
+    public void shouldAuditLogWithSimpleAuthenticator() throws Exception {
+        final String username = "stephen";
+        final String password = "password";
+
+        final Cluster cluster = TestClientFactory.build().credentials(username, password)
+                .addContactPoint(kdcServer.hostname).create();
+        final Client client = cluster.connect();
+
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        final String simpleAuthenticatorName = SimpleAuthenticator.class.getSimpleName();
+        final String authMsg = recordingAppender.getMessages().stream()
+                .filter( msg -> msg.toString().contains("by " + simpleAuthenticatorName) ).iterator().next();
+        final Matcher m = Pattern.compile(".*?([\\d.:]+).*?").matcher(authMsg);
+        m.find();
+        final String address = m.group(1);
+
+        assertTrue(recordingAppender.logContainsAny(AUDIT_LOGGER_NAME, INFO,
+                String.format("User %s with address %s authenticated by %s", username, address, simpleAuthenticatorName)));
+        assertTrue(recordingAppender.logContainsAny(AUDIT_LOGGER_NAME, INFO,
+                String.format("User with address %s requested: 1+1", address)));
+        assertTrue(recordingAppender.logContainsAny(AUDIT_LOGGER_NAME, INFO,
+                String.format("User with address %s requested: 1+2", address)));
+        assertTrue(recordingAppender.logContainsAny(AUDIT_LOGGER_NAME, INFO,
+                String.format("User with address %s requested: 1+3", address)));
+    }
+
+    @Test
+    public void shouldAuditLogWithKrb5Authenticator() throws Exception {
+        final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE)
+                .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
+        final Client client = cluster.connect();
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        final Matcher m = Pattern.compile(".*?([\\d.:]+).*?").matcher(authMsg);
+        m.find();
+        final String address = m.group(1);
+        assertTrue(authEvent.getLevel() == INFO && authMsg.equals(
+                String.format("User %s with address %s authenticated by Krb5Authenticator", kdcServer.clientPrincipalName, address)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1+1", address))));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1+2", address))));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1+3", address))));
+    }
+
+    @Test
+    public void shouldNotAuditLogWhenDisabled() throws Exception {
+        final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE)
+                .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
+        final Client client = cluster.connect();
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User .*? with address .*? authenticated by Krb5Authenticator")));
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .*? requested: 1\\+1")));
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().matches("User with address .*? requested: 1\\+2")));
+        assertFalse(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+            item.getMessage().toString().matches("User with address .*? requested: 1\\+3")));
+    }
+
+    @Test
+    public void shouldAuditLogWithNioTransport() throws Exception {
+        // ToDo issue (outside scope of this suite): .channelizer(Channelizer.NioChannelizer.class) fails
+        final Cluster cluster = TestClientFactory.build().channelizer(Channelizer.NioChannelizer.class.getName())
+                .jaasEntry(TESTCONSOLE).protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
+        final Client client = cluster.connect();
+        try {
+            assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
+            assertEquals(3, client.submit("1+2").all().get().get(0).getInt());
+            assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
+        } finally {
+            cluster.close();
+        }
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains("Krb5Authenticator")).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        final Matcher m = Pattern.compile(".*?([\\d.:]+).*?").matcher(authMsg);
+        m.find();
+        final String address = m.group(1);
+        assertTrue(authEvent.getLevel() == INFO && authMsg.equals(
+                String.format("User %s with address %s authenticated by Krb5Authenticator", kdcServer.clientPrincipalName, address)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1+1", address))));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1+2", address))));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1+3", address))));
+    }
+
+    @Test
+    public void shouldAuditLogWithHttpTransport() throws Exception {
+        final CloseableHttpClient httpclient = HttpClients.createDefault();
+        final HttpGet httpget = new HttpGet(TestClientFactory.createURLString("?gremlin=1-1"));
+        httpget.addHeader("Authorization", "Basic " + encoder.encodeToString("stephen:password".getBytes()));
+
+        final CloseableHttpResponse response = httpclient.execute(httpget);
+        assertEquals(200, response.getStatusLine().getStatusCode());
+        assertEquals("application/json", response.getEntity().getContentType().getValue());
+        final String json = EntityUtils.toString(response.getEntity());
+        final JsonNode node = mapper.readTree(json);
+        response.close();
+        assertEquals(0, node.get("result").get("data").get(0).intValue());
+
+        final List<LoggingEvent> log = recordingAppender.getEvents();
+        final Stream<LoggingEvent> auditEvents = log.stream().filter(event -> event.getLoggerName().equals(AUDIT_LOGGER_NAME));
+        final LoggingEvent authEvent = auditEvents
+                .filter(event -> event.getMessage().toString().contains("SimpleAuthenticator")).iterator().next();
+        final String authMsg = authEvent.getMessage().toString();
+        final Matcher m = Pattern.compile(".*?([\\d.:]+).*?").matcher(authMsg);
+        m.find();
+        final String address = m.group(1);
+        assertTrue(authEvent.getLevel() == INFO && authMsg.equals(
+                String.format("User %s with address %s authenticated by SimpleAuthenticator", "stephen", address)));
+        assertTrue(log.stream().anyMatch(item -> item.getLevel() == INFO &&
+                item.getMessage().toString().equals(String.format("User with address %s requested: 1-1", address))));
+    }
+
+    //ToDo: test with two clients
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5Test.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5Test.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5Test.java
index b87c170..6d596af 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5Test.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5Test.java
@@ -19,28 +19,25 @@
 package org.apache.tinkerpop.gremlin.server;
 
 import org.apache.commons.lang.exception.ExceptionUtils;
-import org.apache.log4j.AppenderSkeleton;
 import org.apache.log4j.Logger;
-import org.apache.log4j.Level;
-import org.apache.log4j.spi.LoggingEvent;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator;
+import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
 import org.ietf.jgss.GSSException;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.apache.tinkerpop.gremlin.driver.Client;
-import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.slf4j.LoggerFactory;
 
 import java.io.File;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
 import javax.security.auth.login.LoginException;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import org.junit.Test;
 
 
 
@@ -49,14 +46,84 @@ import org.junit.Test;
  *
  * Todo: change back to integrate test later on
  */
-public class AuthKrb5Test extends AuthKrb5TestBase {
-    // Cannot use mere slf4j because need to check log output
-    private final Logger rootLogger = Logger.getRootLogger();
-    private final Logger logger = Logger.getLogger(AuthKrb5Test.class);
+public class AuthKrb5Test extends AbstractGremlinServerIntegrationTest {
+    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AuthKrb5Test.class);
+    private Log4jRecordingAppender recordingAppender = null;
+
+    static final String TESTCONSOLE = "GremlinConsole";
+    static final String TESTCONSOLE_NOT_LOGGED_IN = "UserNotLoggedIn";
+
+    private KdcFixture kdcServer;
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        setupForEachTest();
+        try {
+            final String buildDir = System.getProperty("build.dir");
+            kdcServer = new KdcFixture(buildDir +
+                    "/test-classes/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf");
+            kdcServer.setUp();
+        } catch(Exception e)  {
+            logger.warn(e.getMessage());
+        }
+        super.setUp();
+    }
+
+    public void setupForEachTest() {
+        recordingAppender = new Log4jRecordingAppender();
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.addAppender(recordingAppender);
+    }
 
-    private GremlinServerAuthKrb5Integrate server;
-    private static final String TESTCONSOLE = "GremlinConsole";
-    private static final String TESTCONSOLE_NOT_LOGGED_IN = "UserNotLoggedIn";
+    @After
+    public void teardownForEachTest() {
+        final Logger rootLogger = Logger.getRootLogger();
+        rootLogger.removeAppender(recordingAppender);
+    }
+
+    /**
+     * Configure specific Gremlin Server settings for specific tests.
+     */
+    @Override
+    public Settings overrideSettings(final Settings settings) {
+        settings.host = kdcServer.hostname;
+        final Settings.SslSettings sslConfig = new Settings.SslSettings();
+        sslConfig.enabled = false;
+        settings.ssl = sslConfig;
+        final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
+        settings.authentication = authSettings;
+        authSettings.className = Krb5Authenticator.class.getName();
+        final Map<String,Object> authConfig = new HashMap<>();
+        authConfig.put("principal", kdcServer.serverPrincipal);
+        authConfig.put("keytab", kdcServer.serviceKeytabFile.getAbsolutePath());
+        authSettings.config = authConfig;
+
+        final String nameOfTest = name.getMethodName();
+        switch (nameOfTest) {
+            case "shouldAuthenticateWithDefaults":
+            case "shouldFailWithoutClientJaasEntry":
+            case "shouldFailWithoutClientTicketCache":
+                break;
+            case "shouldFailWithNonexistentServerPrincipal":
+                authConfig.put("principal", "no-service");
+                break;
+            case "shouldFailWithEmptyServerKeytab":
+                final File keytabFile = new File(".", "no-file");
+                authConfig.put("keytab", keytabFile);
+                break;
+            case "shouldFailWithWrongServerKeytab":
+                final String principal = "no-principal/somehost@TEST.COM";
+                try { kdcServer.createPrincipal(principal); } catch(Exception e) {
+                    logger.error("Cannot create principal in overrideSettings(): " + e.getMessage());
+                };
+                authConfig.put("principal", principal);
+                break;
+            case "shouldAuthenticateWithQop":
+                break;
+        }
+        return settings;
+    }
 
     /**
      * Defaults from TestClientFactory:
@@ -89,10 +156,8 @@ public class AuthKrb5Test extends AuthKrb5TestBase {
      */
     @Test
     public void shouldAuthenticateWithDefaults() throws Exception {
-        server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), serviceKeytabFile);
-        server.setUp();
         final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE)
-            .protocol(getServerPrincipalName()).addContactPoint(getHostname()).create();
+            .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
         final Client client = cluster.connect();
         try {
             assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
@@ -100,16 +165,13 @@ public class AuthKrb5Test extends AuthKrb5TestBase {
             assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
         } finally {
             cluster.close();
-            server.tearDown();
         }
     }
 
     @Test
     public void shouldFailWithoutClientJaasEntry() throws Exception {
-        server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), serviceKeytabFile);
-        server.setUp();
-        final Cluster cluster = TestClientFactory.build().protocol(getServerPrincipalName())
-                .addContactPoint(getHostname()).create();
+        final Cluster cluster = TestClientFactory.build().protocol(kdcServer.serverPrincipalName)
+                .addContactPoint(kdcServer.hostname).create();
         final Client client = cluster.connect();
         try {
             client.submit("1+1").all().get();
@@ -119,16 +181,13 @@ public class AuthKrb5Test extends AuthKrb5TestBase {
             assertEquals(GSSException.class, root.getClass());
         } finally {
             cluster.close();
-            server.tearDown();
         }
     }
 
     @Test
     public void shouldFailWithoutClientTicketCache() throws Exception {
-        server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), serviceKeytabFile);
-        server.setUp();
         final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE_NOT_LOGGED_IN)
-                .protocol(getServerPrincipalName()).addContactPoint(getHostname()).create();
+                .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
         final Client client = cluster.connect();
         try {
             client.submit("1+1").all().get();
@@ -138,80 +197,30 @@ public class AuthKrb5Test extends AuthKrb5TestBase {
             assertEquals(LoginException.class, root.getClass());
         } finally {
             cluster.close();
-            server.tearDown();
         }
     }
 
     @Test
     public void shouldFailWithNonexistentServerPrincipal() throws Exception {
-        final TestAppender appender = new TestAppender();
-        rootLogger.addAppender(appender);
-        server = new GremlinServerAuthKrb5Integrate("no-service", serviceKeytabFile);
-        server.setUp();
-        server.tearDown();
-
-        final List<LoggingEvent> log = appender.getLog();
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == Level.WARN &&
-                item.getMessage() == "Failed to login to kdc"));
-    }
-
-    class TestAppender extends AppenderSkeleton {
-        private final List<LoggingEvent> log = new ArrayList<LoggingEvent>();
-
-        @Override
-        public boolean requiresLayout() {
-            return false;
-        }
-
-        protected void append(final LoggingEvent loggingEvent) {
-            log.add(loggingEvent);
-        }
-
-        @Override
-        public void close() {
-        }
-
-        public List<LoggingEvent> getLog() {
-            return new ArrayList<LoggingEvent>(log);
-        }
+        assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
     }
 
     @Test
     public void shouldFailWithEmptyServerKeytab() throws Exception {
-        final TestAppender appender = new TestAppender();
-        rootLogger.addAppender(appender);
-        final File keytabFile = new File(".", "no-file");
-        server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), keytabFile);
-        server.setUp();
-        server.tearDown();
-
-        final List<LoggingEvent> log = appender.getLog();
-        for (LoggingEvent event: log) {
-            System.out.println("Log: " + event.getLevel() + " " + event.getMessage());
-        }
-        assertTrue(log.stream().anyMatch(item -> item.getLevel() == Level.WARN &&
-                item.getMessage() == "Failed to login to kdc"));
+        assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
     }
 
     @Test
     public void shouldFailWithWrongServerKeytab() throws Exception {
-        final TestAppender appender = new TestAppender();
-        rootLogger.addAppender(appender);
-        final String principal = "no-principal/somehost@TEST.COM";
-        getKdcServer().createPrincipal(principal);
-        server = new GremlinServerAuthKrb5Integrate(principal, serviceKeytabFile);
-        server.setUp();
-        server.tearDown();
+        assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
     }
 
     @Test
     public void shouldAuthenticateWithQop() throws Exception {
-        server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), serviceKeytabFile);
-        server.setUp();
         final String oldQop = System.getProperty("javax.security.sasl.qop", "");
         System.setProperty("javax.security.sasl.qop", "auth-conf");
         final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE)
-                .protocol(getServerPrincipalName()).addContactPoint(getHostname()).create();
+                .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
         final Client client = cluster.connect();
         try {
             assertEquals(2, client.submit("1+1").all().get().get(0).getInt());
@@ -219,7 +228,6 @@ public class AuthKrb5Test extends AuthKrb5TestBase {
             assertEquals(4, client.submit("1+3").all().get().get(0).getInt());
         } finally {
             cluster.close();
-            server.tearDown();
             System.setProperty("javax.security.sasl.qop", oldQop);
         }
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5TestBase.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5TestBase.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5TestBase.java
deleted file mode 100644
index ccf6f9f..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5TestBase.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.tinkerpop.gremlin.server;
-
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.server.LoginTestBase;
-import org.apache.kerby.kerberos.kerb.server.TestKdcServer;
-import org.apache.tinkerpop.gremlin.server.auth.Krb5Authenticator;
-
-import java.io.File;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.util.*;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * @author Marc de Lignie
- */
-public class AuthKrb5TestBase extends LoginTestBase {
-    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AuthKrb5TestBase.class);
-
-    private String safeHostname = null;
-    private String safeServerPrincipal = null;
-
-    public AuthKrb5TestBase() {
-        // Hostname setting must be consistent with the way gremlin-console sets gremlin-server's hostname
-        // and derives gremlin-server's principal name. Also, the hostname needs to be lowercase for use
-        // in principal names.
-        try {
-            safeHostname = Inet4Address.getLocalHost().getCanonicalHostName().toLowerCase();
-            safeServerPrincipal = getServerPrincipalName() + "/" + getHostname() + "@" + TestKdcServer.KDC_REALM;
-        } catch (UnknownHostException e) {
-            logger.error("Hostname not found");
-        }
-    }
-
-    @Rule
-    public TestName name = new TestName();
-
-    @Override
-    protected String getHostname() {
-        return safeHostname;
-    }
-
-    @Override
-    protected String getServerPrincipal() { return safeServerPrincipal; }
-
-    @Override
-    protected void createPrincipals() throws KrbException {
-        getKdcServer().createPrincipals(getServerPrincipal());
-        getKdcServer().createPrincipal(getClientPrincipal(), getClientPassword());
-    }
-
-    @Override
-    protected void deletePrincipals() throws KrbException {
-        getKdcServer().getKadmin().deleteBuiltinPrincipals();
-        getKdcServer().deletePrincipals(getServerPrincipal());
-        getKdcServer().deletePrincipal(getClientPrincipal());
-    }
-
-    protected class GremlinServerAuthKrb5Integrate extends AbstractGremlinServerIntegrationTest {
-
-        final String principal;
-        final File keytabFile;
-
-        GremlinServerAuthKrb5Integrate(String principal, File keytabFile) {
-            this.principal = principal;
-            this.keytabFile = keytabFile;
-        }
-
-        @Override
-        public Settings overrideSettings(final Settings settings) {
-            settings.host = getHostname();
-            logger.debug("Hostname: " + settings.host);
-            final Settings.AuthenticationSettings authSettings = new Settings.AuthenticationSettings();
-            authSettings.className = Krb5Authenticator.class.getName();
-            final Map authConfig = new HashMap<String,Object>();
-            authConfig.put("keytab", keytabFile.getAbsolutePath());
-            authConfig.put("principal", principal);
-            authSettings.config = authConfig;
-            settings.authentication = authSettings;
-            final Settings.SslSettings sslConfig = new Settings.SslSettings();
-            sslConfig.enabled = false;
-            settings.ssl = sslConfig;
-
-//            switch (nameOfTest) {
-//                case "shouldAuthenticateOverSslWithKerberosTicket":
-//                case "shouldFailIfSslEnabledOnServerButNotClient":
-//                    final Settings.SslSettings sslConfig = new Settings.SslSettings();
-//                    sslConfig.enabled = true;
-//                    settings.ssl = sslConfig;
-//                    break;
-//            }
-            return settings;
-        }
-    }
-
-    @Before
-    @Override
-    public void setUp() throws Exception {
-        logger.info("Starting " + name.getMethodName());
-        super.setUp();
-        loginServiceUsingKeytab();
-        loginClientUsingTicketCache();
-        final String buildDir = System.getProperty("build.dir");
-        System.setProperty("java.security.auth.login.config", buildDir +
-            "/test-classes/org/apache/tinkerpop/gremlin/server/gremlin-console-jaas.conf");
-    }
-}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
new file mode 100644
index 0000000..73aa0a7
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/KdcFixture.java
@@ -0,0 +1,152 @@
+/*
+ * 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.tinkerpop.gremlin.server;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbConfig;
+import org.apache.kerby.kerberos.kerb.client.KrbConfigKey;
+import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.util.NetworkUtil;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.net.Inet4Address;
+
+
+/**
+ * @author Marc de Lignie
+ *
+ * This class is derived from the following classes from https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2/:
+ *  - org.apache.kerby.kerberos.kerb.server.TestKdcServer
+ *  - org.apache.kerby.kerberos.kerb.server.KdcTestBase
+ *  - org.apache.kerby.kerberos.kerb.server.LoginTestBase.java
+ *
+ * See also: gremlin-server/src/main/static/NOTICE
+ */
+public class KdcFixture {
+
+    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KdcFixture.class);
+
+    final String clientPassword = "123456";
+    final String clientPrincipalName = "drankye";
+    final String serverPrincipalName = "test-service";
+    final String ticketCacheFileName = "test-tkt.cc";
+    final String serviceKeytabFileName = "test-service.keytab";
+
+    final String clientPrincipal;
+    final String serverPrincipal;
+    final File testDir;
+    final File ticketCacheFile;
+    final File serviceKeytabFile;
+
+    final String hostname;
+    private SimpleKdcServer kdcServer;
+
+
+    public KdcFixture(String authConfigName)  throws Exception {
+        System.setProperty("java.security.auth.login.config", authConfigName);
+        hostname = findHostname();
+        serverPrincipal = serverPrincipalName + "/" + hostname + "@" + KdcFixture.TestKdcServer.KDC_REALM;
+        clientPrincipal = clientPrincipalName + "@" + KdcFixture.TestKdcServer.KDC_REALM;
+        testDir = createTestDir();
+        ticketCacheFile = new File(testDir, ticketCacheFileName);
+        serviceKeytabFile = new File(testDir, serviceKeytabFileName);
+    }
+
+    private String findHostname() {
+        // Hostname setting must be consistent with the way gremlin-console sets gremlin-server's hostname
+        // and derives gremlin-server's principal name. Also, the hostname needs to be lowercase for use
+        // in principal names.
+        String hostname = "";
+        try {
+            hostname = Inet4Address.getLocalHost().getCanonicalHostName().toLowerCase();
+        } catch (Exception e) {
+            logger.error("Hostname not found");
+        }
+        return hostname;
+    }
+
+    private File createTestDir() {
+        String basedir = System.getProperty("basedir");
+        File targetdir = new File(basedir, "target");
+        File testDir = new File(targetdir, "tmp");
+        testDir.mkdirs();
+        return testDir;
+    }
+
+    private class TestKdcServer extends SimpleKdcServer {
+        public static final String KDC_REALM = "TEST.COM";
+        public static final String HOSTNAME = "localhost";
+
+        TestKdcServer() throws KrbException {
+            setKdcRealm(KDC_REALM);
+            setKdcHost(HOSTNAME);
+            setAllowTcp(true);
+            setAllowUdp(false);    // There are still udp issues in Apache Directory-Kerby 1.0.0-RC2
+            setKdcTcpPort(NetworkUtil.getServerPort());
+
+            KrbClient krbClnt = getKrbClient();
+            KrbConfig krbConfig = krbClnt.getKrbConfig();
+            krbConfig.setString(KrbConfigKey.PERMITTED_ENCTYPES,
+                    "aes128-cts-hmac-sha1-96 des-cbc-crc des-cbc-md5 des3-cbc-sha1");
+            krbClnt.setTimeout(10 * 1000);
+        }
+    }
+
+    public void setUp() throws Exception {
+        setUpKdcServer();
+        setUpPrincipals();
+    }
+
+    private void setUpKdcServer() throws Exception {
+        kdcServer = new TestKdcServer();
+        kdcServer.setWorkDir(testDir);
+        kdcServer.init();
+        kdcServer.start();
+    }
+
+    private void setUpPrincipals() throws KrbException {
+        kdcServer.createPrincipals(serverPrincipal);
+        kdcServer.exportPrincipal(serverPrincipal, serviceKeytabFile);
+
+        kdcServer.createPrincipal(clientPrincipal, clientPassword);
+        TgtTicket tgt = kdcServer.getKrbClient().requestTgt(clientPrincipal, clientPassword);
+        kdcServer.getKrbClient().storeTicket(tgt, ticketCacheFile);
+    }
+
+    public void close() throws Exception {
+        deletePrincipals();
+        kdcServer.stop();
+        ticketCacheFile.delete();
+        serviceKeytabFile.delete();
+        testDir.delete();
+    }
+
+    private void deletePrincipals() throws KrbException {
+        kdcServer.getKadmin().deleteBuiltinPrincipals();
+        kdcServer.deletePrincipals(serverPrincipal);
+        kdcServer.deletePrincipal(clientPrincipal);
+    }
+
+    public void createPrincipal(final String principal) throws KrbException {
+        kdcServer.createPrincipal(principal);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
index e44f72f..4a9ebd4 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/util/Log4jRecordingAppender.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.util;
 
 import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
 import org.apache.log4j.PatternLayout;
 import org.apache.log4j.spi.LoggingEvent;
 
@@ -32,6 +33,7 @@ import java.util.List;
  */
 public class Log4jRecordingAppender extends AppenderSkeleton {
     private final List<String> messages = new ArrayList<>();
+    private final List<LoggingEvent> events = new ArrayList<>();
 
     public Log4jRecordingAppender() {
         super();
@@ -41,6 +43,7 @@ public class Log4jRecordingAppender extends AppenderSkeleton {
     @Override
     protected void append(final LoggingEvent event) {
         messages.add(layout.format(event));
+        events.add(event);
     }
 
     @Override
@@ -52,9 +55,9 @@ public class Log4jRecordingAppender extends AppenderSkeleton {
         return true;
     }
 
-    public List<String> getMessages() {
-        return messages;
-    }
+    public List<String> getMessages() { return messages; }
+
+    public List<LoggingEvent> getEvents() { return events; }
 
     public void clear() {
         messages.clear();
@@ -63,4 +66,13 @@ public class Log4jRecordingAppender extends AppenderSkeleton {
     public boolean logContainsAny(final String fragment) {
         return messages.stream().anyMatch(m -> m.contains(fragment));
     }
-}
\ No newline at end of file
+
+    public boolean logContainsAny(final String loggerName, final Level level, final String fragment) {
+        return events.stream().anyMatch(m -> m.getLoggerName().equals(loggerName) &&
+                m.getLevel().equals(level) && m.getMessage().toString().contains(fragment));
+    }
+    public boolean logMatchesAny(final String loggerName, final Level level, final String regex) {
+        return events.stream().anyMatch(m -> m.getLoggerName().equals(loggerName) &&
+                m.getLevel().equals(level) && m.getMessage().toString().matches(regex));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/68eff1db/gremlin-server/src/test/resources/log4j-test.properties
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/resources/log4j-test.properties b/gremlin-server/src/test/resources/log4j-test.properties
index 5dec106..c806201 100644
--- a/gremlin-server/src/test/resources/log4j-test.properties
+++ b/gremlin-server/src/test/resources/log4j-test.properties
@@ -20,4 +20,4 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n
 
-log4j.logger.org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor=ERROR
\ No newline at end of file
+log4j.logger.org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor=ERROR