Repository: tinkerpop Updated Branches: refs/heads/TINKERPOP-2023 e0176c2e5 -> 29daf30d3 (forced update)
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/29daf30d Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/29daf30d Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/29daf30d Branch: refs/heads/TINKERPOP-2023 Commit: 29daf30d3ae1eeba23a4e8a74bbf88128f21e1f3 Parents: 1b99323 Author: Robert Dale <robd...@gmail.com> Authored: Sat Aug 11 21:12:50 2018 -0400 Committer: Robert Dale <robd...@gmail.com> Committed: Sun Aug 12 05:30:00 2018 -0400 ---------------------------------------------------------------------- gremlin-console/conf/remote-secure.yaml | 5 +- .../tinkerpop/gremlin/driver/Cluster.java | 172 ++++++++++++++++++- .../tinkerpop/gremlin/driver/Settings.java | 57 ++++++ .../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 12 files changed, 386 insertions(+), 56 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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/29daf30d/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