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:02:21 UTC
[13/27] tinkerpop git commit: Some cleanup
Some cleanup
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/6a9c6674
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/6a9c6674
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/6a9c6674
Branch: refs/heads/master
Commit: 6a9c6674ca80fac28a4c74e00e00d91aefc829dd
Parents: c849295
Author: HadoopMarc <vt...@xs4all.nl>
Authored: Fri Jan 13 20:42:51 2017 +0100
Committer: HadoopMarc <vt...@xs4all.nl>
Committed: Wed Jan 18 20:08:00 2017 +0100
----------------------------------------------------------------------
.../gremlin/server/auth/JaasKrbUtil.java | 9 +-
.../gremlin/server/auth/Krb5Authenticator.java | 22 +-
.../tinkerpop/gremlin/server/AuditLogTest.java | 322 -------------------
.../tinkerpop/gremlin/server/AuthKrb5Test.java | 263 ---------------
.../GremlinServerAuditLogIntegrateTest.java | 322 +++++++++++++++++++
.../GremlinServerAuthKrb5IntegrateTest.java | 235 ++++++++++++++
.../tinkerpop/gremlin/server/KdcFixture.java | 2 +-
7 files changed, 569 insertions(+), 606 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6a9c6674/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/JaasKrbUtil.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/JaasKrbUtil.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/JaasKrbUtil.java
index ad87d58..6a2e8d3 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/JaasKrbUtil.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/JaasKrbUtil.java
@@ -53,8 +53,7 @@ public final class JaasKrbUtil {
private JaasKrbUtil() { }
- public static Subject loginUsingPassword(
- String principal, String password) throws LoginException {
+ public static Subject loginUsingPassword(String principal, String password) throws LoginException {
Set<Principal> principals = new HashSet<Principal>();
principals.add(new KerberosPrincipal(principal));
@@ -69,8 +68,7 @@ public final class JaasKrbUtil {
return loginContext.getSubject();
}
- public static Subject loginUsingTicketCache(
- String principal, File cacheFile) throws LoginException {
+ public static Subject loginUsingTicketCache(String principal, File cacheFile) throws LoginException {
Set<Principal> principals = new HashSet<Principal>();
principals.add(new KerberosPrincipal(principal));
@@ -84,8 +82,7 @@ public final class JaasKrbUtil {
return loginContext.getSubject();
}
- public static Subject loginUsingKeytab(
- String principal, File keytabFile) throws LoginException {
+ public static Subject loginUsingKeytab(String principal, File keytabFile) throws LoginException {
Set<Principal> principals = new HashSet<Principal>();
principals.add(new KerberosPrincipal(principal));
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6a9c6674/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
index 57a4259..275dba6 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/Krb5Authenticator.java
@@ -36,7 +36,7 @@ import java.util.Map;
/**
- * A Kerberos implementation of an {@link Authenticator}
+ * A Kerberos (GSSAPI) implementation of an {@link Authenticator}
*
* @author Marc de Lignie
*/
@@ -102,10 +102,10 @@ public class Krb5Authenticator implements Authenticator {
}
/*
- * Invoked by:
- * https://github.com/apache/tinkerpop/blob/3.1.1-incubating/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
+ * Krb5SaslAuthenticator is invoked by:
+ * org.apache.tinkerpop.gremlin.server.handler.SaslAuthenticationHandler
* Negotiates with evaluateChallenge() of the generic sasl handler in gremlin console:
- * https://github.com/apache/tinkerpop/blob/3.1.1-incubating/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
+ * org.apache.tinkerpop.gremlin.driver.Handler.java
* See also:
* https://docs.oracle.com/javase/8/docs/technotes/guides/security/sasl/sasl-refguide.html
* https://docs.oracle.com/javase/8/docs/api/org/ietf/jgss/GSSContext.html
@@ -120,13 +120,11 @@ public class Krb5Authenticator implements Authenticator {
try {
// For sasl properties regarding GSSAPI, see:
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/sasl/sasl-refguide.html#SERVER
- // Rely on GSSAPI defaults for Sasl.MAX_BUFFER and "javax.security.sasl.sendmaxbuffer"
- // Sasl policy properties are not relevant here, because the sasl mechanisme is not negotiated
- // Kerberos implementations do not handle Sasl.QOP values reliably; rather use SSL for enhanced privacy,
- // see https://issues.apache.org/jira/browse/HIVE-8377
+ // Rely on GSSAPI defaults for Sasl.MAX_BUFFER and Sasl.QOP. Note, however, that gremlin-driver has
+ // Sasl.SERVER_AUTH fixed to true (mutual authentication) and one can configure SSL for enhanced confidentiality,
+ // Sasl policy properties for negotiating the authenticatin mechanism are not relevant here, because
+ // GSSAPI is the only available mechanism for this authenticator
final Map props = new HashMap<String, Object>();
- if (!System.getProperty(Sasl.QOP, "").equals(""))
- logger.warn("Gremlin server uses default Sasl.QOP values, use SSL for enhanced privacy");
final String[] principalParts = principalName.split("/|@");
if (principalParts.length < 3) throw new IllegalArgumentException("Use principal name of format 'service/fqdn@kdcrealm'");
saslServer = Sasl.createSaslServer(mechanism, principalParts[0], principalParts[1], props, Krb5SaslAuthenticator.this);
@@ -139,9 +137,6 @@ public class Krb5Authenticator implements Authenticator {
/*
* This method is based on the handle() method from:
* https://github.com/apache/directory-kerby/blob/kerby-all-1.0.0-RC2/kerby-kerb/integration-test/src/main/java/org/apache/kerby/kerberos/kerb/integration/test/sasl/SaslAppServer.java
- * Other example sources:
- * https://gist.github.com/honza889/1347ddee89311dd636d5 (APL)
- * https://github.com/wildfly-security/jboss-sasl/blob/master/src/test/java/org/jboss/sasl/test/ServerCallbackHandler.java (GPL)
*/
@Override
public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
@@ -188,7 +183,6 @@ public class Krb5Authenticator implements Authenticator {
}
@Override
- // todo: apply for audit logging, see related todo in gremlin-server/.../SaslAuthenticationHandler.java
public AuthenticatedUser getAuthenticatedUser() throws AuthenticationException {
logger.debug("getAuthenticatedUser called: " + saslServer.getAuthorizationID());
return new AuthenticatedUser(saslServer.getAuthorizationID());
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6a9c6674/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
deleted file mode 100644
index b2f0fe8..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuditLogTest.java
+++ /dev/null
@@ -1,322 +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.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() throws Exception {
- final Logger rootLogger = Logger.getRootLogger();
- rootLogger.removeAppender(recordingAppender);
- kdcServer.close();
- }
-
- /**
- * 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().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/6a9c6674/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
deleted file mode 100644
index 11b873c..0000000
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AuthKrb5Test.java
+++ /dev/null
@@ -1,263 +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.commons.lang.exception.ExceptionUtils;
-import org.apache.log4j.Logger;
-import org.apache.tinkerpop.gremlin.driver.Client;
-import org.apache.tinkerpop.gremlin.driver.Cluster;
-import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0;
-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.Test;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-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;
-
-
-
-/**
- * @author Marc de Lignie
- *
- * Todo: change back to integrate test later on
- */
-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);
- }
-
- @After
- public void teardownForEachTest() throws Exception {
- final Logger rootLogger = Logger.getRootLogger();
- rootLogger.removeAppender(recordingAppender);
- kdcServer.close();
- }
-
- /**
- * 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:
- * private int port = 45940;
- * private MessageSerializer serializer = Serializers.GRYO_V1D0.simpleInstance();
- * private int nioPoolSize = Runtime.getRuntime().availableProcessors();
- * private int workerPoolSize = Runtime.getRuntime().availableProcessors() * 2;
- * private int minConnectionPoolSize = ConnectionPool.MIN_POOL_SIZE;
- * private int maxConnectionPoolSize = ConnectionPool.MAX_POOL_SIZE;
- * private int minSimultaneousUsagePerConnection = ConnectionPool.MIN_SIMULTANEOUS_USAGE_PER_CONNECTION;
- * private int maxSimultaneousUsagePerConnection = ConnectionPool.MAX_SIMULTANEOUS_USAGE_PER_CONNECTION;
- * private int maxInProcessPerConnection = Connection.MAX_IN_PROCESS;
- * private int minInProcessPerConnection = Connection.MIN_IN_PROCESS;
- * private int maxWaitForConnection = Connection.MAX_WAIT_FOR_CONNECTION;
- * private int maxWaitForSessionClose = Connection.MAX_WAIT_FOR_SESSION_CLOSE;
- * private int maxContentLength = Connection.MAX_CONTENT_LENGTH;
- * private int reconnectInitialDelay = Connection.RECONNECT_INITIAL_DELAY;
- * private int reconnectInterval = Connection.RECONNECT_INTERVAL;
- * private int resultIterationBatchSize = Connection.RESULT_ITERATION_BATCH_SIZE;
- * private long keepAliveInterval = Connection.KEEP_ALIVE_INTERVAL;
- * private String channelizer = Channelizer.WebSocketChannelizer.class.getName();
- * private boolean enableSsl = false;
- * private String trustCertChainFile = null;
- * private String keyCertChainFile = null;
- * private String keyFile = null;
- * private String keyPassword = null;
- * private SslContext sslContext = null;
- * private LoadBalancingStrategy loadBalancingStrategy = new LoadBalancingStrategy.RoundRobin();
- * private AuthProperties authProps = new AuthProperties();
- */
- @Test
- public void shouldAuthenticateWithDefaults() 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();
- }
- }
-
- @Test
- public void shouldFailWithoutClientJaasEntry() throws Exception {
- final Cluster cluster = TestClientFactory.build().protocol(kdcServer.serverPrincipalName)
- .addContactPoint(kdcServer.hostname).create();
- final Client client = cluster.connect();
- try {
- client.submit("1+1").all().get();
- fail("This should not succeed as the client config does not contain a JaasEntry");
- } catch(Exception ex) {
- final Throwable root = ExceptionUtils.getRootCause(ex);
- assertEquals(GSSException.class, root.getClass());
- } finally {
- cluster.close();
- }
- }
-
- @Test
- public void shouldFailWithoutClientTicketCache() throws Exception {
- final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE_NOT_LOGGED_IN)
- .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
- final Client client = cluster.connect();
- try {
- client.submit("1+1").all().get();
- fail("This should not succeed as the client config does not contain a valid ticket cache");
- } catch(Exception ex) {
- final Throwable root = ExceptionUtils.getRootCause(ex);
- assertEquals(LoginException.class, root.getClass());
- } finally {
- cluster.close();
- }
- }
-
- @Test
- public void shouldFailWithNonexistentServerPrincipal() throws Exception {
- assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
- }
-
- @Test
- public void shouldFailWithEmptyServerKeytab() throws Exception {
- assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
- }
-
- @Test
- public void shouldFailWithWrongServerKeytab() throws Exception {
- assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
- }
-
- @Test
- public void shouldAuthenticateWithQop() throws Exception {
- 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(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();
- System.setProperty("javax.security.sasl.qop", oldQop);
- }
- }
-
-// ToDo: Unclear how to test this
-// @Test
-// public void shouldFailWithAuthIdUnequalAuthzId() throws Exception {
-// server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), serviceKeytabFile);
-// server.setUp();
-// }
-
-
- @Test
- public void shouldAuthenticateWithSerializeResultToString() throws Exception {
- MessageSerializer serializer = new GryoMessageSerializerV1d0();
- Map config = new HashMap<String, Object>();
- config.put("serializeResultToString", true);
- serializer.configure(config, null);
- final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE)
- .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).serializer(serializer).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();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6a9c6674/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.java
new file mode 100644
index 0000000..32c8451
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuditLogIntegrateTest.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.GremlinServerAuthKrb5IntegrateTest.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 test suite assumes that tests are
+ * run sequentially and thus the server and kdcServer variables can be reused.
+ */
+public class GremlinServerAuditLogIntegrateTest extends AbstractGremlinServerIntegrationTest {
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerAuditLogIntegrateTest.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() throws Exception {
+ final Logger rootLogger = Logger.getRootLogger();
+ rootLogger.removeAppender(recordingAppender);
+ kdcServer.close();
+ }
+
+ /**
+ * 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().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 for AllowAllAuthenticator,
+ // 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 {
+ 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/6a9c6674/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
new file mode 100644
index 0000000..9573208
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthKrb5IntegrateTest.java
@@ -0,0 +1,235 @@
+/*
+ * 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.commons.lang.exception.ExceptionUtils;
+import org.apache.log4j.Logger;
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
+import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0;
+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.Test;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+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;
+
+
+
+/**
+ * @author Marc de Lignie
+ *
+ */
+public class GremlinServerAuthKrb5IntegrateTest extends AbstractGremlinServerIntegrationTest {
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GremlinServerAuthKrb5IntegrateTest.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);
+ }
+
+ @After
+ public void teardownForEachTest() throws Exception {
+ final Logger rootLogger = Logger.getRootLogger();
+ rootLogger.removeAppender(recordingAppender);
+ kdcServer.close();
+ }
+
+ /**
+ * 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;
+ }
+
+ @Test
+ public void shouldAuthenticateWithDefaults() 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();
+ }
+ }
+
+ @Test
+ public void shouldFailWithoutClientJaasEntry() throws Exception {
+ final Cluster cluster = TestClientFactory.build().protocol(kdcServer.serverPrincipalName)
+ .addContactPoint(kdcServer.hostname).create();
+ final Client client = cluster.connect();
+ try {
+ client.submit("1+1").all().get();
+ fail("This should not succeed as the client config does not contain a JaasEntry");
+ } catch(Exception ex) {
+ final Throwable root = ExceptionUtils.getRootCause(ex);
+ assertEquals(GSSException.class, root.getClass());
+ } finally {
+ cluster.close();
+ }
+ }
+
+ @Test
+ public void shouldFailWithoutClientTicketCache() throws Exception {
+ final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE_NOT_LOGGED_IN)
+ .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).create();
+ final Client client = cluster.connect();
+ try {
+ client.submit("1+1").all().get();
+ fail("This should not succeed as the client config does not contain a valid ticket cache");
+ } catch(Exception ex) {
+ final Throwable root = ExceptionUtils.getRootCause(ex);
+ assertEquals(LoginException.class, root.getClass());
+ } finally {
+ cluster.close();
+ }
+ }
+
+ @Test
+ public void shouldFailWithNonexistentServerPrincipal() throws Exception {
+ assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
+ }
+
+ @Test
+ public void shouldFailWithEmptyServerKeytab() throws Exception {
+ assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
+ }
+
+ @Test
+ public void shouldFailWithWrongServerKeytab() throws Exception {
+ assertTrue(recordingAppender.logContainsAny("WARN - Failed to login to kdc"));
+ }
+
+ @Test
+ public void shouldAuthenticateWithQop() throws Exception {
+ 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(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();
+ System.setProperty("javax.security.sasl.qop", oldQop);
+ }
+ }
+
+// ToDo: Unclear how to test this
+// @Test
+// public void shouldFailWithAuthIdUnequalAuthzId() throws Exception {
+// server = new GremlinServerAuthKrb5Integrate(getServerPrincipal(), serviceKeytabFile);
+// server.setUp();
+// }
+
+
+ // This test backs a fix in gremlin-driver (cd628b251f6956c826df20c89177680fe120ff99)
+ // Maybe gremlin-driver needs its own test with client.submit("[1,2,3] as byte[]")
+ @Test
+ public void shouldAuthenticateWithSerializeResultToString() throws Exception {
+ MessageSerializer serializer = new GryoMessageSerializerV1d0();
+ Map config = new HashMap<String, Object>();
+ config.put("serializeResultToString", true);
+ serializer.configure(config, null);
+ final Cluster cluster = TestClientFactory.build().jaasEntry(TESTCONSOLE)
+ .protocol(kdcServer.serverPrincipalName).addContactPoint(kdcServer.hostname).serializer(serializer).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();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6a9c6674/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
index 7ff2f06..db19c96 100644
--- 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
@@ -79,7 +79,7 @@ public class KdcFixture {
try {
hostname = Inet4Address.getLocalHost().getCanonicalHostName().toLowerCase();
} catch (Exception e) {
- logger.error("Hostname not found");
+ logger.error("Hostname not found: " + e.getMessage());
}
return hostname;
}