You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by fl...@apache.org on 2018/08/30 14:31:06 UTC

[22/50] tinkerpop git commit: Implementation of Sasl authentication.

Implementation of Sasl authentication.


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

Branch: refs/heads/TINKERPOP-1774
Commit: 2a8b4b4ff5cf55b82fe2af8f8390724c6688467f
Parents: 675c077
Author: Matthew Allen <ma...@runbox.com>
Authored: Fri Jul 6 20:49:54 2018 +0100
Committer: Matthew Allen <ma...@runbox.com>
Committed: Thu Aug 23 06:33:51 2018 +0100

----------------------------------------------------------------------
 .../lib/driver/authenticator.js                 | 14 ++++++
 .../lib/driver/driver-remote-connection.js      | 44 ++++++++-----------
 .../lib/driver/sasl-authenticator.js            | 45 ++++++++++++++++++++
 .../javascript/gremlin-javascript/lib/utils.js  | 23 +++++++++-
 4 files changed, 99 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2a8b4b4f/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/authenticator.js
----------------------------------------------------------------------
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/authenticator.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/authenticator.js
new file mode 100644
index 0000000..053aecd
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/authenticator.js
@@ -0,0 +1,14 @@
+'use strict';
+
+/** @abstract */
+class Authenticator {
+  constructor(credentials) {
+    this._credentials = credentials;
+  }
+  
+  evaluateChallenge(ws, header) {
+    throw new Error("evaluateChallenge should be implemented");
+  }
+}
+
+module.exports = Authenticator;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2a8b4b4f/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
----------------------------------------------------------------------
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
index 0f7cedb..153c278 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/driver-remote-connection.js
@@ -22,7 +22,6 @@
  */
 'use strict';
 
-const crypto = require('crypto');
 const WebSocket = require('ws');
 const util = require('util');
 const RemoteConnection = require('./remote-connection').RemoteConnection;
@@ -31,7 +30,8 @@ const serializer = require('../structure/io/graph-serializer');
 const responseStatusCode = {
   success: 200,
   noContent: 204,
-  partialContent: 206
+  partialContent: 206,
+  authenticationChallenge:  407,
 };
 const defaultMimeType = 'application/vnd.gremlin-v2.0+json';
 
@@ -48,6 +48,7 @@ class DriverRemoteConnection extends RemoteConnection {
    * @param {Boolean} [options.rejectUnauthorized] Determines whether to verify or not the server certificate.
    * @param {String} [options.traversalSource] The traversal source. Defaults to: 'g'.
    * @param {GraphSONWriter} [options.writer] The writer to use.
+   * @param {Authenticator} [options.authenticator] The authentication handler to use.
    * @constructor
    */
   constructor(url, options) {
@@ -76,7 +77,13 @@ class DriverRemoteConnection extends RemoteConnection {
     const mimeType = options.mimeType || defaultMimeType;
     this._header = String.fromCharCode(mimeType.length) + mimeType;
     this.isOpen = false;
+    this.connectionError = false;
+    this.connectionErrorMessage = '';
     this.traversalSource = options.traversalSource || 'g';
+
+    if (options.authenticator) {
+      this._authenticator = options.authenticator;
+    }
   }
 
   /**
@@ -102,7 +109,7 @@ class DriverRemoteConnection extends RemoteConnection {
   /** @override */
   submit(bytecode) {
     return this.open().then(() => new Promise((resolve, reject) => {
-      const requestId = getUuid();
+      const requestId = utils.getUuid();
       this._responseHandlers[requestId] = {
         callback: (err, result) => err ? reject(err) : resolve(result),
         result: null
@@ -112,12 +119,12 @@ class DriverRemoteConnection extends RemoteConnection {
     }));
   }
 
-  _getRequest(id, bytecode) {
+  _getRequest(id, bytecode, op, args) {
     return ({
       'requestId': { '@type': 'g:UUID', '@value': id },
-      'op': 'bytecode',
+      'op': op || 'bytecode',
       'processor': 'traversal',
-      'args': {
+      'args': args || {
         'gremlin': this._writer.adaptObject(bytecode),
         'aliases': { 'g': this.traversalSource }
       }
@@ -151,7 +158,11 @@ class DriverRemoteConnection extends RemoteConnection {
       return;
     }
 
-    if (response.status.code >= 400) {
+    if (response.status.code === responseStatusCode.authenticationChallenge && this._authenticator) {
+       this._authenticator.evaluateChallenge(this._ws, this._header);
+       return;
+    }
+    else if (response.status.code >= 400) {
       // callback in error
       return handler.callback(
         new Error(util.format('Server error: %s (%d)', response.status.message, response.status.code)));
@@ -203,25 +214,6 @@ class DriverRemoteConnection extends RemoteConnection {
   }
 }
 
-function getUuid() {
-  const buffer = crypto.randomBytes(16);
-  //clear the version
-  buffer[6] &= 0x0f;
-  //set the version 4
-  buffer[6] |= 0x40;
-  //clear the variant
-  buffer[8] &= 0x3f;
-  //set the IETF variant
-  buffer[8] |= 0x80;
-  const hex = buffer.toString('hex');
-  return (
-    hex.substr(0, 8) + '-' +
-    hex.substr(8, 4) + '-' +
-    hex.substr(12, 4) + '-' +
-    hex.substr(16, 4) + '-' +
-    hex.substr(20, 12));
-}
-
 const bufferFromString = (Int8Array.from !== Buffer.from && Buffer.from) || function newBuffer(text) {
   return new Buffer(text, 'utf8');
 };

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2a8b4b4f/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/sasl-authenticator.js
----------------------------------------------------------------------
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/sasl-authenticator.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/sasl-authenticator.js
new file mode 100644
index 0000000..1f08b7d
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/driver/sasl-authenticator.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const Authenticator = require('./authenticator');
+const utils = require('../utils');
+
+class SaslAuthenticator extends Authenticator {
+  /**
+   * Creates a new instance of SaslAuthenticator.
+   * @param {Object} [credentials] The authentication credential options.
+   * @param {String} [credentials.username] The user for the authentication response.
+   * @param {String} [credentials.password] The plaintext password for authentication response.
+   * @constructor
+   */
+  constructor(credentials) {
+    super(credentials);
+  }
+  
+  evaluateChallenge(ws, header) {
+    const message = bufferFromString(header + JSON.stringify({
+      'requestId': { '@type': 'g:UUID', '@value': utils.getUuid() },
+      'op': 'authentication',
+      'processor': 'traversal',
+      'args': {
+        'sasl': this.saslArgument()
+      }
+    }));
+    
+    return ws.send(message);
+  }
+
+  saslArgument() {
+    if (this._credentials.username === null || this._credentials.username.length === 0 
+      || this._credentials.password === null || this._credentials.password.length === 0 ) {
+      return '';
+    }
+    return new Buffer(`\0${this._credentials.username}\0${this._credentials.password}`).toString('base64');
+  }
+}
+
+
+const bufferFromString = (Int8Array.from !== Buffer.from && Buffer.from) || function newBuffer(text) {
+  return new Buffer(text, 'utf8');
+};
+
+module.exports = SaslAuthenticator;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/2a8b4b4f/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js
----------------------------------------------------------------------
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js
index e3a001c..7abc5fe 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/utils.js
@@ -23,6 +23,8 @@
  */
 'use strict';
 
+const crypto = require('crypto');
+
 exports.toLong = function toLong(value) {
   return new Long(value);
 };
@@ -32,4 +34,23 @@ const Long = exports.Long = function Long(value) {
     throw new TypeError('Ty')
   }
   this.value = value.toString();
-};
\ No newline at end of file
+};
+
+exports.getUuid = function getUuid() {
+  const buffer = crypto.randomBytes(16);
+  //clear the version
+  buffer[6] &= 0x0f;
+  //set the version 4
+  buffer[6] |= 0x40;
+  //clear the variant
+  buffer[8] &= 0x3f;
+  //set the IETF variant
+  buffer[8] |= 0x80;
+  const hex = buffer.toString('hex');
+  return (
+    hex.substr(0, 8) + '-' +
+    hex.substr(8, 4) + '-' +
+    hex.substr(12, 4) + '-' +
+    hex.substr(16, 4) + '-' +
+    hex.substr(20, 12));
+}
\ No newline at end of file