This is an automated email from the ASF dual-hosted git repository.

valentyn pushed a commit to branch master-http
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/master-http by this push:
     new faa79409e1 sigv4 auth client implementation (#2601)
faa79409e1 is described below

commit faa79409e1f0019da00a6385ddc376d953c26022
Author: Valentyn Kahamlyk <vkagam...@users.noreply.github.com>
AuthorDate: Wed May 15 11:02:36 2024 -0700

    sigv4 auth client implementation (#2601)
---
 .../console/jsr223/DriverRemoteAcceptor.java       |  27 +--
 gremlin-driver/pom.xml                             |  15 ++
 .../apache/tinkerpop/gremlin/driver/Client.java    | 103 ++-------
 .../apache/tinkerpop/gremlin/driver/Cluster.java   |  16 +-
 .../tinkerpop/gremlin/driver/Connection.java       |  36 +---
 .../tinkerpop/gremlin/driver/RequestOptions.java   |  17 +-
 .../apache/tinkerpop/gremlin/driver/auth/Auth.java |  42 ++++
 .../gremlin/driver/{Auth.java => auth/Basic.java}  |  35 ++--
 .../tinkerpop/gremlin/driver/auth/Sigv4.java       | 229 +++++++++++++++++++++
 .../driver/exception/ResponseException.java        |  44 +---
 .../driver/handler/GremlinResponseHandler.java     |  21 +-
 .../driver/handler/HttpGremlinRequestEncoder.java  |  25 ++-
 .../handler/HttpGremlinResponseStreamDecoder.java  |   5 +-
 .../gremlin/server/GremlinDriverIntegrateTest.java |  80 +------
 .../server/GremlinServerAuthIntegrateTest.java     |  46 ++++-
 .../server/GremlinServerAuthzIntegrateTest.java    |   2 +-
 .../gremlin/server/HttpDriverIntegrateTest.java    |  22 --
 .../org/apache/tinkerpop/gremlin/util/Tokens.java  |  34 ---
 18 files changed, 424 insertions(+), 375 deletions(-)

diff --git 
a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java
 
b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java
index 86f920097d..713b848d40 100644
--- 
a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java
+++ 
b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java
@@ -173,10 +173,9 @@ public class DriverRemoteAcceptor implements 
RemoteAcceptor {
                     throw new RemoteException(String.format("%s - try 
increasing the timeout with the :remote command", 
responseException.getMessage()));
                 } else if (responseException.getResponseStatusCode() == 
HttpResponseStatus.INTERNAL_SERVER_ERROR)
                     throw new RemoteException(String.format(
-                            "Server could not serialize the result requested. 
Server error - %s. Note that the class must be serializable by the client and 
server for proper operation.", responseException.getMessage()),
-                            
responseException.getRemoteStackTrace().orElse(null));
+                            "Server could not serialize the result requested. 
Server error - %s. Note that the class must be serializable by the client and 
server for proper operation.", responseException.getMessage()));
                 else
-                    throw new RemoteException(responseException.getMessage(), 
responseException.getRemoteStackTrace().orElse(null));
+                    throw new RemoteException(responseException.getMessage());
             } else if (ex.getCause() != null) {
                 final Throwable rootCause = ExceptionUtils.getRootCause(ex);
                 if (rootCause instanceof TimeoutException)
@@ -202,31 +201,21 @@ public class DriverRemoteAcceptor implements 
RemoteAcceptor {
     private List<Result> send(final String gremlin) throws SaslException {
         try {
             final RequestOptions.Builder options = RequestOptions.build();
-            aliases.forEach(options::addAlias);
+            if (aliases.containsKey("g")) {
+                options.addG(aliases.get("g"));
+            }
+
             if (timeout > NO_TIMEOUT)
                 options.timeout(timeout);
 
             // TODO: console-specific user agent that isn't the one sent from 
gremlin-driver.
 
             final ResultSet rs = this.currentClient.submit(gremlin, 
options.create());
-            final List<Result> results = rs.all().get();
-            final Map<String, Object> statusAttributes = 
rs.statusAttributes().getNow(null);
-
-            // Check for and print warnings
-            if (null != statusAttributes && 
statusAttributes.containsKey(Tokens.STATUS_ATTRIBUTE_WARNINGS)) {
-                final Object warningAttributeObject = 
statusAttributes.get(Tokens.STATUS_ATTRIBUTE_WARNINGS);
-                if (warningAttributeObject instanceof List) {
-                    for (Object warningListItem : 
(List<?>)warningAttributeObject)
-                        
shellEnvironment.errPrintln(String.valueOf(warningListItem));
-                } else {
-                    
shellEnvironment.errPrintln(String.valueOf(warningAttributeObject));
-                }
-            }
 
-            return results;
+            return rs.all().get();
         } catch (Exception e) {
             // handle security error as-is and unwrapped
-            final Optional<Throwable> throwable  = 
Stream.of(ExceptionUtils.getThrowables(e)).filter(t -> t instanceof 
SaslException).findFirst();
+            final Optional<Throwable> throwable = 
Stream.of(ExceptionUtils.getThrowables(e)).filter(t -> t instanceof 
SaslException).findFirst();
             if (throwable.isPresent())
                 throw (SaslException) throwable.get();
 
diff --git a/gremlin-driver/pom.xml b/gremlin-driver/pom.xml
index 84cf73fd7d..8923bc0de6 100644
--- a/gremlin-driver/pom.xml
+++ b/gremlin-driver/pom.xml
@@ -50,6 +50,21 @@ limitations under the License.
             <artifactId>logback-classic</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-core</artifactId>
+            <version>1.12.720</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
         <!-- TinkerGraph is an optional dependency that is only required if 
doing deserialization of Graph instances -->
         <dependency>
             <groupId>org.apache.tinkerpop</groupId>
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index 97b9a05d1a..5a74c416fc 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
@@ -19,9 +19,6 @@
 package org.apache.tinkerpop.gremlin.driver;
 
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.exception.NoHostAvailableException;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
@@ -29,11 +26,13 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.net.ssl.SSLException;
 import java.net.ConnectException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -103,16 +102,7 @@ public abstract class Client {
      * @param graphOrTraversalSource rebinds the specified global Gremlin 
Server variable to "g"
      */
     public Client alias(final String graphOrTraversalSource) {
-        return alias(makeDefaultAliasMap(graphOrTraversalSource));
-    }
-
-    /**
-     * Creates a {@code Client} that supplies the specified set of aliases, 
thus allowing the user to re-name
-     * one or more globally defined {@link Graph} or {@link TraversalSource} 
server bindings for the context of
-     * the created {@code Client}.
-     */
-    public Client alias(final Map<String, String> aliases) {
-        return new AliasClusteredClient(this, aliases);
+        return new AliasClusteredClient(this, graphOrTraversalSource);
     }
 
     /**
@@ -137,7 +127,7 @@ public abstract class Client {
      * must be examined to determine the number of times that object should be 
presented in iteration.
      */
     public CompletableFuture<ResultSet> submitAsync(final Traversal traversal) 
{
-        throw new UnsupportedOperationException("This implementation does not 
support Traversal submission - use a sessionless Client created with from the 
alias() method");
+        throw new UnsupportedOperationException("This implementation does not 
support Traversal submission - use a Client created with from the alias() 
method");
     }
 
     /**
@@ -179,7 +169,7 @@ public abstract class Client {
      * must be examined to determine the number of times that object should be 
presented in iteration.
      */
     public CompletableFuture<ResultSet> submitAsync(final Bytecode bytecode) {
-        throw new UnsupportedOperationException("This implementation does not 
support Traversal submission - use a sessionless Client created with from the 
alias() method");
+        throw new UnsupportedOperationException("This implementation does not 
support Traversal submission - use a Client created with from the alias() 
method");
     }
 
     /**
@@ -190,7 +180,7 @@ public abstract class Client {
      * @see #submitAsync(Bytecode)
      */
     public CompletableFuture<ResultSet> submitAsync(final Bytecode bytecode, 
final RequestOptions options) {
-        throw new UnsupportedOperationException("This implementation does not 
support Traversal submission - use a sessionless Client created with from the 
alias() method");
+        throw new UnsupportedOperationException("This implementation does not 
support Traversal submission - use a Client created with from the alias() 
method");
     }
 
     /**
@@ -296,32 +286,8 @@ public abstract class Client {
     @Deprecated
     public CompletableFuture<ResultSet> submitAsync(final String gremlin, 
final String graphOrTraversalSource,
                                                     final Map<String, Object> 
parameters) {
-        Map<String, String> aliases = null;
-        if (graphOrTraversalSource != null && 
!graphOrTraversalSource.isEmpty()) {
-            aliases = makeDefaultAliasMap(graphOrTraversalSource);
-        }
-
-        return submitAsync(gremlin, aliases, parameters);
-    }
-
-    /**
-     * The asynchronous version of {@link #submit(String, Map)}} where the 
returned future will complete when the
-     * write of the request completes.
-     *
-     * @param gremlin    the gremlin script to execute
-     * @param parameters a map of parameters that will be bound to the script 
on execution
-     * @param aliases    aliases the specified global Gremlin Server variable 
some other name that then be used in the
-     *                   script where the key is the alias name and the value 
represents the global variable on the
-     *                   server
-     * @deprecated As of release 3.4.0, replaced by {@link 
#submitAsync(String, RequestOptions)}.
-     */
-    @Deprecated
-    public CompletableFuture<ResultSet> submitAsync(final String gremlin, 
final Map<String, String> aliases,
-                                                    final Map<String, Object> 
parameters) {
         final RequestOptions.Builder options = RequestOptions.build();
-        if (aliases != null && !aliases.isEmpty()) {
-            aliases.forEach(options::addAlias);
-        }
+        options.addG(graphOrTraversalSource);
 
         if (parameters != null && !parameters.isEmpty()) {
             parameters.forEach(options::addParameter);
@@ -350,7 +316,7 @@ public abstract class Client {
         // apply settings if they were made available
         options.getTimeout().ifPresent(timeout -> 
request.addTimeoutMillis(timeout));
         options.getParameters().ifPresent(params -> 
request.addBindings(params));
-        options.getAliases().ifPresent(aliases -> {if (aliases.get("g") != 
null) request.addG(aliases.get("g")); });
+        options.getG().ifPresent(g -> request.addG(g));
         options.getLanguage().ifPresent(lang -> request.addLanguage(lang));
         options.getMaterializeProperties().ifPresent(mp -> 
request.addMaterializeProperties(mp));
 
@@ -400,16 +366,9 @@ public abstract class Client {
         return cluster;
     }
 
-    protected Map<String, String> makeDefaultAliasMap(final String 
graphOrTraversalSource) {
-        final Map<String, String> aliases = new HashMap<>();
-        aliases.put("g", graphOrTraversalSource);
-        return aliases;
-    }
-
     /**
-     * A {@code Client} implementation that does not operate in a session.  
Requests are sent to multiple servers
-     * given a {@link LoadBalancingStrategy}.  Transactions are automatically 
committed
-     * (or rolled-back on error) after each request.
+     * A {@code Client} implementation.  Requests are sent to multiple servers 
given a {@link LoadBalancingStrategy}.
+     * Transactions are automatically committed (or rolled-back on error) 
after each request.
      */
     public final static class ClusteredClient extends Client {
 
@@ -461,17 +420,7 @@ public abstract class Client {
          */
         @Override
         public Client alias(final String graphOrTraversalSource) {
-            final Map<String, String> aliases = new HashMap<>();
-            aliases.put("g", graphOrTraversalSource);
-            return alias(aliases);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Client alias(final Map<String, String> aliases) {
-            return new AliasClusteredClient(this, aliases);
+            return new AliasClusteredClient(this, graphOrTraversalSource);
         }
 
         /**
@@ -550,7 +499,7 @@ public abstract class Client {
             return closing.get();
         }
 
-        private Consumer<Host> initializeConnectionSetupForHost = host -> {
+        private final Consumer<Host> initializeConnectionSetupForHost = host 
-> {
             try {
                 // hosts that don't initialize connection pools will come up 
as a dead host.
                 hostConnectionPools.put(host, new ConnectionPool(host, 
ClusteredClient.this));
@@ -603,13 +552,13 @@ public abstract class Client {
      */
     public static class AliasClusteredClient extends Client {
         private final Client client;
-        private final Map<String, String> aliases = new HashMap<>();
+        private final String graphOrTraversalSource;
         final CompletableFuture<Void> close = new CompletableFuture<>();
 
-        AliasClusteredClient(final Client client, final Map<String, String> 
aliases) {
+        AliasClusteredClient(final Client client, final String 
graphOrTraversalSource) {
             super(client.cluster);
             this.client = client;
-            this.aliases.putAll(aliases);
+            this.graphOrTraversalSource = graphOrTraversalSource;
         }
 
         @Override
@@ -642,17 +591,7 @@ public abstract class Client {
         public CompletableFuture<ResultSet> submitAsync(final RequestMessageV4 
msg) {
             final RequestMessageV4.Builder builder = 
RequestMessageV4.from(msg);
 
-            // only add aliases which aren't already present. if they are 
present then they represent request level
-            // overrides which should be mucked with
-            // TODO: replaced this with ARGS_G as we don't allow a map of 
aliases anymore.
-//            if (!aliases.isEmpty()) {
-//                final Map original = (Map) 
msg.getArgs().getOrDefault(Tokens.ARGS_ALIASES, Collections.emptyMap());
-//                aliases.forEach((k, v) -> {
-//                    if (!original.containsKey(k))
-//                        builder.addArg(Tokens.ARGS_ALIASES, aliases);
-//                });
-//            }
-            builder.addG(aliases.get("g"));
+            builder.addG(graphOrTraversalSource);
 
             return super.submitAsync(builder.create());
         }
@@ -675,9 +614,7 @@ public abstract class Client {
         @Override
         public RequestMessageV4.Builder buildMessage(final 
RequestMessageV4.Builder builder) {
             if (close.isDone()) throw new IllegalStateException("Client is 
closed");
-//            TODO: aliases not supported. replace with ARG_G.
-//            if (!aliases.isEmpty())
-//                builder.addArg(Tokens.ARGS_ALIASES, aliases);
+            builder.addG(graphOrTraversalSource);
 
             return client.buildMessage(builder);
         }
@@ -720,9 +657,9 @@ public abstract class Client {
          * {@inheritDoc}
          */
         @Override
-        public Client alias(final Map<String, String> aliases) {
+        public Client alias(final String graphOrTraversalSource) {
             if (close.isDone()) throw new IllegalStateException("Client is 
closed");
-            return new AliasClusteredClient(client, aliases);
+            return new AliasClusteredClient(client, graphOrTraversalSource);
         }
     }
 }
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
index 4505784224..057a8d0898 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
@@ -18,27 +18,26 @@
  */
 package org.apache.tinkerpop.gremlin.driver;
 
+import io.netty.bootstrap.Bootstrap;
 import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.ChannelOption;
-import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.SslProvider;
 import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
 import io.netty.util.concurrent.Future;
 import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.tinkerpop.gremlin.driver.auth.Auth;
 import org.apache.tinkerpop.gremlin.util.MessageSerializerV4;
 import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4;
 import org.apache.tinkerpop.gremlin.util.ser.SerializersV4;
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.nio.NioEventLoopGroup;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.TrustManagerFactory;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -68,7 +67,6 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
-import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 
 /**
@@ -361,7 +359,7 @@ public final class Cluster {
         return manager.serializer;
     }
 
-    List<UnaryOperator<FullHttpRequest>> getRequestInterceptor() {
+    List<RequestInterceptor> getRequestInterceptor() {
         return manager.interceptor;
     }
 
@@ -489,7 +487,7 @@ public final class Cluster {
         private boolean sslSkipCertValidation = false;
         private SslContext sslContext = null;
         private LoadBalancingStrategy loadBalancingStrategy = new 
LoadBalancingStrategy.RoundRobin();
-        private List<UnaryOperator<FullHttpRequest>> interceptors = new 
ArrayList<>();
+        private List<RequestInterceptor> interceptors = new ArrayList<>();
         private long connectionSetupTimeoutMillis = 
Connection.CONNECTION_SETUP_TIMEOUT_MILLIS;
         private boolean enableUserAgentOnConnect = true;
 
@@ -842,7 +840,7 @@ public final class Cluster {
         private final LoadBalancingStrategy loadBalancingStrategy;
         private final Optional<SslContext> sslContextOptional;
         private final Supplier<RequestMessageV4.Builder> validationRequest;
-        private final List<UnaryOperator<FullHttpRequest>> interceptor;
+        private final List<RequestInterceptor> interceptor;
 
         /**
          * Thread pool for requests.
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
index 8a07912189..c4694b63aa 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
@@ -89,6 +89,9 @@ final class Connection {
         if (cluster.isClosing())
             throw new IllegalStateException("Cannot open a connection with the 
cluster after close() is called");
 
+        if (client.isClosing())
+            throw new IllegalStateException("Cannot open a connection with the 
client after close() is called");
+
         final Bootstrap b = this.cluster.getFactory().createBootstrap();
         try {
             channelizer = new Channelizer.HttpChannelizer();
@@ -273,39 +276,6 @@ final class Connection {
         // guess). that seems to put the executor thread in a monitor state 
that it doesn't recover from. since all
         // the code in here is behind shutdownInitiated the synchronized 
doesn't seem necessary
         if (shutdownInitiated.compareAndSet(false, true)) {
-            // the session close message was removed in 3.5.0 after 
deprecation at 3.3.11. That removal was perhaps
-            // a bit hasty as session semantics may still require this message 
in certain cases. Until we can look
-            // at this in more detail, it seems best to bring back the old 
functionality to the driver.
-            // TODO: commented due to not supporting sessions with HTTP.
-            /*if (client instanceof Client.SessionedClient) {
-                final boolean forceClose = 
client.getSettings().getSession().get().isForceClosed();
-                final RequestMessageV4 closeMessage = client.buildMessage(
-                        
RequestMessageV4.build(Tokens.OPS_CLOSE).addArg(Tokens.ARGS_FORCE, 
forceClose)).create();
-
-                final CompletableFuture<ResultSet> closed = new 
CompletableFuture<>();
-
-                // TINKERPOP-2822 should investigate this write more carefully 
to check for sensible behavior
-                // in the event the Channel was not created but we try to send 
the close message
-                write(closeMessage, closed);
-
-                try {
-                    // make sure we get a response here to validate that 
things closed as expected.  on error, we'll let
-                    // the server try to clean up on its own.  the primary 
error here should probably be related to
-                    // protocol issues which should not be something a user 
has to fuss with.
-                    closed.join().all().get(cluster.getMaxWaitForClose(), 
TimeUnit.MILLISECONDS);
-                } catch (TimeoutException ex) {
-                    final String msg = String.format(
-                            "Timeout while trying to close connection on %s - 
force closing - server will close session on shutdown or expiration.",
-                            ((Client.SessionedClient) client).getSessionId());
-                    logger.warn(msg, ex);
-                } catch (Exception ex) {
-                    final String msg = String.format(
-                            "Encountered an error trying to close connection 
on %s - force closing - server will close session on shutdown or expiration.",
-                            ((Client.SessionedClient) client).getSessionId());
-                    logger.warn(msg, ex);
-                }
-            }*/
-
             // take a defensive posture here in the event the channelizer 
didn't get initialized somehow and a
             // close() on the Connection is still called
             if (channelizer != null)
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
index da6634d85c..b06e403048 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/RequestOptions.java
@@ -33,7 +33,7 @@ public final class RequestOptions {
 
     public static final RequestOptions EMPTY = RequestOptions.build().create();
 
-    private final Map<String,String> aliases;
+    private final String graphOrTraversalSource;
     private final Map<String, Object> parameters;
     private final Integer batchSize;
     private final Long timeout;
@@ -41,7 +41,7 @@ public final class RequestOptions {
     private final String materializeProperties;
 
     private RequestOptions(final Builder builder) {
-        this.aliases = builder.aliases;
+        this.graphOrTraversalSource = builder.graphOrTraversalSource;
         this.parameters = builder.parameters;
         this.batchSize = builder.batchSize;
         this.timeout = builder.timeout;
@@ -49,8 +49,8 @@ public final class RequestOptions {
         this.materializeProperties = builder.materializeProperties;
     }
 
-    public Optional<Map<String, String>> getAliases() {
-        return Optional.ofNullable(aliases);
+    public Optional<String> getG() {
+        return Optional.ofNullable(graphOrTraversalSource);
     }
 
     public Optional<Map<String, Object>> getParameters() {
@@ -76,7 +76,7 @@ public final class RequestOptions {
     }
 
     public static final class Builder {
-        private Map<String,String> aliases = null;
+        private String graphOrTraversalSource = null;
         private Map<String, Object> parameters = null;
         private Integer batchSize = null;
         private Long timeout = null;
@@ -86,11 +86,8 @@ public final class RequestOptions {
         /**
          * The aliases to set on the request.
          */
-        public Builder addAlias(final String aliasName, final String 
actualName) {
-            if (null == aliases)
-                aliases = new HashMap<>();
-
-            aliases.put(aliasName, actualName);
+        public Builder addG(final String graphOrTraversalSource) {
+            this.graphOrTraversalSource = graphOrTraversalSource;
             return this;
         }
 
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Auth.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Auth.java
new file mode 100644
index 0000000000..8437cf7609
--- /dev/null
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Auth.java
@@ -0,0 +1,42 @@
+/*
+ * 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.driver.auth;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import org.apache.tinkerpop.gremlin.driver.RequestInterceptor;
+
+public interface Auth extends RequestInterceptor {
+    static Auth basic(final String username, final String password) {
+        return new Basic(username, password);
+    }
+
+    static Auth sigv4(final String regionName, final AWSCredentialsProvider 
awsCredentialsProvider) {
+        return new Sigv4(regionName, awsCredentialsProvider);
+    }
+
+    static Auth sigv4(final String regionName, final AWSCredentialsProvider 
awsCredentialsProvider, final String serviceName) {
+        return new Sigv4(regionName, awsCredentialsProvider, serviceName);
+    }
+
+    public class AuthenticationException extends RuntimeException {
+        public AuthenticationException(Exception cause) {
+            super(cause);
+        }
+    }
+}
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Auth.java 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Basic.java
similarity index 52%
rename from 
gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Auth.java
rename to 
gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Basic.java
index fa832aeca0..578a241c92 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Auth.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Basic.java
@@ -16,35 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tinkerpop.gremlin.driver;
+package org.apache.tinkerpop.gremlin.driver.auth;
 
 import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.codec.http.HttpHeaderNames;
 
 import java.util.Base64;
 
-public abstract class Auth implements RequestInterceptor {
+public class Basic implements Auth {
 
-    public static Auth basic(final String username, final String password) {
-        return new Basic(username, password);
-    }
-
-    public static class Basic extends Auth {
+    private final String username;
+    private final String password;
 
-        private final String username;
-        private final String password;
-
-        private Basic(final String username, final String password ) {
-            this.username = username;
-            this.password = password;
-        }
+    public Basic(final String username, final String password) {
+        this.username = username;
+        this.password = password;
+    }
 
-        @Override
-        public FullHttpRequest apply(FullHttpRequest fullHttpRequest) {
-            final String valueToEncode = username + ":" + password;
-            fullHttpRequest.headers().add(HttpHeaderNames.AUTHORIZATION,
-                    "Basic " + 
Base64.getEncoder().encodeToString(valueToEncode.getBytes()));
-            return fullHttpRequest;
-        }
+    @Override
+    public FullHttpRequest apply(final FullHttpRequest fullHttpRequest) {
+        final String valueToEncode = username + ":" + password;
+        fullHttpRequest.headers().add(HttpHeaderNames.AUTHORIZATION,
+                "Basic " + 
Base64.getEncoder().encodeToString(valueToEncode.getBytes()));
+        return fullHttpRequest;
     }
 }
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Sigv4.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Sigv4.java
new file mode 100644
index 0000000000..8e2665dc9c
--- /dev/null
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/auth/Sigv4.java
@@ -0,0 +1,229 @@
+/*
+ * 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.driver.auth;
+
+import com.amazonaws.DefaultRequest;
+import com.amazonaws.SignableRequest;
+import com.amazonaws.auth.AWS4Signer;
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.BasicSessionCredentials;
+import com.amazonaws.http.HttpMethodName;
+import com.amazonaws.util.SdkHttpUtils;
+import com.amazonaws.util.StringUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaders;
+import org.apache.http.entity.StringEntity;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.amazonaws.auth.internal.SignerConstants.AUTHORIZATION;
+import static com.amazonaws.auth.internal.SignerConstants.HOST;
+import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_DATE;
+import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_SECURITY_TOKEN;
+
+public class Sigv4 implements Auth {
+
+    static final String NEPTUNE_SERVICE_NAME = "neptune-db";
+    private final AWSCredentialsProvider awsCredentialsProvider;
+    private final AWS4Signer aws4Signer;
+
+    public Sigv4(final String regionName, final AWSCredentialsProvider 
awsCredentialsProvider) {
+        this(regionName, awsCredentialsProvider, NEPTUNE_SERVICE_NAME);
+    }
+
+    public Sigv4(final String regionName, final AWSCredentialsProvider 
awsCredentialsProvider, final String serviceName) {
+        this.awsCredentialsProvider = awsCredentialsProvider;
+
+        aws4Signer = new AWS4Signer();
+        aws4Signer.setRegionName(regionName);
+        aws4Signer.setServiceName(serviceName);
+    }
+
+    @Override
+    public FullHttpRequest apply(final FullHttpRequest fullHttpRequest) {
+        try {
+            // Convert Http request into an AWS SDK signable request
+            final SignableRequest<?> awsSignableRequest = 
toSignableRequest(fullHttpRequest);
+
+            // Sign the AWS SDK signable request (which internally adds some 
HTTP headers)
+            final AWSCredentials credentials = 
awsCredentialsProvider.getCredentials();
+            aws4Signer.sign(awsSignableRequest, credentials);
+
+            // extract session token if temporary credentials are provided
+            String sessionToken = "";
+            if ((credentials instanceof BasicSessionCredentials)) {
+                sessionToken = ((BasicSessionCredentials) 
credentials).getSessionToken();
+            }
+
+            // todo: confirm is needed to replace header `Host` with `host`
+            fullHttpRequest.headers().remove(HttpHeaderNames.HOST);
+            fullHttpRequest.headers().add(HOST, 
awsSignableRequest.getHeaders().get(HOST));
+            fullHttpRequest.headers().add(X_AMZ_DATE, 
awsSignableRequest.getHeaders().get(X_AMZ_DATE));
+            fullHttpRequest.headers().add(AUTHORIZATION, 
awsSignableRequest.getHeaders().get(AUTHORIZATION));
+
+            if (!sessionToken.isEmpty()) {
+                fullHttpRequest.headers().add(X_AMZ_SECURITY_TOKEN, 
sessionToken);
+            }
+        } catch (final Exception ex) {
+            throw new AuthenticationException(ex);
+        }
+        return fullHttpRequest;
+    }
+
+    private SignableRequest<?> toSignableRequest(final FullHttpRequest 
request) throws IOException {
+
+        // make sure the request contains the minimal required set of 
information
+        checkNotNull(request.uri(), "The request URI must not be null");
+        checkNotNull(request.method(), "The request method must not be null");
+
+        // convert the headers to the internal API format
+        final HttpHeaders headers = request.headers();
+        final Map<String, String> headersInternal = new HashMap<>();
+
+        String hostName = "";
+
+        // we don't want to add the Host header as the Signer always adds the 
host header.
+        for (String header : headers.names()) {
+            // Skip adding the Host header as the signing process will add one.
+            if (!header.equalsIgnoreCase(HOST)) {
+                headersInternal.put(header, headers.get(header));
+            } else {
+                hostName = headers.get(header);
+            }
+        }
+
+        // convert the parameters to the internal API format
+        final URI uri = URI.create(request.uri());
+        final Map<String, List<String>> parametersInternal = 
extractParametersFromQueryString(uri.getQuery());
+
+        // carry over the entity (or an empty entity, if no entity is provided)
+        final InputStream content;
+        final ByteBuf contentBuffer = request.content();
+        boolean hasContent = false;
+        try {
+            if (contentBuffer != null && contentBuffer.isReadable()) {
+                hasContent = true;
+                contentBuffer.retain();
+                final byte[] bytes = new byte[contentBuffer.readableBytes()];
+                contentBuffer.getBytes(contentBuffer.readerIndex(), bytes);
+                content = new ByteArrayInputStream(bytes);
+            } else {
+                content = new StringEntity("").getContent();
+            }
+        } finally {
+            if (hasContent) {
+                contentBuffer.release();
+            }
+        }
+
+        if (StringUtils.isNullOrEmpty(hostName)) {
+            // try to extract hostname from the uri since hostname was not 
provided in the header.
+            final String authority = uri.getAuthority();
+            if (authority == null) {
+                throw new IllegalArgumentException("Unable to identify host 
information,"
+                        + " either hostname should be provided in the uri or 
should be passed as a header");
+            }
+
+            hostName = authority;
+        }
+
+        final URI endpointUri = URI.create("http://"; + hostName);
+
+        return convertToSignableRequest(
+                request.method().name(),
+                endpointUri,
+                uri.getPath(),
+                headersInternal,
+                parametersInternal,
+                content);
+    }
+
+    private HashMap<String, List<String>> 
extractParametersFromQueryString(final String queryStr) {
+
+        final HashMap<String, List<String>> parameters = new HashMap<>();
+
+        if (queryStr == null) {
+            return parameters;
+        }
+
+        // convert the parameters to the internal API format
+        for (final String queryParam : queryStr.split("&")) {
+
+            if (!queryParam.isEmpty()) {
+                final String[] keyValuePair = queryParam.split("=", 2);
+
+                // parameters are encoded in the HTTP request, we need to 
decode them here
+                final String key = SdkHttpUtils.urlDecode(keyValuePair[0]);
+                final String value;
+
+                if (keyValuePair.length == 2) {
+                    value = SdkHttpUtils.urlDecode(keyValuePair[1]);
+                } else {
+                    value = "";
+                }
+
+                // insert the parameter key into the map, if not yet present
+                if (!parameters.containsKey(key)) {
+                    parameters.put(key, new ArrayList<>());
+                }
+
+                // append the parameter value to the list for the given key
+                parameters.get(key).add(value);
+            }
+        }
+
+        return parameters;
+    }
+
+    private SignableRequest<?> convertToSignableRequest(
+            final String httpMethodName,
+            final URI httpEndpointUri,
+            final String resourcePath,
+            final Map<String, String> httpHeaders,
+            final Map<String, List<String>> httpParameters,
+            final InputStream httpContent) {
+
+        // create the HTTP AWS SDK Signable Request and carry over information
+        final DefaultRequest<?> awsRequest = new 
DefaultRequest<>(NEPTUNE_SERVICE_NAME);
+        awsRequest.setHttpMethod(HttpMethodName.fromValue(httpMethodName));
+        awsRequest.setEndpoint(httpEndpointUri);
+        awsRequest.setResourcePath(resourcePath);
+        awsRequest.setHeaders(httpHeaders);
+        awsRequest.setParameters(httpParameters);
+        awsRequest.setContent(httpContent);
+
+        return awsRequest;
+    }
+
+    private void checkNotNull(final Object obj, final String errMsg) {
+        if (obj == null) {
+            throw new IllegalArgumentException(errMsg);
+        }
+    }
+}
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/exception/ResponseException.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/exception/ResponseException.java
index 13aaeed725..84d22650bb 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/exception/ResponseException.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/exception/ResponseException.java
@@ -20,37 +20,22 @@ package org.apache.tinkerpop.gremlin.driver.exception;
 
 import io.netty.handler.codec.http.HttpResponseStatus;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public class ResponseException extends Exception {
     private final HttpResponseStatus responseStatusCode;
-    private final String remoteStackTrace;
-    private final List<String> remoteExceptionHierarchy;
-    private final Map<String,Object> attributes;
+    private final String remoteException;
 
     public ResponseException(final HttpResponseStatus responseStatusCode, 
final String serverMessage) {
-        this(responseStatusCode, serverMessage, null, null);
-    }
-
-    public ResponseException(final HttpResponseStatus responseStatusCode, 
final String serverMessage,
-                             final List<String> remoteExceptionHierarchy, 
final String remoteStackTrace) {
-        this(responseStatusCode, serverMessage, remoteExceptionHierarchy, 
remoteStackTrace, null);
+        this(responseStatusCode, serverMessage, null);
     }
 
     public ResponseException(final HttpResponseStatus responseStatusCode, 
final String serverMessage,
-                             final List<String> remoteExceptionHierarchy, 
final String remoteStackTrace,
-                             final Map<String,Object> statusAttributes) {
+                             final String remoteException) {
         super(serverMessage);
         this.responseStatusCode = responseStatusCode;
-        this.remoteExceptionHierarchy = remoteExceptionHierarchy != null ? 
Collections.unmodifiableList(remoteExceptionHierarchy) : null;
-        this.remoteStackTrace = remoteStackTrace;
-        this.attributes = statusAttributes != null ? 
Collections.unmodifiableMap(statusAttributes) : null;
+        this.remoteException = remoteException;
     }
 
     public HttpResponseStatus getResponseStatusCode() {
@@ -58,24 +43,9 @@ public class ResponseException extends Exception {
     }
 
     /**
-     * The stacktrace produced by the remote server.
-     */
-    public Optional<String> getRemoteStackTrace() {
-        return Optional.ofNullable(remoteStackTrace);
-    }
-
-    /**
-     * The list of exceptions generated by the server starting with the 
top-most one followed by its "cause". That
-     * cause is then followed by its cause and so on down the line.
-     */
-    public Optional<List<String>> getRemoteExceptionHierarchy() {
-        return Optional.ofNullable(remoteExceptionHierarchy);
-    }
-
-    /**
-     * Gets any status attributes from the response.
+     * The exception generated by the server.
      */
-    public Optional<Map<String, Object>> getStatusAttributes() {
-        return Optional.ofNullable(attributes);
+    public String getRemoteException() {
+        return remoteException;
     }
 }
\ No newline at end of file
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java
index 18035ff6c8..0efa524ec8 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/GremlinResponseHandler.java
@@ -25,16 +25,13 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.tinkerpop.gremlin.driver.Result;
 import org.apache.tinkerpop.gremlin.driver.ResultQueue;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
-import org.apache.tinkerpop.gremlin.util.Tokens;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.apache.tinkerpop.gremlin.util.message.ResponseMessageV4;
 import org.apache.tinkerpop.gremlin.util.ser.SerializationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -85,17 +82,11 @@ public class GremlinResponseHandler extends 
SimpleChannelInboundHandler<Response
         } else {
             // this is a "success" but represents no results otherwise it is 
an error
             if (statusCode != HttpResponseStatus.NO_CONTENT) {
-                final Map<String, Object> attributes = 
response.getStatus().getAttributes();
-                final String stackTrace = 
attributes.containsKey(Tokens.STATUS_ATTRIBUTE_STACK_TRACE) ?
-                        (String) 
attributes.get(Tokens.STATUS_ATTRIBUTE_STACK_TRACE) : null;
-                final List<String> exceptions = 
attributes.containsKey(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS) ?
-                        (List<String>) 
attributes.get(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS) : null;
                 queue.markError(new 
ResponseException(response.getStatus().getCode(), 
response.getStatus().getMessage(),
-                        exceptions, stackTrace, 
cleanStatusAttributes(attributes)));
+                        response.getStatus().getException()));
             }
         }
 
-        // todo:
         // as this is a non-PARTIAL_CONTENT code - the stream is done.
         if (statusCode != HttpResponseStatus.PARTIAL_CONTENT) {
             final ResultQueue current = pending.getAndSet(null);
@@ -120,14 +111,4 @@ public class GremlinResponseHandler extends 
SimpleChannelInboundHandler<Response
         if 
(!IteratorUtils.anyMatch(ExceptionUtils.getThrowableList(cause).iterator(), t 
-> t instanceof SerializationException))
             if (ctx.channel().isActive()) ctx.close();
     }
-
-    // todo: solution is not decided
-    private Map<String, Object> cleanStatusAttributes(final Map<String, 
Object> statusAttributes) {
-        final Map<String, Object> m = new HashMap<>();
-        statusAttributes.forEach((k, v) -> {
-            if (!k.equals(Tokens.STATUS_ATTRIBUTE_EXCEPTIONS) && 
!k.equals(Tokens.STATUS_ATTRIBUTE_STACK_TRACE))
-                m.put(k, v);
-        });
-        return m;
-    }
 }
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java
index a004c899a7..500e3e1858 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinRequestEncoder.java
@@ -28,15 +28,19 @@ import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http.HttpResponseStatus;
 import io.netty.handler.codec.http.HttpVersion;
+import org.apache.tinkerpop.gremlin.driver.RequestInterceptor;
 import org.apache.tinkerpop.gremlin.driver.UserAgent;
+import org.apache.tinkerpop.gremlin.driver.auth.Auth;
+import org.apache.tinkerpop.gremlin.driver.auth.Auth.AuthenticationException;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.util.MessageSerializerV4;
 import org.apache.tinkerpop.gremlin.util.message.RequestMessageV4;
 import org.apache.tinkerpop.gremlin.util.ser.SerTokens;
+import org.apache.tinkerpop.gremlin.util.ser.SerializationException;
 
+import java.net.InetSocketAddress;
 import java.util.List;
-import java.util.function.UnaryOperator;
 
 /**
  * Converts {@link RequestMessageV4} to a {@code HttpRequest}.
@@ -46,9 +50,9 @@ public final class HttpGremlinRequestEncoder extends 
MessageToMessageEncoder<Req
 
     private final MessageSerializerV4<?> serializer;
     private final boolean userAgentEnabled;
-    private final List<UnaryOperator<FullHttpRequest>> interceptors;
+    private final List<RequestInterceptor> interceptors;
 
-    public HttpGremlinRequestEncoder(final MessageSerializerV4<?> serializer, 
final List<UnaryOperator<FullHttpRequest>> interceptors, boolean 
userAgentEnabled) {
+    public HttpGremlinRequestEncoder(final MessageSerializerV4<?> serializer, 
final List<RequestInterceptor> interceptors, boolean userAgentEnabled) {
         this.serializer = serializer;
         this.interceptors = interceptors;
         this.userAgentEnabled = userAgentEnabled;
@@ -61,8 +65,7 @@ public final class HttpGremlinRequestEncoder extends 
MessageToMessageEncoder<Req
         if (requestMessage.getField("gremlin") instanceof Bytecode &&
                 !mimeType.equals(SerTokens.MIME_GRAPHSON_V4) &&
                 !mimeType.equals(SerTokens.MIME_GRAPHBINARY_V4)) {
-            // todo: correct status code !!!
-            throw new 
ResponseException(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format(
+            throw new ResponseException(HttpResponseStatus.BAD_REQUEST, 
String.format(
                     "An error occurred during serialization of this request 
[%s] - it could not be sent to the server - Reason: only GraphSON3 and 
GraphBinary recommended for serialization of Bytecode requests, but used %s",
                     requestMessage, serializer.getClass().getName()));
         }
@@ -73,21 +76,25 @@ public final class HttpGremlinRequestEncoder extends 
MessageToMessageEncoder<Req
             request.headers().add(HttpHeaderNames.CONTENT_TYPE, mimeType);
             request.headers().add(HttpHeaderNames.CONTENT_LENGTH, 
buffer.readableBytes());
             request.headers().add(HttpHeaderNames.ACCEPT, mimeType);
+            request.headers().add(HttpHeaderNames.HOST, ((InetSocketAddress) 
channelHandlerContext.channel().remoteAddress()).getAddress().getHostAddress());
             if (userAgentEnabled) {
                 request.headers().add(HttpHeaderNames.USER_AGENT, 
UserAgent.USER_AGENT);
             }
 
-            for (final UnaryOperator<FullHttpRequest> interceptor: 
interceptors ) {
+            for (final RequestInterceptor interceptor : interceptors) {
                 request = interceptor.apply(request);
             }
             objects.add(request);
 
             System.out.println("----------------------------");
-        } catch (Exception ex) {
-            // todo: correct status code !!!
-            throw new 
ResponseException(HttpResponseStatus.INTERNAL_SERVER_ERROR, String.format(
+        } catch (SerializationException ex) {
+            throw new ResponseException(HttpResponseStatus.BAD_REQUEST, 
String.format(
                     "An error occurred during serialization of this request 
[%s] - it could not be sent to the server - Reason: %s",
                     requestMessage, ex));
+        } catch (AuthenticationException ex) {
+            throw new ResponseException(HttpResponseStatus.BAD_REQUEST, 
String.format(
+                    "An error occurred during authentication [%s] - it could 
not be sent to the server - Reason: %s",
+                    requestMessage, ex));
         }
     }
 }
diff --git 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java
 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java
index 4ebfb5c172..83a294a7b0 100644
--- 
a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java
+++ 
b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/HttpGremlinResponseStreamDecoder.java
@@ -42,9 +42,8 @@ import java.util.Objects;
 
 public class HttpGremlinResponseStreamDecoder extends 
MessageToMessageDecoder<DefaultHttpObject> {
 
-    // todo: move out
-    public static final AttributeKey<Boolean> IS_FIRST_CHUNK = 
AttributeKey.valueOf("isFirstChunk");
-    public static final AttributeKey<HttpResponseStatus> RESPONSE_STATUS = 
AttributeKey.valueOf("responseStatus");
+    private static final AttributeKey<Boolean> IS_FIRST_CHUNK = 
AttributeKey.valueOf("isFirstChunk");
+    private static final AttributeKey<HttpResponseStatus> RESPONSE_STATUS = 
AttributeKey.valueOf("responseStatus");
 
     private final MessageSerializerV4<?> serializer;
     private final ObjectMapper mapper = new ObjectMapper();
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 39d86bf879..d380061ef7 100644
--- 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@ -71,12 +71,9 @@ import java.util.stream.IntStream;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.AllOf.allOf;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.hamcrest.core.StringContains.containsString;
 import static org.hamcrest.core.StringEndsWith.endsWith;
-import static org.hamcrest.number.OrderingComparison.greaterThan;
-import static org.hamcrest.number.OrderingComparison.lessThanOrEqualTo;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -210,27 +207,29 @@ public class GremlinDriverIntegrateTest extends 
AbstractGremlinServerIntegration
     @Test
     public void shouldInterceptRequestsWithHandshake() throws Exception {
         final int requestsToMake = 32;
-        final AtomicInteger websocketHandshakeRequests = new AtomicInteger(0);
+        final AtomicInteger handshakeRequests = new AtomicInteger(0);
 
         final Cluster cluster = TestClientFactory.build().
                 minConnectionPoolSize(1).maxConnectionPoolSize(1).
                 requestInterceptor(r -> {
-            websocketHandshakeRequests.incrementAndGet();
+            handshakeRequests.incrementAndGet();
             return r;
         }).create();
 
         try {
             final Client client = cluster.connect();
             for (int ix = 0; ix < requestsToMake; ix++) {
-                assertEquals(ix + 1, client.submit(ix + 
"+1").all().get().get(0).getInt());
+                final List<Result> result = client.submit(ix + 
"+1").all().get();
+                assertEquals(ix + 1, result.get(0).getInt());
             }
         } finally {
             cluster.close();
         }
 
-        assertEquals(1, websocketHandshakeRequests.get());
+        assertEquals(requestsToMake, handshakeRequests.get());
     }
 
+    @Ignore("Reading for streaming GraphSON is not supported")
     @Test
     public void shouldReportErrorWhenRequestCantBeSerialized() throws 
Exception {
         final Cluster cluster = 
TestClientFactory.build().serializer(SerializersV4.GRAPHSON_V4).create();
@@ -289,69 +288,6 @@ public class GremlinDriverIntegrateTest extends 
AbstractGremlinServerIntegration
         }
     }
 
-    @Ignore("websockets test")
-    @Test
-    public void shouldKeepAliveForWebSockets() throws Exception {
-        // keep the connection pool size at 1 to remove the possibility of 
lots of connections trying to ping which will
-        // complicate the assertion logic
-        final Cluster cluster = TestClientFactory.build().
-                minConnectionPoolSize(1).
-                maxConnectionPoolSize(1).create();
-        try {
-            final Client client = cluster.connect();
-
-            // fire up lots of requests so as to schedule/deschedule lots of 
ping jobs
-            for (int ix = 0; ix < 500; ix++) {
-                assertEquals(2, 
client.submit("1+1").all().get().get(0).getInt());
-            }
-
-            // don't send any messages for a bit so that the driver pings in 
the background
-            Thread.sleep(3000);
-
-            // make sure no bonus messages sorta fire off once we get back to 
sending requests
-            for (int ix = 0; ix < 500; ix++) {
-                assertEquals(2, 
client.submit("1+1").all().get().get(0).getInt());
-            }
-
-            // there really shouldn't be more than 3 of these sent. should 
definitely be at least one though
-            final long messages = logCaptor.getLogs().stream().filter(m -> 
m.contains("Sending ping frame to the server")).count();
-            assertThat(messages, allOf(greaterThan(0L), 
lessThanOrEqualTo(3L)));
-        } finally {
-            cluster.close();
-        }
-    }
-
-    @Ignore("websockets test")
-    @Test
-    public void shouldKeepAliveForWebSocketsWithNoInFlightRequests() throws 
Exception {
-        // keep the connection pool size at 1 to remove the possibility of 
lots of connections trying to ping which will
-        // complicate the assertion logic
-        final Cluster cluster = TestClientFactory.build().
-                minConnectionPoolSize(1).
-                maxConnectionPoolSize(1).create();
-        try {
-            final Client client = cluster.connect();
-
-            // forcefully initialize the client to mimic a scenario when 
client has some active connection with no
-            // in flight requests on them.
-            client.init();
-
-            // don't send any messages for a bit so that the driver pings in 
the background
-            Thread.sleep(3000);
-
-            // make sure no bonus messages sorta fire off once we get back to 
sending requests
-            for (int ix = 0; ix < 500; ix++) {
-                assertEquals(2, 
client.submit("1+1").all().get().get(0).getInt());
-            }
-
-            // there really shouldn't be more than 3 of these sent. should 
definitely be at least one though
-            final long messages = logCaptor.getLogs().stream().filter(m -> 
m.contains("Sending ping frame to the server")).count();
-            assertThat(messages, allOf(greaterThan(0L), 
lessThanOrEqualTo(3L)));
-        } finally {
-            cluster.close();
-        }
-    }
-
     @Test
     public void shouldEventuallySucceedAfterChannelLevelError() {
         final Cluster cluster = TestClientFactory.build()
@@ -537,9 +473,7 @@ public class GremlinDriverIntegrateTest extends 
AbstractGremlinServerIntegration
                 assertThat(inner.getMessage(), endsWith("Division by zero"));
 
                 final ResponseException rex = (ResponseException) inner;
-                assertEquals("java.lang.ArithmeticException", 
rex.getRemoteExceptionHierarchy().get().get(0));
-                assertEquals(1, 
rex.getRemoteExceptionHierarchy().get().size());
-                assertThat(rex.getRemoteStackTrace().get(), 
containsString("Division by zero"));
+                assertEquals("java.lang.ArithmeticException", 
rex.getRemoteException());
             }
 
             // should not die completely just because we had a bad 
serialization error.  that kind of stuff happens
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 c33e42ba29..4c3ad5d18b 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
@@ -18,6 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.server;
 
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSCredentialsProvider;
+import io.netty.handler.codec.http.FullHttpRequest;
 import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
@@ -29,13 +32,20 @@ import org.junit.Test;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
 
-import static org.apache.tinkerpop.gremlin.driver.Auth.basic;
+import static org.apache.tinkerpop.gremlin.driver.auth.Auth.basic;
+import static org.apache.tinkerpop.gremlin.driver.auth.Auth.sigv4;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.startsWith;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.AnyOf.anyOf;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -59,6 +69,9 @@ public class GremlinServerAuthIntegrateTest extends 
AbstractGremlinServerIntegra
 
         final String nameOfTest = name.getMethodName();
         switch (nameOfTest) {
+            case "shouldPassSigv4ToServer":
+                settings.authentication = new 
Settings.AuthenticationSettings();
+                break;
             case "shouldAuthenticateOverSslWithPlainText":
             case "shouldFailIfSslEnabledOnServerButNotClient":
                 final Settings.SslSettings sslConfig = new 
Settings.SslSettings();
@@ -72,6 +85,34 @@ public class GremlinServerAuthIntegrateTest extends 
AbstractGremlinServerIntegra
         return settings;
     }
 
+    @Test
+    public void shouldPassSigv4ToServer() throws Exception {
+        final AWSCredentialsProvider credentialsProvider = 
mock(AWSCredentialsProvider.class);
+        final AWSCredentials credentials = mock(AWSCredentials.class);
+        when(credentialsProvider.getCredentials()).thenReturn(credentials);
+        when(credentials.getAWSAccessKeyId()).thenReturn("I am 
AWSAccessKeyId");
+        when(credentials.getAWSSecretKey()).thenReturn("I am AWSSecretKey");
+
+        final AtomicReference<FullHttpRequest> fullHttpRequest = new 
AtomicReference<>();
+        final Cluster cluster = TestClientFactory.build()
+                .auth(sigv4("us-west2", credentialsProvider))
+                .requestInterceptor(r -> {
+                    fullHttpRequest.set(r);
+                    return r;
+                })
+                .create();
+        final Client client = cluster.connect();
+        client.submit("1+1").all().get();
+
+        assertNotNull(fullHttpRequest.get().headers().get("X-Amz-Date"));
+        assertThat(fullHttpRequest.get().headers().get("Authorization"),
+                startsWith("AWS4-HMAC-SHA256 Credential=I am AWSAccessKeyId"));
+        assertThat(fullHttpRequest.get().headers().get("Authorization"),
+                containsString("/us-west2/neptune-db/aws4_request, 
SignedHeaders=accept;content-length;content-type;host;user-agent;x-amz-date, 
Signature="));
+
+        cluster.close();
+    }
+
     @Test
     public void shouldFailIfSslEnabledOnServerButNotClient() throws Exception {
         final Cluster cluster = TestClientFactory.open();
@@ -102,8 +143,11 @@ public class GremlinServerAuthIntegrateTest extends 
AbstractGremlinServerIntegra
         final Cluster cluster = TestClientFactory.build()
                 .enableSsl(true).sslSkipCertValidation(true)
                 .auth(basic("stephen", "password")).create();
+
         final Client client = cluster.connect();
 
+        client.submit("1+1").all().get();
+
         assertConnection(cluster, client);
     }
 
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
index 8cdb5a32ff..08eb912d5f 100644
--- 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthzIntegrateTest.java
@@ -49,7 +49,7 @@ import java.util.Base64;
 import java.util.HashMap;
 import java.util.Objects;
 
-import static org.apache.tinkerpop.gremlin.driver.Auth.basic;
+import static org.apache.tinkerpop.gremlin.driver.auth.Auth.basic;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/HttpDriverIntegrateTest.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/HttpDriverIntegrateTest.java
index 2205434174..514a88d80e 100644
--- 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/HttpDriverIntegrateTest.java
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/HttpDriverIntegrateTest.java
@@ -29,7 +29,6 @@ import 
org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
 import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
-import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.util.ExceptionHelper;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -43,8 +42,6 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
 
 import static 
org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.hamcrest.CoreMatchers.is;
@@ -153,24 +150,6 @@ public class HttpDriverIntegrateTest extends 
AbstractGremlinServerIntegrationTes
         }
     }
 
-//    @Test
-//    public void shouldFailToUseTx() {
-//        final Cluster cluster = TestClientFactory.build().create();
-//        try {
-//            final GraphTraversalSource g = 
traversal().with(DriverRemoteConnection.using(cluster));
-//            final Transaction tx = g.tx();
-//            final GraphTraversalSource gtx = tx.begin();
-//            gtx.inject("1").toList();
-//            fail("Can't use tx() with HTTP");
-//        } catch (Exception ex) {
-//            final Throwable t = ExceptionUtils.getRootCause(ex);
-//            // assertEquals("Cannot use sessions or tx() with 
HttpChannelizer", t.getMessage());
-//            assertEquals("not implemented", t.getMessage());
-//        } finally {
-//            cluster.close();
-//        }
-//    }
-
     @Test
     public void shouldDeserializeErrorWithGraphBinary() {
         final Cluster cluster = TestClientFactory.build().create();
@@ -185,7 +164,6 @@ public class HttpDriverIntegrateTest extends 
AbstractGremlinServerIntegrationTes
         }
     }
 
-    @Ignore("driver side error")
     @Test
     public void shouldReportErrorWhenRequestCantBeSerialized() throws 
Exception {
         final Cluster cluster = TestClientFactory.build().create();
diff --git 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
index fe0ed59e5d..cd11da7ac6 100644
--- a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
+++ b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/Tokens.java
@@ -18,7 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.util;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Failure;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 
@@ -48,13 +47,6 @@ public final class Tokens {
      */
     public static final String ARGS_BINDINGS = "bindings";
 
-    /**
-     * @Deprecated
-     */
-    public static final String ARGS_ALIASES = "aliases";
-
-    public static final String ARGS_FORCE = "force";
-
     /**
      * Argument name that allows definition of alias names for {@link Graph} 
and {@link TraversalSource} objects on
      * the remote system.
@@ -107,30 +99,4 @@ public final class Tokens {
     public static final String ARGS_USER_AGENT = "userAgent";
 
     public static final String VAL_TRAVERSAL_SOURCE_ALIAS = "g";
-
-    /**
-     * Refers to the hierarchy of exception names for a particular exception 
thrown on the server.
-     */
-    public static final String STATUS_ATTRIBUTE_EXCEPTIONS = "exceptions";
-
-    /**
-     * Refers to the stacktrace for an exception thrown on the server
-     */
-    public static final String STATUS_ATTRIBUTE_STACK_TRACE = "stackTrace";
-
-    /**
-     * A {@link ResultSet#statusAttributes()} key for user-facing warnings.
-     * <p>
-     * Implementations that set this key should consider using one of
-     * these two recommended value types:
-     * <ul>
-     *     <li>A {@code List} implementation containing
-     *     references for which {@code String#valueOf(Object)} produces
-     *     a meaningful return value.  For example, a list of strings.</li>
-     *     <li>Otherwise, any single non-list object for which
-     *     {@code String#valueOf(Object)} produces a meaningful return value.
-     *     For example, a string.</li>
-     * </ul>
-     */
-    public static final String STATUS_ATTRIBUTE_WARNINGS = "warnings";
 }

Reply via email to