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/01/16 20:22:38 UTC

tinkerpop git commit: TINKERPOP-1600 Added base64 encoded string to sasl challenge

Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1600 [created] 0fcb306ef


TINKERPOP-1600 Added base64 encoded string to sasl challenge


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

Branch: refs/heads/TINKERPOP-1600
Commit: 0fcb306efa05c21b9c11f25f5dddb658159a4540
Parents: 9d1c3e5
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Mon Jan 16 15:22:07 2017 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Mon Jan 16 15:22:07 2017 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                  |  1 +
 docs/src/dev/io/graphson.asciidoc                   |  5 ++---
 docs/src/upgrade/release-3.2.x-incubating.asciidoc  | 16 ++++++++++++++++
 .../apache/tinkerpop/gremlin/driver/Handler.java    | 15 +++++++++++++--
 .../server/handler/SaslAuthenticationHandler.java   | 14 ++++++++++++--
 5 files changed, 44 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0fcb306e/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 0a2affe..5e10e21 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* SASL negotiation supports both a byte array and Base64 encoded bytes as a string for authentication to Gremlin Server.
 * Made error messaging more consistent during result iteration timeouts in Gremlin Server.
 * `PathRetractionStrategy` does not add a `NoOpBarrierStep` to the end of local children as its wasted computation in 99% of traversals.
 * Fixed a bug in `AddVertexStartStep` where if a side-effect was being used in the parametrization, an NPE occurred.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0fcb306e/docs/src/dev/io/graphson.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/io/graphson.asciidoc b/docs/src/dev/io/graphson.asciidoc
index cdc9880..fe56c27 100644
--- a/docs/src/dev/io/graphson.asciidoc
+++ b/docs/src/dev/io/graphson.asciidoc
@@ -1299,7 +1299,7 @@ ResponseMessage
 Authentication Challenge
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
-When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).
+When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but not in the default provided by Gremlin Server).
 
 [source,json]
 ----
@@ -4262,14 +4262,13 @@ The following `RequestMessage` is an example of a sessionless request for a scri
 }
 ----
 
-
 ResponseMessage
 ~~~~~~~~~~~~~~~
 
 Authentication Challenge
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
-When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but no in the default provided by Gremlin Server).
+When authentication is enabled, an initial request to the server will result in an authentication challenge. The typical response message will appear as follows, but handling it could be different dependending on the SASL implementation (e.g. multiple challenges maybe requested in some cases, but not in the default provided by Gremlin Server).
 
 [source,json]
 ----

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0fcb306e/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
index 8d73baed..b478b96 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -240,6 +240,22 @@ and defaults to `false`.
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-932[TINKERPOP-932],
 link:http://tinkerpop.apache.org/docs/current/dev/provider/#_session_opprocessor[Provider Documentation - Session OpProcessor]
 
+SASL Authentication
++++++++++++++++++++
+
+Gremlin Supports SASL based authentication. The server accepts either a byte array or Base64 encoded String as the in
+the `sasl` argument on the `RequestMessage`, however it sends back a byte array only. Some serializers or serializer
+configurations don't work well with that approach (specifically the "toString" configuration on the Gryo serializer) as
+the byte array is returned in the `ResponseMessage` result. In the case of the "toString" serializer the byte array
+gets "toString'd" and the can't be read by the client.
+
+In 3.2.4, the byte array is still returned in the `ResponseMessage` result, but is also returned in the status
+attributes under a `sasl` key as a Base64 encoded string. In this way, the client has options on how it chooses to
+process the authentication response and the change remains backward compatible. Drivers should upgrade to using the
+Base64 encoded string however as the old approach will likely be removed in the future.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1600[TINKERPOP-1600]
+
 TinkerPop 3.2.3
 ---------------
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0fcb306e/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
index 681354c..650bc2f 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
@@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory;
 import java.net.InetSocketAddress;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -70,6 +71,9 @@ final class Handler {
         private static final Map<String, String> SASL_PROPERTIES = new HashMap<String, String>() {{ put(Sasl.SERVER_AUTH, "true"); }};
         private static final byte[] NULL_CHALLENGE = new byte[0];
 
+        private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
+        private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
+
         private final AuthProperties authProps;
 
         public GremlinSaslAuthenticationHandler(final AuthProperties authProps) {
@@ -103,9 +107,16 @@ final class Handler {
 
                     messageBuilder.addArg(Tokens.ARGS_SASL_MECHANISM, getMechanism());
                     messageBuilder.addArg(Tokens.ARGS_SASL, saslClient.get().hasInitialResponse() ?
-                                                                evaluateChallenge(subject, saslClient, NULL_CHALLENGE) : null);
+                            BASE64_ENCODER.encodeToString(evaluateChallenge(subject, saslClient, NULL_CHALLENGE)) : null);
                 } else {
-                    messageBuilder.addArg(Tokens.ARGS_SASL, evaluateChallenge(subject, saslClient, (byte[])response.getResult().getData()));
+                    // the server sends base64 encoded sasl as well as the byte array. the byte array will eventually be
+                    // phased out, but is present now for backward compatibility in 3.2.x
+                    final String base64sasl = response.getStatus().getAttributes().containsKey(Tokens.ARGS_SASL) ?
+                        response.getStatus().getAttributes().get(Tokens.ARGS_SASL).toString() :
+                        BASE64_ENCODER.encodeToString((byte[]) response.getResult().getData());
+
+                    messageBuilder.addArg(Tokens.ARGS_SASL, BASE64_ENCODER.encodeToString(
+                        evaluateChallenge(subject, saslClient, BASE64_DECODER.decode(base64sasl))));
                 }
                 channelHandlerContext.writeAndFlush(messageBuilder.create());
             } else {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/0fcb306e/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
index 4bb7879..2d7edf0 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/handler/SaslAuthenticationHandler.java
@@ -28,6 +28,9 @@ import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
@@ -50,6 +53,8 @@ import org.slf4j.LoggerFactory;
 @ChannelHandler.Sharable
 public class SaslAuthenticationHandler extends ChannelInboundHandlerAdapter {
     private static final Logger logger = LoggerFactory.getLogger(SaslAuthenticationHandler.class);
+    private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
+    private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
 
     private final Authenticator authenticator;
 
@@ -80,7 +85,7 @@ public class SaslAuthenticationHandler extends ChannelInboundHandlerAdapter {
                     if (saslObject instanceof byte[]) {
                         saslResponse = (byte[]) saslObject;
                     } else if(saslObject instanceof String) {
-                        saslResponse = Base64.getDecoder().decode((String) saslObject);
+                        saslResponse = BASE64_DECODER.decode((String) saslObject);
                     } else {
                         final ResponseMessage error = ResponseMessage.build(request.get())
                                 .statusMessage("Incorrect type for : " + Tokens.ARGS_SASL + " - byte[] or base64 encoded String is expected")
@@ -101,8 +106,13 @@ public class SaslAuthenticationHandler extends ChannelInboundHandlerAdapter {
                             final RequestMessage original = request.get();
                             ctx.fireChannelRead(original);
                         } else {
-                            // not done here - send back the sasl message for next challenge
+                            // not done here - send back the sasl message for next challenge. note that we send back
+                            // the base64 encoded sasl as well as the byte array. the byte array will eventually be
+                            // phased out, but is present now for backward compatibility in 3.2.x
+                            final Map<String,Object> metadata = new HashMap<>();
+                            metadata.put(Tokens.ARGS_SASL, BASE64_ENCODER.encode(saslMessage));
                             final ResponseMessage authenticate = ResponseMessage.build(requestMessage)
+                                    .statusAttributes(metadata)
                                     .code(ResponseStatusCode.AUTHENTICATE).result(saslMessage).create();
                             ctx.writeAndFlush(authenticate);
                         }