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 2015/07/16 22:35:31 UTC
[1/2] incubator-tinkerpop git commit: More tests and javadoc around
gremlin server/driver authentication.
Repository: incubator-tinkerpop
Updated Branches:
refs/heads/auth b0136f332 -> e4c44af3e
More tests and javadoc around gremlin server/driver authentication.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/df72b67c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/df72b67c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/df72b67c
Branch: refs/heads/auth
Commit: df72b67c031690ad9504bd1b10458a2a3043aa9a
Parents: b0136f3
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Jul 16 16:31:22 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Jul 16 16:31:22 2015 -0400
----------------------------------------------------------------------
.../server/auth/AllowAllAuthenticator.java | 4 +-
.../server/auth/SimpleAuthenticator.java | 21 ++--
.../auth/groovy/plugin/CredentialGraph.java | 24 ++++-
.../server/GremlinServerAuthIntegrateTest.java | 2 +-
.../server/auth/SimpleAuthenticatorTest.java | 102 ++++++++++++++++++
.../auth/groovy/plugin/CredentialGraphTest.java | 106 +++++++++++++++++++
6 files changed, 247 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/df72b67c/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/AllowAllAuthenticator.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/AllowAllAuthenticator.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/AllowAllAuthenticator.java
index 1efcf98..0a7c427 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/AllowAllAuthenticator.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/AllowAllAuthenticator.java
@@ -23,7 +23,7 @@ import java.util.Map;
/**
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
-public class AllowAllAuthenticator implements Authenticator {
+public final class AllowAllAuthenticator implements Authenticator {
private static final SaslNegotiator AUTHENTICATOR_INSTANCE = new Negotiator();
public boolean requireAuthentication(){
@@ -40,7 +40,7 @@ public class AllowAllAuthenticator implements Authenticator {
private static class Negotiator implements SaslNegotiator {
- public byte[] evaluateResponse(byte[] clientResponse) throws AuthenticationException {
+ public byte[] evaluateResponse(final byte[] clientResponse) throws AuthenticationException {
return null;
}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/df72b67c/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticator.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticator.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticator.java
index 5a7eb94..772823c 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticator.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticator.java
@@ -46,6 +46,8 @@ public class SimpleAuthenticator implements Authenticator {
private static final byte NUL = 0;
private CredentialGraph credentialStore;
+ public static final String CONFIG_CREDENTIALS_LOCATION = "gremlin.server.credentials";
+
@Override
public boolean requireAuthentication() {
return true;
@@ -54,25 +56,28 @@ public class SimpleAuthenticator implements Authenticator {
@Override
public void setup(final Map<String,Object> config) {
if (null == config) {
- throw new IllegalStateException(String.format(
+ throw new IllegalArgumentException(String.format(
"Could not configure a %s - provide a 'config' in the 'authentication' settings",
SimpleAuthenticator.class.getName()));
}
final Configuration conf = new MapConfiguration(config);
+ if (!config.containsKey(CONFIG_CREDENTIALS_LOCATION)) {
+ throw new IllegalStateException(String.format(
+ "Credentials configuration for TinkerGraph should include %s key that points to a gryo file containing credentials data", CONFIG_CREDENTIALS_LOCATION));
+ }
+
final Graph graph = GraphFactory.open(conf);
if (graph instanceof TinkerGraph) {
final TinkerGraph tinkerGraph = (TinkerGraph) graph;
tinkerGraph.createIndex(PROPERTY_USERNAME, Vertex.class);
- if (config.containsKey("gremlin.server.credentials")) {
- final String location = (String) config.get("gremlin.server.credentials");
- try {
- tinkerGraph.io(IoCore.gryo()).readGraph(location);
- } catch (IOException e) {
- logger.warn("Could not read credentials graph from {} - authentication is enabled, but with an empty user database", location);
- }
+ final String location = (String) config.get(CONFIG_CREDENTIALS_LOCATION);
+ try {
+ tinkerGraph.io(IoCore.gryo()).readGraph(location);
+ } catch (IOException e) {
+ logger.warn("Could not read credentials graph from {} - authentication is enabled, but with an empty user database", location);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/df72b67c/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraph.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraph.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraph.java
index 9678279..de7f209 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraph.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraph.java
@@ -25,11 +25,15 @@ import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.mindrot.jbcrypt.BCrypt;
+import java.util.concurrent.atomic.AtomicInteger;
+
import static org.apache.tinkerpop.gremlin.server.auth.groovy.plugin.CredentialGraphTokens.PROPERTY_PASSWORD;
import static org.apache.tinkerpop.gremlin.server.auth.groovy.plugin.CredentialGraphTokens.PROPERTY_USERNAME;
import static org.apache.tinkerpop.gremlin.server.auth.groovy.plugin.CredentialGraphTokens.VERTEX_LABEL_USER;
/**
+ * A DSL for managing a "credentials graph" used by Gremlin Server for simple authentication functions.
+ *
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
public class CredentialGraph {
@@ -42,6 +46,11 @@ public class CredentialGraph {
g = graph.traversal();
}
+ /**
+ * Finds a user by username and return {@code null} if one could not be found.
+ *
+ * @throws IllegalStateException if there is more than one user with a particular username.
+ */
public Vertex findUser(final String username) {
final GraphTraversal<Vertex,Vertex> t = g.V().has(PROPERTY_USERNAME, username);
final Vertex v = t.hasNext() ? t.next() : null;
@@ -49,14 +58,27 @@ public class CredentialGraph {
return v;
}
+ /**
+ * Creates a new user.
+ *
+ * @return the newly created user vertex
+ */
public Vertex createUser(final String username, final String password) {
+ if (findUser(username) != null) throw new IllegalStateException("User with this name already exists");
return graph.addVertex(T.label, VERTEX_LABEL_USER,
PROPERTY_USERNAME, username,
PROPERTY_PASSWORD, BCrypt.hashpw(password, BCrypt.gensalt()));
}
+ /**
+ * Removes a user by name.
+ *
+ * @return the number of users removed (which should be one or zero)
+ */
public long removeUser(final String username) {
- return g.V().has(PROPERTY_USERNAME, username).drop().count().next();
+ final AtomicInteger counter = new AtomicInteger(0);
+ g.V().has(PROPERTY_USERNAME, username).sideEffect(v -> counter.incrementAndGet()).drop().iterate();
+ return counter.get();
}
public static CredentialGraph credentials(final Graph graph) {
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/df72b67c/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
index ae1e775..b817d3c 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
@@ -47,7 +47,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
// use a credentials graph with one user in it: stephen/password
final Map<String,Object> authConfig = new HashMap<>();
authConfig.put("gremlin.graph", TinkerGraph.class.getName());
- authConfig.put("gremlin.server.credentials", "data/credentials.kryo");
+ authConfig.put(SimpleAuthenticator.CONFIG_CREDENTIALS_LOCATION, "data/credentials.kryo");
authSettings.config = authConfig;
settings.authentication = authSettings;
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/df72b67c/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticatorTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticatorTest.java
new file mode 100644
index 0000000..7ce69d1
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/SimpleAuthenticatorTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.auth;
+
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class SimpleAuthenticatorTest {
+ private Authenticator authenticator;
+
+ @Before
+ public void setup() {
+ authenticator = new SimpleAuthenticator();
+ }
+
+ @Test
+ public void shouldAlwaysRequireAuthentication() {
+ assertTrue(authenticator.requireAuthentication());
+ }
+
+ @Test
+ public void shouldCreateNewPlainTextSaslNegotiator() {
+ final Authenticator.SaslNegotiator negotiator1 = authenticator.newSaslNegotiator();
+ final Authenticator.SaslNegotiator negotiator2 = authenticator.newSaslNegotiator();
+
+ assertNotEquals(negotiator1, negotiator2);
+ assertNotEquals(negotiator2, negotiator1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldNotAllowNullConfigInSetup() {
+ authenticator.setup(null);
+ }
+
+ @Test
+ public void shouldUseTinkerGraphForCredentialsStoreAndSucceed() throws Exception {
+ final Map<String,Object> config = new HashMap<>();
+ config.put("gremlin.graph", TinkerGraph.class.getName());
+ config.put(SimpleAuthenticator.CONFIG_CREDENTIALS_LOCATION, "data/credentials.kryo");
+ authenticator.setup(config);
+
+ final Authenticator.SaslNegotiator negotiator = authenticator.newSaslNegotiator();
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ final byte[] nul = new byte[] {0};
+ stream.write(nul);
+ stream.write("stephen".getBytes());
+ stream.write(nul);
+ stream.write("password".getBytes());
+
+ negotiator.evaluateResponse(stream.toByteArray());
+ assertTrue(negotiator.isComplete());
+ assertEquals("stephen", negotiator.getAuthenticatedUser().getName());
+ }
+
+ @Test(expected = AuthenticationException.class)
+ public void shouldUseTinkerGraphForCredentialsStoreAndFail() throws Exception {
+ final Map<String,Object> config = new HashMap<>();
+ config.put("gremlin.graph", TinkerGraph.class.getName());
+ config.put(SimpleAuthenticator.CONFIG_CREDENTIALS_LOCATION, "data/credentials.kryo");
+ authenticator.setup(config);
+
+ final Authenticator.SaslNegotiator negotiator = authenticator.newSaslNegotiator();
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ final byte[] nul = new byte[] {0};
+ stream.write(nul);
+ stream.write("stephen".getBytes());
+ stream.write(nul);
+ stream.write("bad-password".getBytes());
+
+ negotiator.evaluateResponse(stream.toByteArray());
+ assertTrue(negotiator.isComplete());
+ negotiator.getAuthenticatedUser();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/df72b67c/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraphTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraphTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraphTest.java
new file mode 100644
index 0000000..2ef270e
--- /dev/null
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/auth/groovy/plugin/CredentialGraphTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.auth.groovy.plugin;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.tinkerpop.gremlin.server.auth.groovy.plugin.CredentialGraph.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class CredentialGraphTest {
+ private TinkerGraph graph;
+
+ @Before
+ public void setup() {
+ graph = TinkerGraph.open();
+ graph.createIndex("username", Vertex.class);
+ }
+
+ @Test
+ public void shouldCreateUser() {
+ final Vertex v = credentials(graph).createUser("stephen", "secret");
+ assertEquals("stephen", v.value("username"));
+ assertEquals("user", v.label());
+ assertNotEquals("secret", v.value("password")); // hashed to something
+ assertThat(v.value("password").toString().length(), greaterThan(0));
+ }
+
+ @Test
+ public void shouldRemoveUser() {
+ assertThat(graph.vertices().hasNext(), is(false));
+ credentials(graph).createUser("stephen", "secret");
+ assertThat(graph.vertices().hasNext(), is(true));
+
+ assertEquals(1, credentials(graph).removeUser("stephen"));
+ assertThat(graph.vertices().hasNext(), is(false));
+ }
+
+ @Test
+ public void shouldNotRemoveUser() {
+ assertThat(graph.vertices().hasNext(), is(false));
+ credentials(graph).createUser("stephen", "secret");
+ assertThat(graph.vertices().hasNext(), is(true));
+
+ assertEquals(0, credentials(graph).removeUser("stephanie"));
+ assertThat(graph.vertices().hasNext(), is(true));
+ }
+
+ @Test
+ public void shouldFindUser() {
+ assertThat(graph.vertices().hasNext(), is(false));
+ credentials(graph).createUser("marko", "secret");
+ final Vertex stephen = credentials(graph).createUser("stephen", "secret");
+ credentials(graph).createUser("daniel", "secret");
+ assertThat(graph.vertices().hasNext(), is(true));
+
+ assertEquals(stephen, credentials(graph).findUser("stephen"));
+ }
+
+ @Test
+ public void shouldNotFindUser() {
+ assertThat(graph.vertices().hasNext(), is(false));
+ credentials(graph).createUser("marko", "secret");
+ credentials(graph).createUser("stephen", "secret");
+ credentials(graph).createUser("daniel", "secret");
+ assertThat(graph.vertices().hasNext(), is(true));
+
+ assertNull(credentials(graph).findUser("stephanie"));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void shouldThrowIfFindingMultipleUsers() {
+ assertThat(graph.vertices().hasNext(), is(false));
+ credentials(graph).createUser("stephen", "secret");
+ credentials(graph).createUser("stephen", "secret");
+ assertThat(graph.vertices().hasNext(), is(true));
+
+ assertNull(credentials(graph).findUser("stephen"));
+ }
+}
[2/2] incubator-tinkerpop git commit: Update changelog.
Posted by sp...@apache.org.
Update changelog.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/e4c44af3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/e4c44af3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/e4c44af3
Branch: refs/heads/auth
Commit: e4c44af3e0feb42baacae6c50eb5564bbe6b1353
Parents: df72b67
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Jul 16 16:35:16 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Jul 16 16:35:16 2015 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 2 ++
1 file changed, 2 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/e4c44af3/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 25d518a..dd05291 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,8 @@ image::http://www.tinkerpop.com/docs/current/images/gremlin-hindu.png[width=225]
TinkerPop 3.0.1 (NOT OFFICIALLY RELEASED YET)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Gremlin Server/Driver authentication support via SASL.
+* Gremlin Server plugin to help with "credential graph" management (used in conjunction with authentication features of Gremlin Server).
* Adjusted configuration for javadoc generation to eliminate error messages.
* Removed "reserved" graph concept names from tests (e.g. "label", "edge", "value") to support the convention of avoiding these strings for property names.
* Introduced `GraphProvider.Descriptor` which annotates a `GraphProvider` implementation to describe what `GraphComputer` implementation will be used.