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.