You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by rd...@apache.org on 2018/08/17 19:48:17 UTC

[12/16] tinkerpop git commit: TINKERPOP-2023 new SSL client, server parameters

TINKERPOP-2023 new SSL client, server parameters


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

Branch: refs/heads/TINKERPOP-2023
Commit: e3b4ae5d848d641d6dbdbfa940acab470c64fabb
Parents: 5f770b1
Author: Robert Dale <ro...@gmail.com>
Authored: Sat Aug 11 21:12:50 2018 -0400
Committer: Robert Dale <ro...@gmail.com>
Committed: Fri Aug 17 15:06:33 2018 -0400

----------------------------------------------------------------------
 gremlin-console/conf/remote-secure.yaml         |   5 +-
 .../tinkerpop/gremlin/driver/Cluster.java       | 172 ++++++++++++++++++-
 .../tinkerpop/gremlin/driver/Settings.java      |  57 ++++++
 .../conf/gremlin-server-rest-secure.yaml        |   6 +-
 gremlin-server/conf/gremlin-server-secure.yaml  |   6 +-
 .../gremlin/server/AbstractChannelizer.java     |  78 +++++++--
 .../tinkerpop/gremlin/server/Settings.java      |  64 ++++++-
 .../AbstractGremlinServerIntegrationTest.java   |   7 +
 .../server/GremlinServerAuthIntegrateTest.java  |   4 +-
 .../GremlinServerAuthOldIntegrateTest.java      |   4 +-
 .../server/GremlinServerIntegrateTest.java      |  41 ++---
 ...ctGremlinServerChannelizerIntegrateTest.java |  10 +-
 gremlin-server/src/test/resources/server.jks    | Bin 0 -> 2258 bytes
 gremlin-server/src/test/resources/server.p12    | Bin 0 -> 2613 bytes
 14 files changed, 396 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-console/conf/remote-secure.yaml
----------------------------------------------------------------------
diff --git a/gremlin-console/conf/remote-secure.yaml b/gremlin-console/conf/remote-secure.yaml
index 4f8d22b..c7a2c44 100644
--- a/gremlin-console/conf/remote-secure.yaml
+++ b/gremlin-console/conf/remote-secure.yaml
@@ -29,5 +29,6 @@ port: 8182
 username: stephen
 password: password
 connectionPool: {
-  enableSsl: true}
-serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}
\ No newline at end of file
+  enableSsl: true,
+  sslSkipCertValidation: true }
+serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
----------------------------------------------------------------------
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 567bfb4..6e4ef25 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
@@ -33,15 +33,25 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -172,6 +182,14 @@ public final class Cluster {
                 .keyCertChainFile(settings.connectionPool.keyCertChainFile)
                 .keyFile(settings.connectionPool.keyFile)
                 .keyPassword(settings.connectionPool.keyPassword)
+                .keyStore(settings.connectionPool.keyStore)
+                .keyStorePassword(settings.connectionPool.keyStorePassword)
+                .keyStoreType(settings.connectionPool.keyStoreType)
+                .trustStore(settings.connectionPool.trustStore)
+                .trustStorePassword(settings.connectionPool.trustStorePassword)
+                .sslCipherSuites(settings.connectionPool.sslCipherSuites)
+                .sslEnabledProtocols(settings.connectionPool.sslEnabledProtocols)
+                .sslSkipCertValidation(settings.connectionPool.sslSkipCertValidation)
                 .nioPoolSize(settings.nioPoolSize)
                 .workerPoolSize(settings.workerPoolSize)
                 .reconnectInterval(settings.connectionPool.reconnectInterval)
@@ -446,29 +464,81 @@ public final class Cluster {
         return manager.authProps;
     }
 
-    SslContext createSSLContext() throws Exception  {
+    SslContext createSSLContext() throws Exception {
         // if the context is provided then just use that and ignore the other settings
-        if (manager.sslContextOptional.isPresent()) return manager.sslContextOptional.get();
+        if (manager.sslContextOptional.isPresent())
+            return manager.sslContextOptional.get();
 
         final SslProvider provider = SslProvider.JDK;
         final Settings.ConnectionPoolSettings connectionPoolSettings = connectionPoolSettings();
         final SslContextBuilder builder = SslContextBuilder.forClient();
 
-        if (connectionPoolSettings.trustCertChainFile != null)
+        if (connectionPoolSettings.trustCertChainFile != null) {
+            logger.warn("Using deprecated SSL trustCertChainFile support");
             builder.trustManager(new File(connectionPoolSettings.trustCertChainFile));
-        else {
-            logger.warn("SSL configured without a trustCertChainFile and thus trusts all certificates without verification (not suitable for production)");
-            builder.trustManager(InsecureTrustManagerFactory.INSTANCE);
         }
 
         if (null != connectionPoolSettings.keyCertChainFile && null != connectionPoolSettings.keyFile) {
+            logger.warn("Using deprecated SSL keyFile support");
             final File keyCertChainFile = new File(connectionPoolSettings.keyCertChainFile);
             final File keyFile = new File(connectionPoolSettings.keyFile);
 
-            // note that keyPassword may be null here if the keyFile is not password-protected.
+            // note that keyPassword may be null here if the keyFile is not
+            // password-protected.
             builder.keyManager(keyCertChainFile, keyFile, connectionPoolSettings.keyPassword);
         }
 
+        // Build JSSE SSLContext
+        try {
+
+            // Load private key/public cert for client auth
+            if (null != connectionPoolSettings.keyStore) {
+                final String keyStoreType = null == connectionPoolSettings.keyStoreType ? KeyStore.getDefaultType()
+                        : connectionPoolSettings.keyStoreType;
+                final KeyStore keystore = KeyStore.getInstance(keyStoreType);
+                final char[] password = null == connectionPoolSettings.keyStorePassword ? null
+                        : connectionPoolSettings.keyStorePassword.toCharArray();
+                try (final InputStream in = new FileInputStream(connectionPoolSettings.keyStore)) {
+                    keystore.load(in, password);
+                }
+                final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+                kmf.init(keystore, password);
+                builder.keyManager(kmf);
+            }
+
+            // Load custom truststore
+            if (null != connectionPoolSettings.trustStore) {
+                final String keystoreType = null == connectionPoolSettings.keyStoreType ? KeyStore.getDefaultType()
+                        : connectionPoolSettings.keyStoreType;
+                final KeyStore truststore = KeyStore.getInstance(keystoreType);
+                final char[] password = null == connectionPoolSettings.trustStorePassword ? null
+                        : connectionPoolSettings.trustStorePassword.toCharArray();
+                try (final InputStream in = new FileInputStream(connectionPoolSettings.trustStore)) {
+                    truststore.load(in, password);
+                }
+                final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                tmf.init(truststore);
+                builder.trustManager(tmf);
+            }
+
+        } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) {
+            logger.error("There was an error enabling SSL.", e);
+            return null;
+        }
+
+        if (null != connectionPoolSettings.sslCipherSuites && !connectionPoolSettings.sslCipherSuites.isEmpty()) {
+            builder.ciphers(connectionPoolSettings.sslCipherSuites);
+        }
+
+        if (null != connectionPoolSettings.sslEnabledProtocols && !connectionPoolSettings.sslEnabledProtocols.isEmpty()) {
+            builder.protocols(connectionPoolSettings.sslEnabledProtocols.toArray(new String[] {}));
+        }
+
+        if (connectionPoolSettings.sslSkipCertValidation) {
+            logger.warn("SSL configured with sslSkipCertValidation thus trusts all certificates without verification (not suitable for production)");
+            builder.trustManager(InsecureTrustManagerFactory.INSTANCE);
+        }
+
         builder.sslProvider(provider);
 
         return builder.build();
@@ -499,6 +569,14 @@ public final class Cluster {
         private String keyCertChainFile = null;
         private String keyFile = null;
         private String keyPassword = null;
+        private String keyStore;
+        private String keyStorePassword;
+        private String trustStore;
+        private String trustStorePassword;
+        private String keyStoreType;
+        private List<String> sslEnabledProtocols = new ArrayList<>();
+        private List<String> sslCipherSuites = new ArrayList<>();
+        private boolean sslSkipCertValidation = false;
         private SslContext sslContext = null;
         private LoadBalancingStrategy loadBalancingStrategy = new LoadBalancingStrategy.RoundRobin();
         private AuthProperties authProps = new AuthProperties();
@@ -579,7 +657,9 @@ public final class Cluster {
          * File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and
          * SSL is enabled, the {@link TrustManager} will be established with a self-signed certificate which is NOT
          * suitable for production purposes.
+         * @deprecated
          */
+        @Deprecated
         public Builder trustCertificateChainFile(final String certificateChainFile) {
             this.trustCertChainFile = certificateChainFile;
             return this;
@@ -597,7 +677,9 @@ public final class Cluster {
 
         /**
          * The X.509 certificate chain file in PEM format.
+         * @deprecated
          */
+        @Deprecated
         public Builder keyCertChainFile(final String keyCertChainFile) {
             this.keyCertChainFile = keyCertChainFile;
             return this;
@@ -605,7 +687,9 @@ public final class Cluster {
 
         /**
          * The PKCS#8 private key file in PEM format.
+         * @deprecated
          */
+        @Deprecated
         public Builder keyFile(final String keyFile) {
             this.keyFile = keyFile;
             return this;
@@ -613,11 +697,77 @@ public final class Cluster {
 
         /**
          * The password of the {@link #keyFile}, or {@code null} if it's not password-protected.
+         * @deprecated
          */
+        @Deprecated
         public Builder keyPassword(final String keyPassword) {
             this.keyPassword = keyPassword;
             return this;
         }
+        
+        /**
+         * 
+         */
+        public Builder keyStore(final String keyStore) {
+            this.keyStore = keyStore;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder keyStorePassword(final String keyStorePassword) {
+            this.keyStorePassword = keyStorePassword;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder trustStore(final String trustStore) {
+            this.trustStore = trustStore;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder trustStorePassword(final String trustStorePassword) {
+            this.trustStorePassword = trustStorePassword;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder keyStoreType(final String keyStoreType) {
+            this.keyStoreType = keyStoreType;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder sslEnabledProtocols(final List<String> sslEnabledProtocols) {
+            this.sslEnabledProtocols = sslEnabledProtocols;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder sslCipherSuites(final List<String> sslCipherSuites) {
+            this.sslCipherSuites = sslCipherSuites;
+            return this;
+        }
+        
+        /**
+         * 
+         */
+        public Builder sslSkipCertValidation(final boolean sslSkipCertValidation) {
+            this.sslSkipCertValidation = sslSkipCertValidation;
+            return this;
+        }
 
         /**
          * The minimum number of in-flight requests that can occur on a {@link Connection} before it is considered
@@ -901,6 +1051,14 @@ public final class Cluster {
             connectionPoolSettings.keyCertChainFile = builder.keyCertChainFile;
             connectionPoolSettings.keyFile = builder.keyFile;
             connectionPoolSettings.keyPassword = builder.keyPassword;
+            connectionPoolSettings.keyStore = builder.keyStore;
+            connectionPoolSettings.keyStorePassword = builder.keyStorePassword;
+            connectionPoolSettings.trustStore = builder.trustStore;
+            connectionPoolSettings.trustStorePassword = builder.trustStorePassword;
+            connectionPoolSettings.keyStoreType = builder.keyStoreType;
+            connectionPoolSettings.sslCipherSuites = builder.sslCipherSuites;
+            connectionPoolSettings.sslEnabledProtocols = builder.sslEnabledProtocols;
+            connectionPoolSettings.sslSkipCertValidation = builder.sslSkipCertValidation;
             connectionPoolSettings.keepAliveInterval = builder.keepAliveInterval;
             connectionPoolSettings.channelizer = builder.channelizer;
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
index 8a2517d..009a0bf 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Settings.java
@@ -232,25 +232,82 @@ final class Settings {
 
         /**
          * The trusted certificate in PEM format.
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String trustCertChainFile = null;
 
         /**
          * The X.509 certificate chain file in PEM format.
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String keyCertChainFile = null;
 
         /**
          * The PKCS#8 private key file in PEM format.
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String keyFile = null;
 
         /**
          * The password of the {@link #keyFile}, or {@code null} if it's not password-protected.
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String keyPassword = null;
 
         /**
+         * JSSE keystore file path. Similar to setting JSSE property
+         * {@code javax.net.ssl.keyStore}.
+         */
+        public String keyStore;
+
+        /**
+         * JSSE keystore password. Similar to setting JSSE property
+         * {@code javax.net.ssl.keyStorePassword}.
+         */
+        public String keyStorePassword;
+
+        /**
+         * JSSE truststore file path. Similar to setting JSSE property
+         * {@code javax.net.ssl.trustStore}.
+         */
+        public String trustStore;
+
+        /**
+         * JSSE truststore password. Similar to setting JSSE property
+         * {@code javax.net.ssl.trustStorePassword}.
+         */
+        public String trustStorePassword;
+
+        /**
+         * JSSE keystore format. Similar to setting JSSE property
+         * {@code javax.net.ssl.keyStoreType}.
+         */
+        public String keyStoreType;
+
+        /**
+         * @see <a href=
+         *      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJSSE_Protocols">JSSE
+         *      Protocols</a>
+         */
+        public List<String> sslEnabledProtocols = new ArrayList<>();
+
+        /**
+         * @see <a href=
+         *      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SupportedCipherSuites">Cipher
+         *      Suites</a>
+         */
+        public List<String> sslCipherSuites = new ArrayList<>();
+
+        /**
+         * 
+         */
+        public boolean sslSkipCertValidation = false;
+
+        /**
          * The minimum size of a connection pool for a {@link Host}. By default this is set to 2.
          */
         public int minSize = ConnectionPool.MIN_POOL_SIZE;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/conf/gremlin-server-rest-secure.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-rest-secure.yaml b/gremlin-server/conf/gremlin-server-rest-secure.yaml
index ab21b33..fcfbba1 100644
--- a/gremlin-server/conf/gremlin-server-rest-secure.yaml
+++ b/gremlin-server/conf/gremlin-server-rest-secure.yaml
@@ -69,4 +69,8 @@ authentication: {
   config: {
     credentialsDb: conf/tinkergraph-credentials.properties}}
 ssl: {
-  enabled: true}
+  enabled: true,
+  # You must configure a keyStore!
+  #keyStore: server.jks,
+  #keyStorePassword: changeit
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/conf/gremlin-server-secure.yaml
----------------------------------------------------------------------
diff --git a/gremlin-server/conf/gremlin-server-secure.yaml b/gremlin-server/conf/gremlin-server-secure.yaml
index 42a7785..af46c59 100644
--- a/gremlin-server/conf/gremlin-server-secure.yaml
+++ b/gremlin-server/conf/gremlin-server-secure.yaml
@@ -73,4 +73,8 @@ authentication: {
   config: {
     credentialsDb: conf/tinkergraph-credentials.properties}}
 ssl: {
-  enabled: true}
+  enabled: true,
+  # You must configure a keyStore!
+  #keyStore: server.jks,
+  #keyStorePassword: changeit
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
index edea752..2a29fec 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
@@ -22,7 +22,6 @@ import io.netty.channel.EventLoopGroup;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.SslProvider;
-import io.netty.handler.ssl.util.SelfSignedCertificate;
 import io.netty.handler.timeout.IdleStateHandler;
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
 import org.apache.tinkerpop.gremlin.driver.ser.AbstractGryoMessageSerializerV1d0;
@@ -43,8 +42,18 @@ import org.javatuples.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLException;
+import javax.net.ssl.TrustManagerFactory;
+
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.util.Arrays;
 import java.util.Collections;
@@ -258,7 +267,7 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
         }
     }
 
-    private SslContext createSSLContext(final Settings settings)  {
+    private SslContext createSSLContext(final Settings settings) {
         final Settings.SslSettings sslSettings = settings.ssl;
 
         if (sslSettings.getSslContext().isPresent()) {
@@ -270,25 +279,62 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
 
         final SslContextBuilder builder;
 
-        // if the config doesn't contain a cert or key then use a self signed cert - not suitable for production
-        if (null == sslSettings.keyCertChainFile || null == sslSettings.keyFile) {
-            try {
-                logger.warn("Enabling SSL with self-signed certificate (NOT SUITABLE FOR PRODUCTION)");
-                final SelfSignedCertificate ssc = new SelfSignedCertificate();
-                builder = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
-            } catch (CertificateException ce) {
-                logger.error("There was an error creating the self-signed certificate for SSL - SSL is not enabled", ce);
-                return null;
-            }
-        } else {
+        // DEPRECATED: If the config has the required, deprecated settings, then use it
+        if (null != sslSettings.keyCertChainFile && null != sslSettings.keyFile) {
+            logger.warn("Using deprecated SSL keyFile support");
             final File keyCertChainFile = new File(sslSettings.keyCertChainFile);
             final File keyFile = new File(sslSettings.keyFile);
             final File trustCertChainFile = null == sslSettings.trustCertChainFile ? null : new File(sslSettings.trustCertChainFile);
 
-            // note that keyPassword may be null here if the keyFile is not password-protected. passing null to
+            // note that keyPassword may be null here if the keyFile is not
+            // password-protected. passing null to
             // trustManager is also ok (default will be used)
-            builder = SslContextBuilder.forServer(keyCertChainFile, keyFile, sslSettings.keyPassword)
-                    .trustManager(trustCertChainFile);
+            builder = SslContextBuilder.forServer(keyCertChainFile, keyFile, sslSettings.keyPassword).trustManager(trustCertChainFile);
+        } else {
+
+            // Build JSSE SSLContext
+            try {
+                final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+
+                // Load private key and signed cert
+                if (null != sslSettings.keyStore) {
+                    final String keyStoreType = null == sslSettings.keyStoreType ? KeyStore.getDefaultType() : sslSettings.keyStoreType;
+                    final KeyStore keystore = KeyStore.getInstance(keyStoreType);
+                    final char[] password = null == sslSettings.keyStorePassword ? null : sslSettings.keyStorePassword.toCharArray();
+                    try (final InputStream in = new FileInputStream(sslSettings.keyStore)) {
+                        keystore.load(in, password);
+                    }
+                    kmf.init(keystore, password);
+                }
+
+                builder = SslContextBuilder.forServer(kmf);
+
+                // Load custom truststore for client auth certs
+                if (null != sslSettings.trustStore) {
+                    final String keystoreType = null == sslSettings.keyStoreType ? KeyStore.getDefaultType() : sslSettings.keyStoreType;
+                    final KeyStore truststore = KeyStore.getInstance(keystoreType);
+                    final char[] password = null == sslSettings.trustStorePassword ? null : sslSettings.trustStorePassword.toCharArray();
+                    try (final InputStream in = new FileInputStream(sslSettings.trustStore)) {
+                        truststore.load(in, password);
+                    }
+                    final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+                    tmf.init(truststore);
+                    builder.trustManager(tmf);
+                }
+
+            } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) {
+                logger.error("There was an error enabling SSL.", e);
+                return null;
+            }
+
+        }
+
+        if (null != sslSettings.sslCipherSuites && !sslSettings.sslCipherSuites.isEmpty()) {
+            builder.ciphers(sslSettings.sslCipherSuites);
+        }
+
+        if (null != sslSettings.sslEnabledProtocols && !sslSettings.sslEnabledProtocols.isEmpty()) {
+            builder.protocols(sslSettings.sslEnabledProtocols.toArray(new String[] {}));
         }
 
         builder.clientAuth(sslSettings.needClientAuth).sslProvider(provider);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
index 74a5a1a..c918f8b 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
@@ -450,34 +450,86 @@ public class Settings {
      */
     public static class SslSettings {
         /**
-         * Enables SSL.  Other settings will be ignored unless this is set to true. By default a self-signed
-         * certificate is used (not suitable for production) for SSL.  To override this setting, be sure to set
-         * the {@link #keyCertChainFile} and the {@link #keyFile}.
+         * Enables SSL. Other SSL settings will be ignored unless this is set to true.
          */
         public boolean enabled = false;
 
         /**
          * The X.509 certificate chain file in PEM format.
+         * 
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String keyCertChainFile = null;
 
         /**
          * The PKCS#8 private key file in PEM format.
+         * 
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String keyFile = null;
 
         /**
-         * The password of the {@link #keyFile}, or {@code null} if it's not password-protected.
+         * The password of the {@link #keyFile}, or {@code null} if it's not
+         * password-protected.
+         * 
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String keyPassword = null;
 
         /**
-         * Trusted certificates for verifying the remote endpoint's certificate. The file should
-         * contain an X.509 certificate chain in PEM format. {@code null} uses the system default.
+         * Trusted certificates for verifying the remote endpoint's certificate. The
+         * file should contain an X.509 certificate chain in PEM format. {@code null}
+         * uses the system default.
+         * 
+         * @deprecated Use JSSE-based settings
          */
+        @Deprecated
         public String trustCertChainFile = null;
 
         /**
+         * JSSE keystore file path. Similar to setting JSSE property
+         * {@code javax.net.ssl.keyStore}.
+         */
+        public String keyStore;
+
+        /**
+         * JSSE keystore password. Similar to setting JSSE property
+         * {@code javax.net.ssl.keyStorePassword}.
+         */
+        public String keyStorePassword;
+
+        /**
+         * JSSE truststore file path. Similar to setting JSSE property
+         * {@code javax.net.ssl.trustStore}.
+         */
+        public String trustStore;
+
+        /**
+         * JSSE truststore password. Similar to setting JSSE property
+         * {@code javax.net.ssl.trustStorePassword}.
+         */
+        public String trustStorePassword;
+
+        /**
+         * JSSE keystore format. Similar to setting JSSE property
+         * {@code javax.net.ssl.keyStoreType}.
+         */
+        public String keyStoreType;
+
+        /**
+         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJSSE_Protocols">JSSE Protocols</a>
+         */
+        public List<String> sslEnabledProtocols = new ArrayList<>();
+
+        /**
+         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SupportedCipherSuites">Cipher Suites</a>
+         */
+        public List<String> sslCipherSuites = new ArrayList<>();
+
+        /**
          * Require client certificate authentication
          */
         public ClientAuth needClientAuth = ClientAuth.NONE;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
index f11a045..0543a59 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/AbstractGremlinServerIntegrationTest.java
@@ -38,6 +38,13 @@ import static org.junit.Assume.assumeThat;
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public abstract class AbstractGremlinServerIntegrationTest {
+    
+    public static final String KEY_PASS = "changeit";
+    public static final String JKS_SERVER_KEY = "src/test/resources/server.jks";
+    public static final String JKS_CLIENT_KEY = "src/test/resources/client.jks";
+    public static final String P12_SERVER_KEY = "src/test/resources/server.p12";
+    public static final String P12_CLIENT_KEY = "src/test/resources/client.p12";
+
     protected GremlinServer server;
     private Settings overriddenSettings;
     private final static String epollOption = "gremlin.server.epoll";

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
index e06bbb7..b4d979a 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
@@ -66,6 +66,8 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
             case "shouldFailIfSslEnabledOnServerButNotClient":
                 final Settings.SslSettings sslConfig = new Settings.SslSettings();
                 sslConfig.enabled = true;
+                sslConfig.keyStore = JKS_SERVER_KEY;
+                sslConfig.keyStorePassword = KEY_PASS;
                 settings.ssl = sslConfig;
                 break;
         }
@@ -107,7 +109,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
     @Test
     public void shouldAuthenticateOverSslWithPlainText() throws Exception {
         final Cluster cluster = TestClientFactory.build()
-                .enableSsl(true)
+                .enableSsl(true).sslSkipCertValidation(true)
                 .credentials("stephen", "password").create();
         final Client client = cluster.connect();
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
index b26dd1e..10755f1 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
@@ -69,6 +69,8 @@ public class GremlinServerAuthOldIntegrateTest extends AbstractGremlinServerInte
             case "shouldFailIfSslEnabledOnServerButNotClient":
                 final Settings.SslSettings sslConfig = new Settings.SslSettings();
                 sslConfig.enabled = true;
+                sslConfig.keyStore = JKS_SERVER_KEY;
+                sslConfig.keyStorePassword = KEY_PASS;
                 settings.ssl = sslConfig;
                 break;
         }
@@ -110,7 +112,7 @@ public class GremlinServerAuthOldIntegrateTest extends AbstractGremlinServerInte
     @Test
     public void shouldAuthenticateOverSslWithPlainText() throws Exception {
         final Cluster cluster = TestClientFactory.build()
-                .enableSsl(true)
+                .enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS).sslSkipCertValidation(true)
                 .credentials("stephen", "password").create();
         final Client client = cluster.connect();
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index eb5def9..238d2b2 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -110,11 +110,10 @@ import static org.junit.Assert.assertEquals;
  */
 public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegrationTest {
 
-    private static final String SERVER_KEY = "src/test/resources/server.key.pk8";
-    private static final String SERVER_CRT = "src/test/resources/server.crt";
-    private static final String KEY_PASS = "changeit";
-    private static final String CLIENT_KEY = "src/test/resources/client.key.pk8";
-    private static final String CLIENT_CRT = "src/test/resources/client.crt";
+    private static final String PEM_SERVER_KEY = "src/test/resources/server.key.pk8";
+    private static final String PEM_SERVER_CRT = "src/test/resources/server.crt";
+    private static final String PEM_CLIENT_KEY = "src/test/resources/client.key.pk8";
+    private static final String PEM_CLIENT_CRT = "src/test/resources/client.crt";
     private Level previousLogLevel;
 
     private Log4jRecordingAppender recordingAppender = null;
@@ -194,6 +193,8 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
             case "shouldEnableSslButFailIfClientConnectsWithoutIt":
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
+                settings.ssl.keyStore = JKS_SERVER_KEY;
+                settings.ssl.keyStorePassword = KEY_PASS;
                 break;
             case "shouldEnableSslWithSslContextProgrammaticallySpecified":
                 settings.ssl = new Settings.SslSettings();
@@ -204,31 +205,31 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
                 settings.ssl.needClientAuth = ClientAuth.REQUIRE;
-                settings.ssl.keyCertChainFile = SERVER_CRT;
-                settings.ssl.keyFile = SERVER_KEY;
+                settings.ssl.keyCertChainFile = PEM_SERVER_CRT;
+                settings.ssl.keyFile = PEM_SERVER_KEY;
                 settings.ssl.keyPassword =KEY_PASS;
                 // Trust the client
-                settings.ssl.trustCertChainFile = CLIENT_CRT;
+                settings.ssl.trustCertChainFile = PEM_CLIENT_CRT;
             	break;
             case "shouldEnableSslAndClientCertificateAuthAndFailWithoutCert":
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
                 settings.ssl.needClientAuth = ClientAuth.REQUIRE;
-                settings.ssl.keyCertChainFile = SERVER_CRT;
-                settings.ssl.keyFile = SERVER_KEY;
+                settings.ssl.keyCertChainFile = PEM_SERVER_CRT;
+                settings.ssl.keyFile = PEM_SERVER_KEY;
                 settings.ssl.keyPassword =KEY_PASS;
                 // Trust the client
-                settings.ssl.trustCertChainFile = CLIENT_CRT;
+                settings.ssl.trustCertChainFile = PEM_CLIENT_CRT;
             	break;
             case "shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCert":
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
                 settings.ssl.needClientAuth = ClientAuth.REQUIRE;
-                settings.ssl.keyCertChainFile = SERVER_CRT;
-                settings.ssl.keyFile = SERVER_KEY;
+                settings.ssl.keyCertChainFile = PEM_SERVER_CRT;
+                settings.ssl.keyFile = PEM_SERVER_KEY;
                 settings.ssl.keyPassword =KEY_PASS;
                 // Trust ONLY the server cert
-                settings.ssl.trustCertChainFile = SERVER_CRT;
+                settings.ssl.trustCertChainFile = PEM_SERVER_CRT;
             	break;
             case "shouldUseSimpleSandbox":
                 settings.scriptEngines.get("gremlin-groovy").config = getScriptEngineConfForSimpleSandbox();
@@ -485,7 +486,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
 
     @Test
     public void shouldEnableSsl() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true).create();
+        final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS).sslSkipCertValidation(true).create();
         final Client client = cluster.connect();
 
         try {
@@ -533,8 +534,8 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
     @Test
     public void shouldEnableSslAndClientCertificateAuth() {
 		final Cluster cluster = TestClientFactory.build().enableSsl(true)
-				.keyCertChainFile(CLIENT_CRT).keyFile(CLIENT_KEY)
-				.keyPassword(KEY_PASS).trustCertificateChainFile(SERVER_CRT).create();
+				.keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY)
+				.keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create();
 		final Client client = cluster.connect();
 
         try {
@@ -546,7 +547,7 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
 
     @Test
     public void shouldEnableSslAndClientCertificateAuthAndFailWithoutCert() {
-        final Cluster cluster = TestClientFactory.build().enableSsl(true).create();
+        final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS).sslSkipCertValidation(true).create();
         final Client client = cluster.connect();
 
         try {
@@ -563,8 +564,8 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
     @Test
     public void shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCert() {
 		final Cluster cluster = TestClientFactory.build().enableSsl(true)
-				.keyCertChainFile(CLIENT_CRT).keyFile(CLIENT_KEY)
-				.keyPassword(KEY_PASS).trustCertificateChainFile(SERVER_CRT).create();
+				.keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY)
+				.keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create();
 		final Client client = cluster.connect();
 
         try {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
index 738ca89..300a7f4 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/channel/AbstractGremlinServerChannelizerIntegrateTest.java
@@ -100,6 +100,8 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre
             case "shouldWorkWithSSL":
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
+                settings.ssl.keyStore = JKS_SERVER_KEY;
+                settings.ssl.keyStorePassword = KEY_PASS;
                 break;
             case "shouldWorkWithAuth":
                 if (authSettings != null) {
@@ -109,6 +111,8 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre
             case "shouldWorkWithSSLAndAuth":
                 settings.ssl = new Settings.SslSettings();
                 settings.ssl.enabled = true;
+                settings.ssl.keyStore = JKS_SERVER_KEY;
+                settings.ssl.keyStorePassword = KEY_PASS;
                 if (authSettings != null) {
                     settings.authentication = getAuthSettings();
                 }
@@ -304,7 +308,7 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre
                                                 .with(Property.USERNAME, username)
                                                 .with(Property.PASSWORD, password);
 
-                nioCluster = nioBuilder.enableSsl(secure).authProperties(authProps).create();
+                nioCluster = nioBuilder.enableSsl(secure).sslSkipCertValidation(true).authProperties(authProps).create();
                 nioClient = nioCluster.connect();
             } else {
                 nioCluster = nioBuilder.enableSsl(secure).create();
@@ -318,10 +322,10 @@ abstract class AbstractGremlinServerChannelizerIntegrateTest extends AbstractGre
                                                 .with(Property.USERNAME, username)
                                                 .with(Property.PASSWORD, password);
 
-                wsCluster = wsBuilder.enableSsl(secure).authProperties(authProps).create();
+                wsCluster = wsBuilder.enableSsl(secure).sslSkipCertValidation(true).authProperties(authProps).create();
                 wsClient = wsCluster.connect();
             } else {
-                wsCluster = wsBuilder.enableSsl(secure).create();
+                wsCluster = wsBuilder.enableSsl(secure).sslSkipCertValidation(true).create();
                 wsClient = wsCluster.connect();
             }
         }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/resources/server.jks
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/resources/server.jks b/gremlin-server/src/test/resources/server.jks
new file mode 100644
index 0000000..85dbe67
Binary files /dev/null and b/gremlin-server/src/test/resources/server.jks differ

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e3b4ae5d/gremlin-server/src/test/resources/server.p12
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/resources/server.p12 b/gremlin-server/src/test/resources/server.p12
new file mode 100644
index 0000000..4d1aad7
Binary files /dev/null and b/gremlin-server/src/test/resources/server.p12 differ