From e3b4ae5d848d641d6dbdbfa940acab470c64fabb Mon Sep 17 00:00:00 2001 From: Robert Dale Date: Sat, 11 Aug 2018 21:12:50 -0400 Subject: [PATCH 1/7] TINKERPOP-2023 new SSL client, server parameters --- 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 +- .../conf/gremlin-server-secure.yaml | 6 +- .../gremlin/server/AbstractChannelizer.java | 78 ++++++-- .../tinkerpop/gremlin/server/Settings.java | 64 ++++++- .../AbstractGremlinServerIntegrationTest.java | 7 + .../GremlinServerAuthIntegrateTest.java | 4 +- .../GremlinServerAuthOldIntegrateTest.java | 4 +- .../server/GremlinServerIntegrateTest.java | 41 +++-- ...GremlinServerChannelizerIntegrateTest.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(-) create mode 100644 gremlin-server/src/test/resources/server.jks create mode 100644 gremlin-server/src/test/resources/server.p12 diff --git a/gremlin-console/conf/remote-secure.yaml b/gremlin-console/conf/remote-secure.yaml index 4f8d22bd73a..c7a2c441075 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 }} 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 567bfb4b39d..6e4ef25d67f 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.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 @@ private static Builder getBuilderFromSettings(final Settings settings) { .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 @@ AuthProperties authProperties() { 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 static class Builder { 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 sslEnabledProtocols = new ArrayList<>(); + private List 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 Builder sslContext(final SslContext sslContext) { * 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 Builder keepAliveInterval(final long keepAliveInterval) { /** * 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 Builder keyCertChainFile(final String keyCertChainFile) { /** * 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 Builder keyFile(final String keyFile) { /** * 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 sslEnabledProtocols) { + this.sslEnabledProtocols = sslEnabledProtocols; + return this; + } + + /** + * + */ + public Builder sslCipherSuites(final List 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 @@ private Manager(final Builder builder) { 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; 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 8a2517d4490..009a0bfc662 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,24 +232,81 @@ static class ConnectionPoolSettings { /** * 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 JSSE + * Protocols + */ + public List sslEnabledProtocols = new ArrayList<>(); + + /** + * @see Cipher + * Suites + */ + public List 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. */ diff --git a/gremlin-server/conf/gremlin-server-rest-secure.yaml b/gremlin-server/conf/gremlin-server-rest-secure.yaml index ab21b339936..fcfbba1b699 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 +} diff --git a/gremlin-server/conf/gremlin-server-secure.yaml b/gremlin-server/conf/gremlin-server-secure.yaml index 42a77852313..af46c596b7b 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 +} 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 edea752776d..2a29fec4144 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.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.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 @@ private void configureSerializers() { } } - 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 @@ private SslContext createSSLContext(final Settings settings) { 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); 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 74a5a1aceb0..c918f8b13ee 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,33 +450,85 @@ public static class AuthenticationSettings { */ 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 JSSE Protocols + */ + public List sslEnabledProtocols = new ArrayList<>(); + + /** + * @see Cipher Suites + */ + public List sslCipherSuites = new ArrayList<>(); + /** * Require client certificate authentication */ 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 f11a0450147..0543a593e3c 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 @@ * @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"; 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 e06bbb7d131..b4d979a0d32 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 Settings overrideSettings(final Settings settings) { 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 void shouldAuthenticateWithPlainText() throws Exception { @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(); 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 b26dd1e6c2d..10755f19927 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 Settings overrideSettings(final Settings settings) { 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 void shouldAuthenticateWithPlainText() throws Exception { @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(); 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 eb5def9db5a..238d2b2e50e 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 @@ */ 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 Settings overrideSettings(final Settings settings) { 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 Settings overrideSettings(final Settings settings) { 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 void shouldUseSimpleSandbox() throws Exception { @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 void shouldEnableSslButFailIfClientConnectsWithoutIt() { @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 void shouldEnableSslAndClientCertificateAuth() { @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 void shouldEnableSslAndClientCertificateAuthAndFailWithoutCert() { @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 { 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 738ca897a66..300a7f4c784 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 @@ public Settings overrideSettings(final Settings settings) { 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 @@ public Settings overrideSettings(final Settings settings) { 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 @@ private void setNioClient(final String username, final String password) { .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 @@ private void setWsClient(final String username, final String password) { .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(); } } diff --git a/gremlin-server/src/test/resources/server.jks b/gremlin-server/src/test/resources/server.jks new file mode 100644 index 0000000000000000000000000000000000000000..85dbe67f62a49af80224da9604e26a3f8024e8a2 GIT binary patch literal 2258 zcmc(g={wX77sqE6iO6KlGRnyQ8w_JDqJ%72in5F`gA6mMhDb~?#@g5lG0A#MqZB3C z8e14r$riFiS&}`8=h1yV&-L8@!Smw0IG^vEbA8XbzGr7)X8{BPL3RuLckz+PcpS-> z9CCS=5LAZiPJlpgFhGNC1A;tzRd~QKurfp#42FYXG}t%qAF+o1@k!h$!t}~tns;;%FYwrx5)iOf*Dw(uB{E^CGEqpr3xbWt@B! z{=^O@VcwO^;+>zs^^#`vSZhC7+qXLR-5Q3p+gw0ykmvSAV^^01iQf%O1G zzfNJ6*5s8Q6q8NrduXv>JhkX#KSaBgO*jo}r%%A$w z5L)`Vyb@K6KCk4=pXQ#YRI1&xppfS}Gs+$tXq!{34~*7RSb6_Dkjc?^?Wdh8N+h^n z5}Y83@(bg2*&X#aH=QWS`iSa{Uk(R9uwCdX)!CgQgKUZ zpLMgmSoCrbr9G}pJO`F;i^rYRE9Em_1+6)oSAA3=PD}Kd;PHZ6w8BMfPV&z>d+fxa zwD(0jiM~2EU^CUJ**zIbTc`@hm(OABvL2(6rlPuk8okXoixuJ{L={Y&Mn znV62Buq67!aDe-!HR{5z%{&{Y%S#!HeWHMSb`g8#@GBZ;=vc6MGw)z%R&PjTk%8TV zwr4Bqy7ym|)$tN9GW3JrrCRB3T9S$vVq>24r@9XFQRuW!nD@`jb~rqK#Z!lEQYRGI z)&~EQPl~4~3bVtgy%jo8T)JuG78KAukFu72z((3M!(YJ|0Y+W+vqoYiN7tfM3=R%d z>NYa`%Az~MTQ<~Eao0vRkC}EkTj6^|OMEOHX7_r-(4#Nvi8WKvp1soK#H)bC$>+4~ z!oaPD&K5T|X1(Or5W7Y5$KkKq^QtdIg4yRpeWnpZ)rO&d{UIjfzFe@^&BE(niI=D( zyMTZ=X9cO~iDkv`-$UP$+q3gA`_{C`i;*>K>L>3eRZp=KO{3KElCjuT3$#PX_jdW4 z`@B_EJ-?x<2W3!JGDG6cb<1hZO;s0im1Ndr#u*Wx%Or@Tb##u3#{%oji^$~02FIMgih>>%w z?_RCFDO#oJiAK^LJ_MN3(6{TWXHMV8 zq2{3MES4n5`*VHOfS z=Cs}lA7QDkB(0&#*CuLOcx)W>GQ8dhT2re+E*bN05;2O7nJCWYQz-E@!TIw7-jS(W zqtwR7FMQlQzEkC`4mi=U`E4b{HA);?rAw?hBDZa|#Q ze4Uw5ayv}1J>ua}#5~#Fkme$+laD}TQm@=8coufGuclyZ@#Ejw2tTim0rWs1C>@|d zZvr%k|9vO~41vJBJsH)201uyXtVQgG02s^<2LVB7et?e$>ICBvfjBw*x8W6moG?Kn zfCGP&JtF)LxWLOexf3K@Fb*vNi2b2^MTAT!IJ_@G&e1Q>pAc+Erl5s(!*^HW7ujkp_vDD1MV%=>>-#ZS~2FJ2-M^X~vx2qqCmdgAK0Q+HQP=USCSeoSM#!52k)r;?%Q3w)@JuxsNr)7&^otadpkCb5!Y{IsVyN zKC;}XP}EhAnjW-eNOr7<1UNJz7c<zS z6HjAng5n(Gng;|527wEZfGi-ryHIICm?#XvJ~Sc^qYGb@O${jL-AO94|H60SpC<0! z*RF|RkVMA#Xu>R!k#P=xR)2+dpsgStLy(2Rp0fhrP`Y?nBwLvH`|&c8Yz{HawGQleR-FhOzZ?=H0AS}Sm>bg?GA8Qii{}-1z=P(Y0w2Nqx$_)4eHi8~2)k Yu*c3*jS{?OP8yDOyGWsZ`X8}GadH?_b literal 0 HcmV?d00001 diff --git a/gremlin-server/src/test/resources/server.p12 b/gremlin-server/src/test/resources/server.p12 new file mode 100644 index 0000000000000000000000000000000000000000..4d1aad7ac7c342ee31764d24ca76268eafecd808 GIT binary patch literal 2613 zcmY+EcQ_l08pace*ct>iYqljt#B7?Q^cqEDQ)=%~M2*A_q1q~HlqxA{YgLO{<($?y zC~B*{_b3%5HsQMWx%b?A{`j8vd*1i^-amf`BC|Xl5QHEytwETi<8H_8vjG`^WFpf9 zn8-A8ZVw=c^w_^e^bTMmz0J98c|K+kmj8UQG6U(zMDQ_!2;N6XL74w*pO*`OVew|e zl*@*5_V4s{;@3nd2!8uhVLA|?*$7Mow=o9-|`n2kWJmsLh+T)C4J#X}I58|S6aT}{-hU0x1 zJwE5R%+vxEtkw;*?m@bbN;P5h6=`E|nc(*EE39YC7ZS^U-9zYEi|}A*=FfHk4gb8u zJF%ey0D8N zaqrX%sqV3Nsc)8~aWn6T zIiA}3Gca;b)o3$NHgrjU)lI>&{8|=$CxG$9KS+AfbX{w-Li7mg%Gl!Q(f!DU`cjJL ztCOm^5x==rBB7+N$PyDb>=EqH?i7r44Oxo;-S#S+wmDe(1#g#H`Fw48H6FFwASriv zLO-g6yZJaEv7I;D5ZbZjRR4b5-i#YEF^NI1G#+Q>7A57E#U%0#7;exa=q4yAKD|Z! zcJAKSh@TI{UN(`e3@n8rE^+skP12_3=9SQ`U3PlkgyGxhXo;A{ZzIm(edQHw`-XJY=;+fOeP3ePrv2Ds#iN3O%fkgAfa z?PU7YvT;^bq_7ghM9A-DsG!Vxv>P zn@O{A#CG`63EaCA|7ZG+wS{lEXl3-H#rrRI!VqfyxsS^q$fiG+=w95z{3^{xab{BuR&xh! zq6+WJg1TCySw-H7?P6CEaQnR9i>&TbStY&P2gA!kheZ0;46y3N+aXzWy5wn8ca$<^ z42FCw$<5#?RiYk+;MUcUkm`5dX9#f5cVU5Un7&tLGo_nldoGO2CZ*1k61-|?M?Wmr z3Q2eC^YjP$K+c}w){HbobSn*1yyH<-$(5^wXbbsts{6A@4Q_{B~hd~OO`;>T!yN@aN2L= zwGpC!p^^zE4-@7DcmuEiXMp3mdYo?ofWZGh;g*MiIn6wMTt(!S6ciB(*X5N}RFQ~t zgxdVo!vHy_D(2kMr2_)a<<|ca;NLh4`4?wD{1Ek=H<&3R34M9NCy}R3_EfU`H)o@W zV8%?CT%+c;J{5pB0V7fm8Hs#UR3;j*2hwgYCD=@q%$lN zVhb&aaxPrDF@uyMKROghcW)BETwkp@s%*3xVoF#tv5rdFudeXc&gZgENt&na%t=|h zNWk(NqFK3zUuVm`N~04fyWYiX%Fd@gW3nDedx?#k{$KQ5m4NY>0j=p%{xd}n1- zhBf;KF7hZQhV-sNHyVHmcb=^;N@S|jgpMrNoWKkc97nP~>Baj0L(*`e zz@oDb~;ooe% zq)mxfh)vFI?br_yl58Hu9+Xv7m4*$epLWc= z!>`_~{|@*S1=fvJ8+~+QX{)S*7yWiHyj|Zk=GC3&?0e{`{i?`=?xA&FDH?>!@m;wLC8HtLH()Ao z$@Ow$YoVOH2@m#3GKb7H?W@=Z)Oz{A1P?j0g!G0LH_7=$T3prf8<)Q=@TMLc5HF3d zkq1Qat$w;^Rgf6m13HmZf?KuHAq(NqupCI^3Pt$5W;J^iEBNo3GY@alE<77Y6wvT6NDbl z4x;0y2Y_L{(5voRPucbGljj5^B|wYQ)RACVD=>Vra{Ti$Rw<1Kebd3?gSbyN9S9gl F{wMg&*dhP` literal 0 HcmV?d00001 From ca83fbdfdc885a9774ba1dbc17b3d9df75c49137 Mon Sep 17 00:00:00 2001 From: Robert Dale Date: Sun, 12 Aug 2018 21:50:02 -0400 Subject: [PATCH 2/7] TINKERPOP-2023 default to TLSv1.2, updated upgrade notes --- CHANGELOG.asciidoc | 1 + .../upgrade/release-3.2.x-incubating.asciidoc | 25 +++++++++++++++++++ gremlin-console/conf/remote-secure.yaml | 2 +- .../conf/gremlin-server-rest-secure.yaml | 1 + .../conf/gremlin-server-secure.yaml | 1 + 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index eb1a6c5c68a..9dec8df7a25 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -23,6 +23,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima [[release-3-2-10]] === TinkerPop 3.2.10 (Release Date: NOT OFFICIALLY RELEASED YET) +* SSL security enhancements * Fixed problem with Gremlin Server sometimes returning an additional message after a failure. * Allowed spaces in classpath for `gremlin-server.bat`. * Modified Maven archetype for Gremlin Server to use remote traversals rather than scripts. diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc index af039374346..9b0a120b797 100644 --- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc +++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc @@ -29,6 +29,31 @@ Please see the link:https://github.com/apache/tinkerpop/blob/3.2.10/CHANGELOG.as === Upgrading for Users +==== SSL Security + +TinkerPop improves its security posture by removing insecure defaults and adding forward-looking standards support. + +Gremlin Server no longer supports automatically creating self-signed certificates. +Self-signed certificates can still be created manually outside of Gremlin Server. +If ssl is enabled, a key store must be configured. + +Cluster client no longer trusts all certs by default as this is an insecure configuration. +Instead, if no trust store is configured, Cluster will use the default CA certs. +To revert to the previous behavior and accept all certs, it must be explicitly configured. + +This release introduces JKS and PKCS12 support. JKS is the legacy Java Key Store. PKCS12 has better cross-platform support and is gaining in adoption. +Be aware that JKS is the default on Java 8. Java 9 and higher use PKCS12 as the default. Both Java keytool and OpenSSL tools can create, read, update PKCS12 files. + +Other new features include specifying SSL protocols and cipher suites. +The packaged `*-secure.yaml` files now restrict the protocol to `TLSv1.2` by default. + +PEM-based configurations are deprecated and may be removed in a future release. + +See the section on configuring SSL. + +link:https://issues.apache.org/jira/browse/TINKERPOP-2022[TINKERPOP-2022] +link:https://issues.apache.org/jira/browse/TINKERPOP-2023[TINKERPOP-2023] + ==== Bulk Import and Export TinkerPop has provided some general methods for importing and exporting data, but more and more graph providers are diff --git a/gremlin-console/conf/remote-secure.yaml b/gremlin-console/conf/remote-secure.yaml index c7a2c441075..b0a7309af43 100644 --- a/gremlin-console/conf/remote-secure.yaml +++ b/gremlin-console/conf/remote-secure.yaml @@ -30,5 +30,5 @@ username: stephen password: password connectionPool: { enableSsl: true, - sslSkipCertValidation: true } + sslEnabledProtocols: [TLSv1.2] } serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }} diff --git a/gremlin-server/conf/gremlin-server-rest-secure.yaml b/gremlin-server/conf/gremlin-server-rest-secure.yaml index fcfbba1b699..2f4db91c451 100644 --- a/gremlin-server/conf/gremlin-server-rest-secure.yaml +++ b/gremlin-server/conf/gremlin-server-rest-secure.yaml @@ -70,6 +70,7 @@ authentication: { credentialsDb: conf/tinkergraph-credentials.properties}} ssl: { enabled: true, + sslEnabledProtocols: [TLSv1.2], # You must configure a keyStore! #keyStore: server.jks, #keyStorePassword: changeit diff --git a/gremlin-server/conf/gremlin-server-secure.yaml b/gremlin-server/conf/gremlin-server-secure.yaml index af46c596b7b..637af122e88 100644 --- a/gremlin-server/conf/gremlin-server-secure.yaml +++ b/gremlin-server/conf/gremlin-server-secure.yaml @@ -74,6 +74,7 @@ authentication: { credentialsDb: conf/tinkergraph-credentials.properties}} ssl: { enabled: true, + sslEnabledProtocols: [TLSv1.2], # You must configure a keyStore! #keyStore: server.jks, #keyStorePassword: changeit From 5d893cfada0e257be1b6561faaad74c66e9cf636 Mon Sep 17 00:00:00 2001 From: Robert Dale Date: Sun, 12 Aug 2018 22:23:33 -0400 Subject: [PATCH 3/7] TINKERPOP-2023 updated docs --- .../reference/gremlin-applications.asciidoc | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index f4f50c13d12..1f64f461ad7 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -732,7 +732,10 @@ The following table describes the various configuration options for the Gremlin |connectionPool.keepAliveInterval |Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to zero to disable this feature. |1800000 |connectionPool.keyCertChainFile |The X.509 certificate chain file in PEM format. |_none_ |connectionPool.keyFile |The `PKCS#8` private key file in PEM format. |_none_ -|connectionPool.keyPassword |The password of the `keyFile` if it is password-protected |_none_ +|connectionPool.keyPassword |The password of the `keyFile` if it is password-protected. |_none_ +|connectionPool.keyStore |The private key in JKS or PKCS#12 format. |_none_ +|connectionPool.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ +|connectionPool.keyStoreType |JKS (Java 8 default) or PKCS#12 (Java 9+ default)|_none_ |connectionPool.maxContentLength |The maximum length in bytes that a message can be sent to the server. This number can be no greater than the setting of the same name in the server configuration. |65536 |connectionPool.maxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |4 |connectionPool.maxSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |16 @@ -745,7 +748,12 @@ The following table describes the various configuration options for the Gremlin |connectionPool.reconnectInitialDelay |The amount of time in milliseconds to wait before trying to reconnect to a dead host for the first time. |1000 |connectionPool.reconnectInterval |The amount of time in milliseconds to wait before trying to reconnect to a dead host. This interval occurs after the time specified by the `reconnectInitialDelay`. |1000 |connectionPool.resultIterationBatchSize |The override value for the size of the result batches to be returned from the server. |64 -|connectionPool.trustCertChainFile |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the `TrustManager` will be established with a self-signed certificate which is NOT suitable for production purposes. |_none_ +|connectionPool.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ +|connectionPool.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ +|connectionPool.sslSkipCertValidation |Configures the `TrustManager` to trust all certs without any validation. Should not be used in production.|false +|connectionPool.trustCertChainFile |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be uesd. |_none_ +|connectionPool.trustStore |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ +|connectionPool.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_ |hosts |The list of hosts that the driver will connect to. |localhost |jaasEntry |Sets the `AuthProperties.Property.JAAS_ENTRY` properties for authentication to Gremlin Server. |_none_ |nioPoolSize |Size of the pool for handling request/response operations. |available processors @@ -1148,11 +1156,18 @@ The following table describes the various configuration options that Gremlin Ser |serializers[X].className |The full class name of the `MessageSerializer` implementation. |_none_ |serializers[X].config |A `Map` containing `MessageSerializer` specific configurations. |_none_ |ssl.enabled |Determines if SSL is turned on or not. |false -|ssl.keyCertChainFile |The X.509 certificate chain file in PEM format. If this value is not present and `ssl.enabled` is `true` a self-signed certificate will be used (not suitable for production). |_none_ -|ssl.keyFile |The `PKCS#8` private key file in PEM format. If this value is not present and `ssl.enabled` is `true` a self-signed certificate will be used (not suitable for production). |_none_ -|ssl.keyPassword |The password of the `keyFile` if it is password-protected |_none_ +|ssl.keyCertChainFile |The X.509 certificate chain file in PEM format.|_none_ +|ssl.keyFile |The `PKCS#8` private key file in PEM format.|_none_ +|ssl.keyPassword |The password of the `keyFile` if it is password-protected. |_none_ +|ssl.keyStore |The private key in JKS or PKCS#12 format. |_none_ +|ssl.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ +|ssl.keyStoreType |JKS (Java 8 default) or PKCS#12 (Java 9+ default) |_none_ |ssl.needClientAuth | Optional. One of NONE, OPTIONAL, REQUIRE. Enables client certificate authentication at the enforcement level specified. Can be used in combination with Authenticator. |_none_ +|ssl.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ +|ssl.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |ssl.trustCertChainFile | Required when needClientAuth is OPTIONAL or REQUIRE. Trusted certificates for verifying the remote endpoint's certificate. The file should contain an X.509 certificate chain in PEM format. |_none_ +|ssl.trustStore |Required when needClientAuth is OPTIONAL or REQUIRE. Trusted certificates for verifying the remote endpoint's certificate. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ +|ssl.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_ |strictTransactionManagement |Set to `true` to require `aliases` to be submitted on every requests, where the `aliases` become the scope of transaction management. |false |threadPoolBoss |The number of threads available to Gremlin Server for accepting connections. Should always be set to `1`. |1 |threadPoolWorker |The number of threads available to Gremlin Server for processing non-blocking reads and writes. |1 @@ -1944,7 +1959,7 @@ The Gremlin Server can also be started as a link:https://hub.docker.com/r/tinker [source,text] ---- $ docker run tinkerpop/gremlin-server:x.y.z -[INFO] GremlinServer - +[INFO] GremlinServer - \,,,/ (o o) -----oOOo-(3)-oOOo----- From d05e3c566b580f5aee020234e17b69df3f708b7a Mon Sep 17 00:00:00 2001 From: Robert Dale Date: Mon, 13 Aug 2018 15:28:40 -0400 Subject: [PATCH 4/7] TINKERPOP-2023 added tests and some fixes --- .../reference/gremlin-applications.asciidoc | 2 +- .../tinkerpop/gremlin/driver/Settings.java | 28 ++- .../gremlin/driver/SettingsTest.java | 17 ++ .../AbstractGremlinServerIntegrationTest.java | 14 +- .../server/GremlinServerIntegrateTest.java | 192 ++++++++++++++++-- ...GremlinServerChannelizerIntegrateTest.java | 2 + .../src/test/resources/client-key.jks | Bin 0 -> 2241 bytes .../src/test/resources/client-key.p12 | Bin 0 -> 2583 bytes .../src/test/resources/client-trust.jks | Bin 0 -> 969 bytes .../src/test/resources/client-trust.p12 | Bin 0 -> 1202 bytes .../resources/{server.jks => server-key.jks} | Bin .../resources/{server.p12 => server-key.p12} | Bin .../src/test/resources/server-trust.jks | Bin 0 -> 952 bytes .../src/test/resources/server-trust.p12 | Bin 0 -> 1186 bytes 14 files changed, 228 insertions(+), 27 deletions(-) create mode 100644 gremlin-server/src/test/resources/client-key.jks create mode 100644 gremlin-server/src/test/resources/client-key.p12 create mode 100644 gremlin-server/src/test/resources/client-trust.jks create mode 100644 gremlin-server/src/test/resources/client-trust.p12 rename gremlin-server/src/test/resources/{server.jks => server-key.jks} (100%) rename gremlin-server/src/test/resources/{server.p12 => server-key.p12} (100%) create mode 100644 gremlin-server/src/test/resources/server-trust.jks create mode 100644 gremlin-server/src/test/resources/server-trust.p12 diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index 1f64f461ad7..8ad8a0a18d8 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -735,7 +735,7 @@ The following table describes the various configuration options for the Gremlin |connectionPool.keyPassword |The password of the `keyFile` if it is password-protected. |_none_ |connectionPool.keyStore |The private key in JKS or PKCS#12 format. |_none_ |connectionPool.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ -|connectionPool.keyStoreType |JKS (Java 8 default) or PKCS#12 (Java 9+ default)|_none_ +|connectionPool.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default)|_none_ |connectionPool.maxContentLength |The maximum length in bytes that a message can be sent to the server. This number can be no greater than the setting of the same name in the server configuration. |65536 |connectionPool.maxInProcessPerConnection |The maximum number of in-flight requests that can occur on a connection. |4 |connectionPool.maxSimultaneousUsagePerConnection |The maximum number of times that a connection can be borrowed from the pool simultaneously. |16 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 009a0bfc662..4d54792d6ce 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 @@ -181,6 +181,32 @@ public static Settings from(final Configuration conf) { if (connectionPoolConf.containsKey("trustCertChainFile")) cpSettings.trustCertChainFile = connectionPoolConf.getString("trustCertChainFile"); + if (connectionPoolConf.containsKey("keyStore")) + cpSettings.keyStore = connectionPoolConf.getString("keyStore"); + + if (connectionPoolConf.containsKey("keyStorePassword")) + cpSettings.keyStorePassword = connectionPoolConf.getString("keyStorePassword"); + + if (connectionPoolConf.containsKey("keyStoreType")) + cpSettings.keyStoreType = connectionPoolConf.getString("keyStoreType"); + + if (connectionPoolConf.containsKey("trustStore")) + cpSettings.trustStore = connectionPoolConf.getString("trustStore"); + + if (connectionPoolConf.containsKey("trustStorePassword")) + cpSettings.trustStorePassword = connectionPoolConf.getString("trustStorePassword"); + + if (connectionPoolConf.containsKey("sslEnabledProtocols")) + cpSettings.sslEnabledProtocols = connectionPoolConf.getList("sslEnabledProtocols").stream().map(Object::toString) + .collect(Collectors.toList()); + + if (connectionPoolConf.containsKey("sslCipherSuites")) + cpSettings.sslCipherSuites = connectionPoolConf.getList("sslCipherSuites").stream().map(Object::toString) + .collect(Collectors.toList()); + + if (connectionPoolConf.containsKey("sslSkipCertValidation")) + cpSettings.sslSkipCertValidation = connectionPoolConf.getBoolean("sslSkipCertValidation"); + if (connectionPoolConf.containsKey("minSize")) cpSettings.minSize = connectionPoolConf.getInt("minSize"); @@ -283,7 +309,7 @@ static class ConnectionPoolSettings { public String trustStorePassword; /** - * JSSE keystore format. Similar to setting JSSE property + * JSSE keystore format. 'jks' or 'pkcs12'. Similar to setting JSSE property * {@code javax.net.ssl.keyStoreType}. */ public String keyStoreType; diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java index c373879820f..56e0ec8c63f 100644 --- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java +++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/SettingsTest.java @@ -49,6 +49,14 @@ public void shouldCreateFromConfiguration() { conf.setProperty("connectionPool.keyFile", "PKCS#8"); conf.setProperty("connectionPool.keyPassword", "password1"); conf.setProperty("connectionPool.trustCertChainFile", "pem"); + conf.setProperty("connectionPool.keyStore", "server.jks"); + conf.setProperty("connectionPool.keyStorePassword", "password2"); + conf.setProperty("connectionPool.keyStoreType", "pkcs12"); + conf.setProperty("connectionPool.trustStore", "trust.jks"); + conf.setProperty("connectionPool.trustStorePassword", "password3"); + conf.setProperty("connectionPool.sslEnabledProtocols", Arrays.asList("TLSv1.1","TLSv1.2")); + conf.setProperty("connectionPool.sslCipherSuites", Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")); + conf.setProperty("connectionPool.sslSkipCertValidation", true); conf.setProperty("connectionPool.minSize", 100); conf.setProperty("connectionPool.maxSize", 200); conf.setProperty("connectionPool.minSimultaneousUsagePerConnection", 300); @@ -71,6 +79,7 @@ public void shouldCreateFromConfiguration() { assertEquals("password1", settings.password); assertEquals("JaasIt", settings.jaasEntry); assertEquals("protocol0", settings.protocol); + assertEquals(Arrays.asList("255.0.0.1", "255.0.0.2", "255.0.0.3"), settings.hosts); assertEquals("my.serializers.MySerializer", settings.serializer.className); assertEquals("thing", settings.serializer.config.get("any")); assertEquals(true, settings.connectionPool.enableSsl); @@ -78,6 +87,14 @@ public void shouldCreateFromConfiguration() { assertEquals("PKCS#8", settings.connectionPool.keyFile); assertEquals("password1", settings.connectionPool.keyPassword); assertEquals("pem", settings.connectionPool.trustCertChainFile); + assertEquals("server.jks", settings.connectionPool.keyStore); + assertEquals("password2", settings.connectionPool.keyStorePassword); + assertEquals("pkcs12", settings.connectionPool.keyStoreType); + assertEquals("trust.jks", settings.connectionPool.trustStore); + assertEquals("password3", settings.connectionPool.trustStorePassword); + assertEquals(Arrays.asList("TLSv1.1","TLSv1.2"), settings.connectionPool.sslEnabledProtocols); + assertEquals(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"), settings.connectionPool.sslCipherSuites); + assertEquals(true, settings.connectionPool.sslSkipCertValidation); assertEquals(100, settings.connectionPool.minSize); assertEquals(200, settings.connectionPool.maxSize); assertEquals(300, settings.connectionPool.minSimultaneousUsagePerConnection); 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 0543a593e3c..c5e396699e1 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 @@ -40,10 +40,16 @@ 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"; + public static final String JKS_SERVER_KEY = "src/test/resources/server-key.jks"; + public static final String JKS_SERVER_TRUST = "src/test/resources/server-trust.jks"; + public static final String JKS_CLIENT_KEY = "src/test/resources/client-key.jks"; + public static final String JKS_CLIENT_TRUST = "src/test/resources/client-trust.jks"; + public static final String P12_SERVER_KEY = "src/test/resources/server-key.p12"; + public static final String P12_SERVER_TRUST = "src/test/resources/server-trust.p12"; + public static final String P12_CLIENT_KEY = "src/test/resources/client-key.p12"; + public static final String P12_CLIENT_TRUST = "src/test/resources/client-trust.p12"; + public static final String KEYSTORE_TYPE_JKS = "jks"; + public static final String KEYSTORE_TYPE_PKCS12 = "pkcs12"; protected GremlinServer server; private Settings overriddenSettings; 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 238d2b2e50e..a4e94785f5d 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 @@ -74,6 +74,7 @@ import java.lang.reflect.Field; import java.nio.channels.ClosedChannelException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -195,42 +196,97 @@ public Settings overrideSettings(final Settings settings) { settings.ssl.enabled = true; settings.ssl.keyStore = JKS_SERVER_KEY; settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; break; case "shouldEnableSslWithSslContextProgrammaticallySpecified": settings.ssl = new Settings.SslSettings(); settings.ssl.enabled = true; settings.ssl.overrideSslContext(createServerSslContext()); break; - case "shouldEnableSslAndClientCertificateAuth": + case "shouldEnableSslAndClientCertificateAuthWithLegacyPem": settings.ssl = new Settings.SslSettings(); settings.ssl.enabled = true; settings.ssl.needClientAuth = ClientAuth.REQUIRE; settings.ssl.keyCertChainFile = PEM_SERVER_CRT; settings.ssl.keyFile = PEM_SERVER_KEY; - settings.ssl.keyPassword =KEY_PASS; + settings.ssl.keyPassword = KEY_PASS; // Trust the client settings.ssl.trustCertChainFile = PEM_CLIENT_CRT; - break; - case "shouldEnableSslAndClientCertificateAuthAndFailWithoutCert": + break; + case "shouldEnableSslAndClientCertificateAuthAndFailWithoutCertWithLegacyPem": settings.ssl = new Settings.SslSettings(); settings.ssl.enabled = true; settings.ssl.needClientAuth = ClientAuth.REQUIRE; settings.ssl.keyCertChainFile = PEM_SERVER_CRT; settings.ssl.keyFile = PEM_SERVER_KEY; - settings.ssl.keyPassword =KEY_PASS; + settings.ssl.keyPassword = KEY_PASS; // Trust the client settings.ssl.trustCertChainFile = PEM_CLIENT_CRT; - break; - case "shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCert": + break; + case "shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCertWithLegacyPem": settings.ssl = new Settings.SslSettings(); settings.ssl.enabled = true; settings.ssl.needClientAuth = ClientAuth.REQUIRE; settings.ssl.keyCertChainFile = PEM_SERVER_CRT; settings.ssl.keyFile = PEM_SERVER_KEY; - settings.ssl.keyPassword =KEY_PASS; + settings.ssl.keyPassword = KEY_PASS; // Trust ONLY the server cert settings.ssl.trustCertChainFile = PEM_SERVER_CRT; - break; + break; + case "shouldEnableSslAndClientCertificateAuthWithPkcs12": + settings.ssl = new Settings.SslSettings(); + settings.ssl.enabled = true; + settings.ssl.needClientAuth = ClientAuth.REQUIRE; + settings.ssl.keyStore = P12_SERVER_KEY; + settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_PKCS12; + settings.ssl.trustStore = P12_SERVER_TRUST; + settings.ssl.trustStorePassword = KEY_PASS; + break; + case "shouldEnableSslAndClientCertificateAuth": + settings.ssl = new Settings.SslSettings(); + settings.ssl.enabled = true; + settings.ssl.needClientAuth = ClientAuth.REQUIRE; + settings.ssl.keyStore = JKS_SERVER_KEY; + settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; + settings.ssl.trustStore = JKS_SERVER_TRUST; + settings.ssl.trustStorePassword = KEY_PASS; + break; + case "shouldEnableSslAndClientCertificateAuthAndFailWithoutCert": + settings.ssl = new Settings.SslSettings(); + settings.ssl.enabled = true; + settings.ssl.needClientAuth = ClientAuth.REQUIRE; + settings.ssl.keyStore = JKS_SERVER_KEY; + settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; + settings.ssl.trustStore = JKS_SERVER_TRUST; + settings.ssl.trustStorePassword = KEY_PASS; + break; + case "shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCert": + settings.ssl = new Settings.SslSettings(); + settings.ssl.enabled = true; + settings.ssl.needClientAuth = ClientAuth.REQUIRE; + settings.ssl.keyStore = JKS_SERVER_KEY; + settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; + break; + case "shouldEnableSslAndFailIfProtocolsDontMatch": + settings.ssl = new Settings.SslSettings(); + settings.ssl.enabled = true; + settings.ssl.keyStore = JKS_SERVER_KEY; + settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; + settings.ssl.sslEnabledProtocols = Arrays.asList("TLSv1.1"); + break; + case "shouldEnableSslAndFailIfCiphersDontMatch": + settings.ssl = new Settings.SslSettings(); + settings.ssl.enabled = true; + settings.ssl.keyStore = JKS_SERVER_KEY; + settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; + settings.ssl.sslCipherSuites = Arrays.asList("TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); + break; case "shouldUseSimpleSandbox": settings.scriptEngines.get("gremlin-groovy").config = getScriptEngineConfForSimpleSandbox(); break; @@ -532,21 +588,21 @@ public void shouldEnableSslButFailIfClientConnectsWithoutIt() { } @Test - public void shouldEnableSslAndClientCertificateAuth() { - final Cluster cluster = TestClientFactory.build().enableSsl(true) - .keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY) - .keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create(); - final Client client = cluster.connect(); + public void shouldEnableSslAndClientCertificateAuthWithLegacyPem() { + final Cluster cluster = TestClientFactory.build().enableSsl(true) + .keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY) + .keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create(); + final Client client = cluster.connect(); try { - assertEquals("test", client.submit("'test'").one().getString()); + assertEquals("test", client.submit("'test'").one().getString()); } finally { cluster.close(); } } @Test - public void shouldEnableSslAndClientCertificateAuthAndFailWithoutCert() { + public void shouldEnableSslAndClientCertificateAuthAndFailWithoutCertWithLegacyPem() { final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS).sslSkipCertValidation(true).create(); final Client client = cluster.connect(); @@ -562,11 +618,11 @@ public void shouldEnableSslAndClientCertificateAuthAndFailWithoutCert() { } @Test - public void shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCert() { - final Cluster cluster = TestClientFactory.build().enableSsl(true) - .keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY) - .keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create(); - final Client client = cluster.connect(); + public void shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCertWithLegacyPem() { + final Cluster cluster = TestClientFactory.build().enableSsl(true) + .keyCertChainFile(PEM_CLIENT_CRT).keyFile(PEM_CLIENT_KEY) + .keyPassword(KEY_PASS).trustCertificateChainFile(PEM_SERVER_CRT).create(); + final Client client = cluster.connect(); try { client.submit("'test'").one(); @@ -578,6 +634,100 @@ public void shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCe cluster.close(); } } + + @Test + public void shouldEnableSslAndClientCertificateAuthWithPkcs12() { + final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(P12_CLIENT_KEY).keyStorePassword(KEY_PASS) + .keyStoreType(KEYSTORE_TYPE_PKCS12).trustStore(P12_CLIENT_TRUST).trustStorePassword(KEY_PASS).create(); + final Client client = cluster.connect(); + + try { + assertEquals("test", client.submit("'test'").one().getString()); + } finally { + cluster.close(); + } + } + + @Test + public void shouldEnableSslAndClientCertificateAuth() { + final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_CLIENT_KEY).keyStorePassword(KEY_PASS) + .keyStoreType(KEYSTORE_TYPE_JKS).trustStore(JKS_CLIENT_TRUST).trustStorePassword(KEY_PASS).create(); + final Client client = cluster.connect(); + + try { + assertEquals("test", client.submit("'test'").one().getString()); + } finally { + cluster.close(); + } + } + + @Test + public void shouldEnableSslAndClientCertificateAuthAndFailWithoutCert() { + final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS) + .keyStoreType(KEYSTORE_TYPE_JKS).sslSkipCertValidation(true).create(); + final Client client = cluster.connect(); + + try { + client.submit("'test'").one(); + fail("Should throw exception because ssl client auth is enabled on the server but client does not have a cert"); + } catch (Exception x) { + final Throwable root = ExceptionUtils.getRootCause(x); + assertThat(root, instanceOf(TimeoutException.class)); + } finally { + cluster.close(); + } + } + + @Test + public void shouldEnableSslAndClientCertificateAuthAndFailWithoutTrustedClientCert() { + final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_CLIENT_KEY).keyStorePassword(KEY_PASS) + .keyStoreType(KEYSTORE_TYPE_JKS).trustStore(JKS_CLIENT_TRUST).trustStorePassword(KEY_PASS).create(); + final Client client = cluster.connect(); + + try { + client.submit("'test'").one(); + fail("Should throw exception because ssl client auth is enabled on the server but does not trust client's cert"); + } catch (Exception x) { + final Throwable root = ExceptionUtils.getRootCause(x); + assertThat(root, instanceOf(TimeoutException.class)); + } finally { + cluster.close(); + } + } + + @Test + public void shouldEnableSslAndFailIfProtocolsDontMatch() { + final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS) + .sslSkipCertValidation(true).sslEnabledProtocols(Arrays.asList("TLSv1.2")).create(); + final Client client = cluster.connect(); + + try { + client.submit("'test'").one(); + fail("Should throw exception because ssl client requires TLSv1.2 whereas server supports only TLSv1.1"); + } catch (Exception x) { + final Throwable root = ExceptionUtils.getRootCause(x); + assertThat(root, instanceOf(TimeoutException.class)); + } finally { + cluster.close(); + } + } + + @Test + public void shouldEnableSslAndFailIfCiphersDontMatch() { + final Cluster cluster = TestClientFactory.build().enableSsl(true).keyStore(JKS_SERVER_KEY).keyStorePassword(KEY_PASS) + .sslSkipCertValidation(true).sslCipherSuites(Arrays.asList("SSL_RSA_WITH_RC4_128_SHA")).create(); + final Client client = cluster.connect(); + + try { + client.submit("'test'").one(); + fail("Should throw exception because ssl client requires TLSv1.2 whereas server supports only TLSv1.1"); + } catch (Exception x) { + final Throwable root = ExceptionUtils.getRootCause(x); + assertThat(root, instanceOf(TimeoutException.class)); + } finally { + cluster.close(); + } + } @Test public void shouldRespectHighWaterMarkSettingAndSucceed() throws Exception { 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 300a7f4c784..ced5247e461 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 @@ -102,6 +102,7 @@ public Settings overrideSettings(final Settings settings) { settings.ssl.enabled = true; settings.ssl.keyStore = JKS_SERVER_KEY; settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; break; case "shouldWorkWithAuth": if (authSettings != null) { @@ -113,6 +114,7 @@ public Settings overrideSettings(final Settings settings) { settings.ssl.enabled = true; settings.ssl.keyStore = JKS_SERVER_KEY; settings.ssl.keyStorePassword = KEY_PASS; + settings.ssl.keyStoreType = KEYSTORE_TYPE_JKS; if (authSettings != null) { settings.authentication = getAuthSettings(); } diff --git a/gremlin-server/src/test/resources/client-key.jks b/gremlin-server/src/test/resources/client-key.jks new file mode 100644 index 0000000000000000000000000000000000000000..39df02b7e13eef6c1a8684588e9f10642dcd1a30 GIT binary patch literal 2241 zcmcgt`8yN}7oLT&WgVg#du7HtV`+%SmhFCtEMu|{#u#KbvL&)yA+n4?7-Xx+PzlMF z>@=m2^|O|^S+X;(?>_fF&;1L&AKo9%d(QKm^StLg?_sVoR{;P3=mfyO0CDvu5qyG9 zLV{|lY!(2(3Pi@R93goioN^E#3s4rs4+OFTSYlYdd!>c0D6nViq&V>2D=a%#2DvY5 zbA`UZFPf}+`K+I0S{ZIM(C&NVM))66dD81BOMG6p(S9ufo>k#UtkrqM7Jq6cpXB_Z zIJX0*SXT8ZEYSWu!qz5GctZiRu)-X1vVrwMJSPI^aSj+>fnQRN+}F}rh?NV2w~Je~ zw8twGXTl(+OZOh#vV?#@ea}M7^duUU>gjALV~0RSGYfCb*Ki#lZv7#hOkNADeHiGKR4yZvaip;4mFUoo0w(N9710bQ*4A5iCAodq=Nu|UHP!O zCe}qRHNE$-T8Yjkn%J__HjFfd@ptkhN1zjRlz6&;^i#Bb7jtrgTgL87Dtc`>RCF%v z_JWwoA zx`h@bQ6MZyjGp_}LXR_?Sh;@M*(hp@PphTRtTt0aF$21rc^ zUN%a6dgIrFg?Ky1qQxCUk6Wg9KDyW3jg_HQ*x4n(M6V8?)59&AEc(0D$tSSiC|d4$ zGk6MfNZvg?e>an|qUIX0j=;Ql|A|~`ZCW^Z$ILIK6S23yb_SzZ_I`jJ33aR688vPx z+x4van&&*$?}@KnkTl%i2%&Z*Ge4YXSd})+&pBp8w;=-{NPmixQ@ zk{g%`t!cfjG#m4rSd=rwAiO7lF>}XkNaS2a39PSltfXB3Ua&jP()ZLVHqKNt-(yfS z3brf>d*UH0;vLyMc1L^)3&6p>ilxaSv4msOKjySI?e7op_r2KYUuc$&A+sSdTRnu=ylY4P zP0xj~HbOb_7aI)x>NN(=98WnF9TESd6pg;PO`m#tD#wt`DU;^xIQQ(g!UyV+Rj~nb zI7qdtD(9rU*!EI;0iEc1p zM`S!sP7-(1p`zjd0*m%!j*&07)`Zd>b-ZTj&hR$R4VibYC=d?`Gz&PQIic|4l?Y*z7#9s;Q#Zi|O`07c4#| z7=K8ol8vwt+jwj^wTAPc8{_~ec;hSFb*o%(-ojMIa!*iN*S;GZwV7SCr%>m}sz+RngpfZ!!@m&|Q%}?g$@t3{S#gSLNDTl09Eywq z2P0!Z4m2%cq0`E;A5j{|6ki!3CIH7#Het1_8f`k>x$BPhP?(6qYF&C80+Q-YsH^c|U zd(!Kq7!3W}sgV-G+$eRVI!XnluA+=owiV%3Mxs@aYN$(p6aUv~Vt`Wr7USeqfMbBX z0Avi16BGjk0-k8g*pBW2_F?Pv84hapWbS^xVE2AkQa0@E6Y+BOz&E&|5n5Uy|GiqL z(t?_{*H>wwpMXJg%kXz*jMLm0ev0f4vCnI!<|i5V0YHzhsZ9KVw;Z=3 zt%v0XND#hZK4g>>*HI&EnwrQvO+Nflx%o*qy`YP4^Rm4c>KV_N3YrC)OP=TP}g zlQH|>l#Uq0npao4qGxtT`E--sHfxdQFvTWOJWPZMn_8S^#;`M$F8+KNr7}*bbSd+{Ln+mFl5M*v_Vhg{ za{ht_E4x(-EwL19pUDb(z-TCyuRG?sLWN4Be1H0W=nE1YLZSGQnmLq zqDl;a02hxI;fS`G#kt8CWgG^-XSHa2A=)JiWXw%CH(YU^y#PPJ za(zpH=@ej$xOY zeJTdTFe-)1#}>ve^nGZ9V2$q!{m znGX6?WwX&ejt?Q}BH=)DK4sj=gi=)@v2D4TvsEiu}IabFlxjUS-U|8Yr_xWvmoRg8k zAmqBAYKKh9#OcH~2k;Arlm)p=Hf9m_g?no3NDkl6c*;^cC7Sv|@(hm0y`0US(^pf} zp{b)4oTmbTX#X^FkzbyTjFW=X@;wr1N)`lu{1tTUo&9%(6>@ogFykmP&Ea03do#LK z!=b9I#^Y7&uw~&(_-YjK6 zF!5Ge;zy}U0;5!k1VzW-WteUfj)Oj@>loCR@|%)rS{`x77^w4a2%D^+HX(m2%b zjSPl~`U{a=xR??R!KyVPRsa@MY5pc-(KsCshbo7kaj)L0dXRkK^HHI&g#@=d+=hFI zURv=Z-_(8mBi{AGO50AA)zCYIb~tM<%z=E^GeL^S0q~WV*&ovJwnfZh+y%zW?TYW> z3zDN016AP$^UEp2v9~|;`aW+@17#hc(56~Z#4y`1uUP$yT8=+vlPZbcA?d1LivS8S zN{1eAu4eOZ?xO|rwfbe6*rGe~$bJKSn_7=0U3;l@>(<>HK!-e8c_<6B)-8^{pk;cn z$NeA%>uy4B`4cCW6+p>Y3V$uyEM%=3bt)Qytv#$0tSNE4w4H?aQV2`qUyI{QHNMB0 z$?~sd8G723v-5BHy)tNIO&RYWQS&Qs=O|y8CKOkSRuV9{v5xQ3*j2 zk{Ilk)j$&j9wO+c3-7W~DQdao#BznvBN7HS6NdxiLznNE z`6AKX22plIe{k@4kTG7{OAta6??so{dj+yL=NdYS6oNZFxufxUo}|=D5Pe_rQHN9NvHH`fL0VNRLdFR>dp5vdrh`< zP(h`b%V)YnOkHq?fn%HZWUu?NPCYngqOhnGyEfR|X`F8E=tY~F70^K?Q5KTY#&A%Z>>~}D!|4{CS<|-~!&UgN>YQa9tU?-d0+!iRDmTx?0N3;xe7?YtVjpq7x zhvb5t!lLWn8!UBBNq}6YHGqL49QT9}kS%Wq} zN&c-$hzOb=1_j^&-T)$i0JsGRK*|0SilRlpLN-JaK?aS{&_ruv&>E-JH88*AY4mrA zo9mZP|3YXG5b$fk|4D%VGA!3$hW+TDBjOt^(ZjGpTeT5(-Xy2)H2>GIF%*uCxc4pu zcHiffYa@B^8j^FB?B)wTuz(T4JfxR(1(PH!`hwV`(2T!Vgf)yOj6gsw6(sfDO9YI&H-Yo~19 ztx)24J*yLuJiTSwk`%QzHZFNcJj%4)ldQF&r6D@`NC0j4NeN2moQf(3YR!=QY=#O% zx|WaRbj$42-W4UD3={XrJpf#aY=FGh6xeb_B5i4xMYYV&QKPwCuN+Pp@*6_G;LM;F zde%Nt)hx>F?0v(PO=a7SNv~ahZz9*7DAYbF$o=W7w23ovq?({Fd>&9cqlp=o zEeyv{U2;U$y$&&w1(|2Y-q1*vtpTtLv4X}|>^Wvcy@>Q(PF_8CHkmaobQ;+=9@Ezs zuqgtZvnP*FL^wYx=fA0a8{~eD+ja2#$97No`@$n14li}|#gDn_#o`>< ztsRRJ!>W*Obn8V5@5$U!gdQfU@%TRfu^G8;?oT&ln5{E|Gv9SDa(v#2J3BA={HrZV zK4Xv3cw&`LTk>18UYkn0Lf7NpHlMj^&LRN^U-oai%psb?tZtlTHHKK%@jhY1tUgJ! z-uiL3%B-et?H!IdE_FC?BfqpIm&k}%G!0}Uq9#4mTv02UM|@i*e8lXaAgVpa{=ebq_ODX@b9DR**th(YiSe730?j*B+ zay=zSN@E;6YKnieyKXP zZt>;cgD}@N#Vx9xBsx-mJ8{%wqQ4Xn*7|-*;L(0kea0+^cmAynAszE&HTM8?Z^_@6 z{>{Wu=oU|L1RY;llJolXBh;r34<+l=pZ33pC|G=}7zrIQiA7*xcMSRL%Hj)H&&0@Y zLwYA>3tCJ%0(+HP$y=uhd^Gk~zld%52lKFt2A8LOIz+K3!mxBjUNd>20l9ifY%+6; zB7hpVoUuMqTXb+NNEfAtl0`wdI8X6&fFw8pV3EMc9vP+b=fUc_R!1XR83H!vo+*Px e(i<|}b|X{mD_5lpicImJr5tAQAP!(+(SHE&wytFW literal 0 HcmV?d00001 diff --git a/gremlin-server/src/test/resources/client-trust.jks b/gremlin-server/src/test/resources/client-trust.jks new file mode 100644 index 0000000000000000000000000000000000000000..d8b54791859e9e686042cda4439950c6b39fdcac GIT binary patch literal 969 zcmezO_TO6u1_mY|W(3omIr+(nIT`uIB|wo>lU~Uv2G$5YQv*u|2Ih8yCgx^?CZ_BK z%uI|-Oe`r0o!bm}**LY@JlekVGBR?rG8hyZavN~6F^96S2{VNT!#EtmOwNvmA_hVr z8Fpdr;KaO=LxH;adAgc4$MzrSvUzjx zoWRnLA|dMoRQ5|AZQypCEBiM1youi9snZklD^^T>ow+tB;qQ{)1&3!}6gw95mkJ;I?jML@MHdLsU#qT_C=v6$cO<0n#qGqn??W4U-6Wy2<{Z~A$pSz&0aWT(5 zrSc75UVU21`1s^|@A;m)PIm~NpE!B_MkgoBOGO)w@pAiz?7o_unAv%uMs)GwC!y9p zxlha|nx3%QQyZP`Wqmf3?ZB~a_1B$M@l4E&42+8v4de}Efe|Xp$0EievQFl%5=*;a zjQphBH5~tXmj*uNj7APbVEO_EA|r$3)Q9)FU!`?U4NnfT`rIURd~ug)syyqzBePt3 zFD#uSvM;V-QC!=$$hUHjYdU|=_fD@f31Ir0(4WTp_@9UrW9^(C1H0`Deb?XU+bbOC zUTCHI-0wp{$CAvP-`};^y_cT*viGRM5ypy!fOnswbS_=gofPQUIZ?uOeysma75)BA z2NdoGF38~c80r|n+iIjV@5uZkC0*5Few$e2ziZBxx;y2OrtbIWb-QjboC`TTGyC?D z6EEAfQ{9T}a%LQVqLuc#%QC*&^CoYh;)4sU7Gb6-$!E134xC*qkmz@~Z*9-nzpMVZ zggV};J{?)mfBQvb{kx6oQ3u~EmTx{g{oGH<35kbN`_K5)Mya GUkw0BG-i?j literal 0 HcmV?d00001 diff --git a/gremlin-server/src/test/resources/client-trust.p12 b/gremlin-server/src/test/resources/client-trust.p12 new file mode 100644 index 0000000000000000000000000000000000000000..2100e94381ed9596391ebeb1ccd442201f6e10dc GIT binary patch literal 1202 zcmV;j1Wo%ef&{Jt0Ru3C1ZM^bDuzgg_YDCD0ic2eSOkIuR4{@BP%wf7Oa=)mhDe6@ z4FLxRpn?QFFoFa*0s#Opf&?-K2`Yw2hW8Bt2LUiC1_~;MNQUGl*rK<4RF*K)7>`rD`AMws*5{@i*lMl}u z38|N2EF0Y0PCmNdCj~esrFV8{2LRvcS)9vj8fMVFMfK^Uj=fIM4m`jFhy#x#U&+5; zCl~5T8)@J$RoQ^Ip42J!`VV!6h`lvupll?iOPiP4*VabZ2G#!D*+V(8M;7_D)C`2Dr1G)U^9gH+ioZ;51+X^x9~|B9#joAvJ-? z*m1C=r2*Kw_b2jTPbnkUYO{=XDabS!!I%1c_y1(xk}b2Z4%hsaUTRdBQ^Q`;pDX$qzZVq8I%bZ|&)xOxr)Qz1 z3zDRqi_Pk#A%j^S61!Y6mC$(NSRps}63rai--`)=JeX3qv1XM=Oqgjm41dhjcJ%G} zmFhFN;dR5RooNwPIM;(bi%Q(1o!LL8aFA>#@yD%wo6e@5i*Qe6YwQBs9qJHw={rW9 z^RrS6sjq|)ECeinjD13ODRs6n_Z8LDxk+$u!hVsVm1DUQ9m$w9Hr&7(nv z+q}H%xr?@ei7YWu9PC6KTyeIzHik>!86!%5iE&(v1rvC#>$kbI+@e2eTYvBjFqQT# zmzmKFwLeyNfq?l_P)MV#3$4Q&tKq7>EW}~W&6RK%7kUhueA{*i; zOpi;^=3Jx@;rz|)Dg9u8s{1cA=B_NWmU$l-(%JtXFfFhYDn7r5PwBR>qdq%h5VqXp zgs^K1=vavF{30-aI0qmjCqE|x_Jwd6U_k36Er^`An#5}w=tIpxqS(d`2Y5W-XlCwc zs(T~6+bcFV)lr4>I0@6%Y(Rd`qpqjqn-=JJ(dkL^UbMAtz1lY0K=jy84;Y7Fu4YNA z(OWqihqxm}uYaXNL16eoCsj*ZEqE{3)T*Ye8;3>nFVMPKEWjtu|857p)J- zbud0KAutIB1uG5%0vZJX1QZ*pvoA7>1%7(QVCE~Sf1oC*IlTlF(%?t#gtt4xKb`;7 Q5t~+~A{L!=0s{etpjsI|E&u=k literal 0 HcmV?d00001 diff --git a/gremlin-server/src/test/resources/server.jks b/gremlin-server/src/test/resources/server-key.jks similarity index 100% rename from gremlin-server/src/test/resources/server.jks rename to gremlin-server/src/test/resources/server-key.jks diff --git a/gremlin-server/src/test/resources/server.p12 b/gremlin-server/src/test/resources/server-key.p12 similarity index 100% rename from gremlin-server/src/test/resources/server.p12 rename to gremlin-server/src/test/resources/server-key.p12 diff --git a/gremlin-server/src/test/resources/server-trust.jks b/gremlin-server/src/test/resources/server-trust.jks new file mode 100644 index 0000000000000000000000000000000000000000..a53cf478582cd11772ea6519dda3cc553926970a GIT binary patch literal 952 zcmezO_TO6u1_mY|W(3o0$vK&+c_lz@s>uZXL_Le+shQ~+hLQ&2AQ3KM0mp*Gkj%X7)S`g=0+?cMVfN6x?7aN)JVSnV0I8k#``=<1p#MkVCHU}R-rZerwTFlb`r zVrpV!WLRad9(Cg&W?r>R9d0E`&s(QwWjK}BSq)aYMxOjU(%Ebabj@Xv<8}2>1d$EgwG2>SMzr^1; z+Pr!TPO=0tiD-NZIPc!wdU%7lZ+|EM{jxu=SAM?iIBDK-fzMVk*@kQQ-uT!_Y)MTD zi_$h!*vX*zYD#09-Mm@VVRkxGP9B-YnrXwHDRgFf+N*oJCY^tI>YiKc+k2H!8*ZAK z&rLd`_~`xl<&mB@W4!eLUQFMx&GvZXgC92p9J}}JwaI*9cYOZG*-on%{HH!i%sE?g zDl_|2`5zUzPcLh2%oca@Ycer2GB7SyG>|ut1xBMRABz}^h}A5&nqMn=gYKK=u+7fb zOw?&Sz=a%$z!U`xL`H_bxr`>}ixPecHC&p=djHIVfGUZ9GWVX{|JTIvPhai*#Cqe~ z(^e)eE3BKg)Hz=3pqkw3V@$PAR4p%>DRr&9sinE}r|qQ^+7sFiR|ia6y7?emo3r-% z`YCTY|1z7nTJP`aF}%Am^Snt+mir8avrG(Xf1hb+9(?fZ@u^!$b0-{%zMr@G09WPa zWt^@ZQ}>X}7+m9=MaRtZQlCgM!XATRaPM?H-u?Z!vuY0Mc7+ Ak^lez literal 0 HcmV?d00001 diff --git a/gremlin-server/src/test/resources/server-trust.p12 b/gremlin-server/src/test/resources/server-trust.p12 new file mode 100644 index 0000000000000000000000000000000000000000..a055de012e90f58bfe63365e54fc8379584a5ad7 GIT binary patch literal 1186 zcmV;T1YP?uf&`ud0Ru3C1Xl(LDuzgg_YDCD0ic2eNCbieL@g}-KiP@ zYA5EhW>C&CNk2bT>8>LZ8j;5?LfZkbtxV{tNKqwf<0B7Uz z3IejIV3J&kRw9CL?9H)IphG4VAxR+Ud?^XylR@%O=Py(&zt|dB4i+t0ODc6SKWhWV z3V+|`dX#vTvDC{sR&Tl{qqjbKn!Kc8UIZ8D7BJDyi`Ey9WxWE7?%>M z*a5Uz-1mT`vdw;)tq_Us%&`ExR#~Z;^-WhuABccn?*KOKp|1^(Tf+>-f7) z8+{Is#c5wWyGfr2r|V&uG*%QLUHAIykvq{ddzhK2)x8 zqO6rz7>^r5FXf$0nx{Pcf}J{dRrO%Ni{xn$GmR}X@_E!hgtNv_s$)SpGB(rR2t+YX z0zU@xgYYNZt?=2?k8ZHA&kDrruhs5CzcZJljgd=*t4U;^ulBVl>&QC2y1+jhDG696_m89HitL7! z+AR*K@%eVi_nU65P;C@}e9I=f=O#NH;byAo4`hvy3XJjno|!cxc4 zWc+;hWM``6wH9EbHc*aoQK5Zj z__GF~cLWA)8e4;F^^w8gjY2I5&|O7Itb$Uj$y-o0B1#A6ANEfX+MZDcSws*5n3 Date: Mon, 13 Aug 2018 15:45:27 -0400 Subject: [PATCH 5/7] TINKERPOP-2023 minor edits --- docs/src/reference/gremlin-applications.asciidoc | 4 ++-- docs/src/upgrade/release-3.2.x-incubating.asciidoc | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index 8ad8a0a18d8..d13e2efd732 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -751,7 +751,7 @@ The following table describes the various configuration options for the Gremlin |connectionPool.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |connectionPool.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |connectionPool.sslSkipCertValidation |Configures the `TrustManager` to trust all certs without any validation. Should not be used in production.|false -|connectionPool.trustCertChainFile |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be uesd. |_none_ +|connectionPool.trustCertChainFile |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ |connectionPool.trustStore |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ |connectionPool.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_ |hosts |The list of hosts that the driver will connect to. |localhost @@ -1161,7 +1161,7 @@ The following table describes the various configuration options that Gremlin Ser |ssl.keyPassword |The password of the `keyFile` if it is password-protected. |_none_ |ssl.keyStore |The private key in JKS or PKCS#12 format. |_none_ |ssl.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ -|ssl.keyStoreType |JKS (Java 8 default) or PKCS#12 (Java 9+ default) |_none_ +|ssl.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default) |_none_ |ssl.needClientAuth | Optional. One of NONE, OPTIONAL, REQUIRE. Enables client certificate authentication at the enforcement level specified. Can be used in combination with Authenticator. |_none_ |ssl.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |ssl.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc index 9b0a120b797..ec973de1e16 100644 --- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc +++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc @@ -49,7 +49,8 @@ The packaged `*-secure.yaml` files now restrict the protocol to `TLSv1.2` by def PEM-based configurations are deprecated and may be removed in a future release. -See the section on configuring SSL. +See also http://tinkerpop.apache.org/docs/current/reference/#_configuration[Connecting via Java Configuration], +http://tinkerpop.apache.org/docs/current/reference/#_configuring_2[Gremlin Server Configuration]. link:https://issues.apache.org/jira/browse/TINKERPOP-2022[TINKERPOP-2022] link:https://issues.apache.org/jira/browse/TINKERPOP-2023[TINKERPOP-2023] From bbc0265c06f803d06ec2b6a600d4632d3f7d7d9b Mon Sep 17 00:00:00 2001 From: Robert Dale Date: Fri, 17 Aug 2018 15:47:27 -0400 Subject: [PATCH 6/7] Removed deprecated settings from docs, updated javadoc --- .../reference/gremlin-applications.asciidoc | 8 ---- .../tinkerpop/gremlin/driver/Cluster.java | 42 ++++++++++--------- .../tinkerpop/gremlin/driver/Settings.java | 10 ++--- .../tinkerpop/gremlin/server/Settings.java | 34 ++++++++------- 4 files changed, 46 insertions(+), 48 deletions(-) diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index d13e2efd732..8372a8ae768 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -730,9 +730,6 @@ The following table describes the various configuration options for the Gremlin |connectionPool.channelizer |The fully qualified classname of the client `Channelizer` that defines how to connect to the server. |`Channelizer.WebSocketChannelizer` |connectionPool.enableSsl |Determines if SSL should be enabled or not. If enabled on the server then it must be enabled on the client. |false |connectionPool.keepAliveInterval |Length of time in milliseconds to wait on an idle connection before sending a keep-alive request. Set to zero to disable this feature. |1800000 -|connectionPool.keyCertChainFile |The X.509 certificate chain file in PEM format. |_none_ -|connectionPool.keyFile |The `PKCS#8` private key file in PEM format. |_none_ -|connectionPool.keyPassword |The password of the `keyFile` if it is password-protected. |_none_ |connectionPool.keyStore |The private key in JKS or PKCS#12 format. |_none_ |connectionPool.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ |connectionPool.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default)|_none_ @@ -751,7 +748,6 @@ The following table describes the various configuration options for the Gremlin |connectionPool.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |connectionPool.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |connectionPool.sslSkipCertValidation |Configures the `TrustManager` to trust all certs without any validation. Should not be used in production.|false -|connectionPool.trustCertChainFile |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ |connectionPool.trustStore |File location for a SSL Certificate Chain to use when SSL is enabled. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ |connectionPool.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_ |hosts |The list of hosts that the driver will connect to. |localhost @@ -1156,16 +1152,12 @@ The following table describes the various configuration options that Gremlin Ser |serializers[X].className |The full class name of the `MessageSerializer` implementation. |_none_ |serializers[X].config |A `Map` containing `MessageSerializer` specific configurations. |_none_ |ssl.enabled |Determines if SSL is turned on or not. |false -|ssl.keyCertChainFile |The X.509 certificate chain file in PEM format.|_none_ -|ssl.keyFile |The `PKCS#8` private key file in PEM format.|_none_ -|ssl.keyPassword |The password of the `keyFile` if it is password-protected. |_none_ |ssl.keyStore |The private key in JKS or PKCS#12 format. |_none_ |ssl.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ |ssl.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default) |_none_ |ssl.needClientAuth | Optional. One of NONE, OPTIONAL, REQUIRE. Enables client certificate authentication at the enforcement level specified. Can be used in combination with Authenticator. |_none_ |ssl.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |ssl.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ -|ssl.trustCertChainFile | Required when needClientAuth is OPTIONAL or REQUIRE. Trusted certificates for verifying the remote endpoint's certificate. The file should contain an X.509 certificate chain in PEM format. |_none_ |ssl.trustStore |Required when needClientAuth is OPTIONAL or REQUIRE. Trusted certificates for verifying the remote endpoint's certificate. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ |ssl.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_ |strictTransactionManagement |Set to `true` to require `aliases` to be submitted on every requests, where the `aliases` become the scope of transaction management. |false 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 6e4ef25d67f..7ae8d2d250a 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 @@ -569,11 +569,11 @@ public final static class Builder { 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 String keyStore = null; + private String keyStorePassword = null; + private String trustStore = null; + private String trustStorePassword = null; + private String keyStoreType = null; private List sslEnabledProtocols = new ArrayList<>(); private List sslCipherSuites = new ArrayList<>(); private boolean sslSkipCertValidation = false; @@ -655,9 +655,8 @@ public Builder sslContext(final SslContext sslContext) { /** * 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 + * SSL is enabled, the default {@link TrustManager} will be used. + * @deprecated As of release 3.2.10, replaced by {@link trustStore} */ @Deprecated public Builder trustCertificateChainFile(final String certificateChainFile) { @@ -677,7 +676,7 @@ public Builder keepAliveInterval(final long keepAliveInterval) { /** * The X.509 certificate chain file in PEM format. - * @deprecated + * @deprecated As of release 3.2.10, replaced by {@link keyStore} */ @Deprecated public Builder keyCertChainFile(final String keyCertChainFile) { @@ -687,7 +686,7 @@ public Builder keyCertChainFile(final String keyCertChainFile) { /** * The PKCS#8 private key file in PEM format. - * @deprecated + * @deprecated As of release 3.2.10, replaced by {@link keyStore} */ @Deprecated public Builder keyFile(final String keyFile) { @@ -697,7 +696,7 @@ public Builder keyFile(final String keyFile) { /** * The password of the {@link #keyFile}, or {@code null} if it's not password-protected. - * @deprecated + * @deprecated As of release 3.2.10, replaced by {@link keyStorePassword} */ @Deprecated public Builder keyPassword(final String keyPassword) { @@ -706,7 +705,7 @@ public Builder keyPassword(final String keyPassword) { } /** - * + * The file location of the private key in JKS or PKCS#12 format. */ public Builder keyStore(final String keyStore) { this.keyStore = keyStore; @@ -714,7 +713,7 @@ public Builder keyStore(final String keyStore) { } /** - * + * The password of the {@link #keyStore}, or {@code null} if it's not password-protected. */ public Builder keyStorePassword(final String keyStorePassword) { this.keyStorePassword = keyStorePassword; @@ -722,7 +721,8 @@ public Builder keyStorePassword(final String keyStorePassword) { } /** - * + * The file location for a SSL Certificate Chain to use when SSL is enabled. If + * this value is not provided and SSL is enabled, the default {@link TrustManager} will be used. */ public Builder trustStore(final String trustStore) { this.trustStore = trustStore; @@ -730,7 +730,7 @@ public Builder trustStore(final String trustStore) { } /** - * + * The password of the {@link #trustStore}, or {@code null} if it's not password-protected. */ public Builder trustStorePassword(final String trustStorePassword) { this.trustStorePassword = trustStorePassword; @@ -738,7 +738,7 @@ public Builder trustStorePassword(final String trustStorePassword) { } /** - * + * The format of the {@link keyStore}, either {@code JKS} or {@code PKCS12} */ public Builder keyStoreType(final String keyStoreType) { this.keyStoreType = keyStoreType; @@ -746,7 +746,9 @@ public Builder keyStoreType(final String keyStoreType) { } /** - * + * A list of SSL protocols to enable. @see JSSE + * Protocols */ public Builder sslEnabledProtocols(final List sslEnabledProtocols) { this.sslEnabledProtocols = sslEnabledProtocols; @@ -754,7 +756,9 @@ public Builder sslEnabledProtocols(final List sslEnabledProtocols) { } /** - * + * A list of cipher suites to enable. @see Cipher + * Suites */ public Builder sslCipherSuites(final List sslCipherSuites) { this.sslCipherSuites = sslCipherSuites; @@ -762,7 +766,7 @@ public Builder sslCipherSuites(final List sslCipherSuites) { } /** - * + * If true, trust all certificates and do not perform any validation. */ public Builder sslSkipCertValidation(final boolean sslSkipCertValidation) { this.sslSkipCertValidation = sslSkipCertValidation; 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 4d54792d6ce..fedd337a334 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 @@ -258,28 +258,28 @@ static class ConnectionPoolSettings { /** * The trusted certificate in PEM format. - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link trustStore} */ @Deprecated public String trustCertChainFile = null; /** * The X.509 certificate chain file in PEM format. - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link keyStore} */ @Deprecated public String keyCertChainFile = null; /** * The PKCS#8 private key file in PEM format. - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link keyStore} */ @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 As of release 3.2.10, replaced by {@link keyStorePassword} */ @Deprecated public String keyPassword = null; @@ -329,7 +329,7 @@ static class ConnectionPoolSettings { public List sslCipherSuites = new ArrayList<>(); /** - * + * If true, trust all certificates and do not perform any validation. */ public boolean sslSkipCertValidation = false; 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 c918f8b13ee..4acfea0a7f6 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 @@ -51,6 +51,8 @@ import java.util.ServiceLoader; import java.util.UUID; +import javax.net.ssl.TrustManager; + /** * Server settings as configured by a YAML file. * @@ -457,7 +459,7 @@ public static class SslSettings { /** * The X.509 certificate chain file in PEM format. * - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link keyStore} */ @Deprecated public String keyCertChainFile = null; @@ -465,7 +467,7 @@ public static class SslSettings { /** * The PKCS#8 private key file in PEM format. * - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link keyStore} */ @Deprecated public String keyFile = null; @@ -474,7 +476,7 @@ public static class SslSettings { * The password of the {@link #keyFile}, or {@code null} if it's not * password-protected. * - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link keyStorePassword} */ @Deprecated public String keyPassword = null; @@ -484,48 +486,48 @@ public static class SslSettings { * file should contain an X.509 certificate chain in PEM format. {@code null} * uses the system default. * - * @deprecated Use JSSE-based settings + * @deprecated As of release 3.2.10, replaced by {@link trustStore} */ @Deprecated public String trustCertChainFile = null; /** - * JSSE keystore file path. Similar to setting JSSE property - * {@code javax.net.ssl.keyStore}. + * The file location of the private key in JKS or PKCS#12 format. */ public String keyStore; /** - * JSSE keystore password. Similar to setting JSSE property - * {@code javax.net.ssl.keyStorePassword}. + * The password of the {@link #keyStore}, or {@code null} if it's not password-protected. */ public String keyStorePassword; /** - * JSSE truststore file path. Similar to setting JSSE property - * {@code javax.net.ssl.trustStore}. + * Trusted certificates for verifying the remote client's certificate. If + * this value is not provided and SSL is enabled, the default {@link TrustManager} will be used. */ public String trustStore; /** - * JSSE truststore password. Similar to setting JSSE property - * {@code javax.net.ssl.trustStorePassword}. + * The password of the {@link #trustStore}, or {@code null} if it's not password-protected. */ public String trustStorePassword; /** - * JSSE keystore format. Similar to setting JSSE property - * {@code javax.net.ssl.keyStoreType}. + * The format of the {@link keyStore}, either {@code JKS} or {@code PKCS12} */ public String keyStoreType; /** - * @see JSSE Protocols + * A list of SSL protocols to enable. @see JSSE + * Protocols */ public List sslEnabledProtocols = new ArrayList<>(); /** - * @see Cipher Suites + * A list of cipher suites to enable. @see Cipher + * Suites */ public List sslCipherSuites = new ArrayList<>(); From b77c0c7b55866bbbddd8d721142118b53fcfe154 Mon Sep 17 00:00:00 2001 From: Robert Dale Date: Fri, 17 Aug 2018 17:35:41 -0400 Subject: [PATCH 7/7] TINKERPOP-2023 updated docs with creating self-signed cert, incorrect ssl configuration will prevent server from starting removed OPTIONAL from needClientAuth --- .../reference/gremlin-applications.asciidoc | 59 +++++++++++++++---- .../gremlin/server/AbstractChannelizer.java | 16 +++-- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index 8372a8ae768..1cd99642eb4 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -1155,10 +1155,10 @@ The following table describes the various configuration options that Gremlin Ser |ssl.keyStore |The private key in JKS or PKCS#12 format. |_none_ |ssl.keyStorePassword |The password of the `keyStore` if it is password-protected. |_none_ |ssl.keyStoreType |`JKS` (Java 8 default) or `PKCS12` (Java 9+ default) |_none_ -|ssl.needClientAuth | Optional. One of NONE, OPTIONAL, REQUIRE. Enables client certificate authentication at the enforcement level specified. Can be used in combination with Authenticator. |_none_ +|ssl.needClientAuth | Optional. One of NONE, REQUIRE. Enables client certificate authentication at the enforcement level specified. Can be used in combination with Authenticator. |_none_ |ssl.sslCipherSuites |The list of JSSE ciphers to support for SSL connections. If specified, only the ciphers that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ |ssl.sslEnabledProtocols |The list of SSL protocols to support for SSL connections. If specified, only the protocols that are listed and supported will be enabled. If not specified, the JVM default is used. |_none_ -|ssl.trustStore |Required when needClientAuth is OPTIONAL or REQUIRE. Trusted certificates for verifying the remote endpoint's certificate. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ +|ssl.trustStore |Required when needClientAuth is REQUIRE. Trusted certificates for verifying the remote endpoint's certificate. If this value is not provided and SSL is enabled, the default `TrustManager` will be used. |_none_ |ssl.trustStorePassword |The password of the `trustStore` if it is password-protected |_none_ |strictTransactionManagement |Set to `true` to require `aliases` to be submitted on every requests, where the `aliases` become the scope of transaction management. |false |threadPoolBoss |The number of threads available to Gremlin Server for accepting connections. Should always be set to `1`. |1 @@ -1249,7 +1249,47 @@ authentication: { ===== Quick Start A quick way to get started with the `SimpleAuthenticator` is to use TinkerGraph for the "credentials graph" and the -"sample" credential graph that is packaged with the server. +"sample" credential graph that is packaged with the server. To secure the transport for the credentials, +SSL should be enabled. For this Quick Start, a self-signed certificate will be created but this should not +be used in a production environment. + +Generate the self-signed SSL certificate: + +[source,text] +---- +$ keytool -genkey -alias localhost -keyalg RSA -keystore server.jks +Enter keystore password: +Re-enter new password: +What is your first and last name? + [Unknown]: localhost +What is the name of your organizational unit? + [Unknown]: +What is the name of your organization? + [Unknown]: +What is the name of your City or Locality? + [Unknown]: +What is the name of your State or Province? + [Unknown]: +What is the two-letter country code for this unit? + [Unknown]: +Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct? + [no]: yes + +Enter key password for + (RETURN if same as keystore password): +---- + +Next, uncomment the `keyStore` and `keyStorePassword` lines in `conf/gremlin-server-secure.yaml`. + +[source,yaml] +---- +ssl: { + enabled: true, + sslEnabledProtocols: [TLSv1.2], + keyStore: server.jks, + keyStorePassword: changeit +} +---- [source,text] ---- @@ -1261,7 +1301,6 @@ $ bin/gremlin-server.sh conf/gremlin-server-secure.yaml [INFO] GremlinServer - Configuring Gremlin Server from conf/gremlin-server-secure.yaml ... -[WARN] AbstractChannelizer - Enabling SSL with self-signed certificate (NOT SUITABLE FOR PRODUCTION) [INFO] AbstractChannelizer - SSL enabled [INFO] SimpleAuthenticator - Initializing authentication with the org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator [INFO] SimpleAuthenticator - CredentialGraph initialized at CredentialGraph{graph=tinkergraph[vertices:1 edges:0]} @@ -1269,19 +1308,18 @@ $ bin/gremlin-server.sh conf/gremlin-server-secure.yaml [INFO] GremlinServer$1 - Channel started at port 8182. ---- -In addition to configuring the authenticator, `gremlin-server-secure.yaml` also enables SSL with a self-signed -certificate. As SSL is enabled on the server it must also be enabled on the client when connecting. To connect to -Gremlin Server with `gremlin-driver`, set the `credentials` and `enableSsl` when constructing the `Cluster`. +As SSL is enabled on the server it must also be enabled on the client when connecting. To connect to +Gremlin Server with `gremlin-driver`, set the `credentials`, `enableSsl`, and `trustStore` when constructing the `Cluster`. [source,java] Cluster cluster = Cluster.build().credentials("stephen", "password") - .enableSsl(true).create(); + .enableSsl(true).trustStore("server.jks").create(); If connecting with Gremlin Console, which utilizes `gremlin-driver` for remote script execution, use the provided `conf/remote-secure.yaml` file when defining the remote. That file contains configuration for the username and -password as well as enablement of SSL from the client side. +password as well as enablement of SSL from the client side. Be sure to configure the trustStore if using self-signed certificates. -Similarly, Gremlin Server can be configured for REST and security. +Similarly, Gremlin Server can be configured for REST and security. Follow the steps above for configuring the SSL certificate. [source,text] ---- @@ -1293,7 +1331,6 @@ $ bin/gremlin-server.sh conf/gremlin-server-rest-secure.yaml [INFO] GremlinServer - Configuring Gremlin Server from conf/gremlin-server-secure.yaml ... -[WARN] AbstractChannelizer - Enabling SSL with self-signed certificate (NOT SUITABLE FOR PRODUCTION) [INFO] AbstractChannelizer - SSL enabled [INFO] SimpleAuthenticator - Initializing authentication with the org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator [INFO] SimpleAuthenticator - CredentialGraph initialized at CredentialGraph{graph=tinkergraph[vertices:1 edges:0]} 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 2a29fec4144..d7f3ec1b8e3 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 @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.server; import io.netty.channel.EventLoopGroup; +import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; @@ -305,6 +306,8 @@ private SslContext createSSLContext(final Settings settings) { keystore.load(in, password); } kmf.init(keystore, password); + } else { + throw new IllegalStateException("keyStore must be configured when SSL is enabled."); } builder = SslContextBuilder.forServer(kmf); @@ -323,8 +326,8 @@ private SslContext createSSLContext(final Settings settings) { } } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) { - logger.error("There was an error enabling SSL.", e); - return null; + logger.error(e.getMessage()); + throw new RuntimeException("There was an error enabling SSL.", e); } } @@ -336,14 +339,19 @@ private SslContext createSSLContext(final Settings settings) { if (null != sslSettings.sslEnabledProtocols && !sslSettings.sslEnabledProtocols.isEmpty()) { builder.protocols(sslSettings.sslEnabledProtocols.toArray(new String[] {})); } + + if (null != sslSettings.needClientAuth && ClientAuth.OPTIONAL == sslSettings.needClientAuth) { + logger.warn("needClientAuth = OPTIONAL is not a secure configuration. Setting to REQUIRE."); + sslSettings.needClientAuth = ClientAuth.REQUIRE; + } builder.clientAuth(sslSettings.needClientAuth).sslProvider(provider); try { return builder.build(); } catch (SSLException ssle) { - logger.error("There was an error enabling SSL", ssle); - return null; + logger.error(ssle.getMessage()); + throw new RuntimeException("There was an error enabling SSL.", ssle); } } }