You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/06/04 14:37:07 UTC
[2/6] incubator-tinkerpop git commit: Simplified the SSL
configuration for Gremlin Server.
Simplified the SSL configuration for Gremlin Server.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/21033372
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/21033372
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/21033372
Branch: refs/heads/master
Commit: 21033372db8535eef89e7e42a5595ec7cda19c50
Parents: 3027d6f
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Jun 4 07:50:40 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Jun 4 07:51:05 2015 -0400
----------------------------------------------------------------------
.../gremlin/server/AbstractChannelizer.java | 90 ++++++++++----------
.../tinkerpop/gremlin/server/Settings.java | 35 ++++++--
2 files changed, 73 insertions(+), 52 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/21033372/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/AbstractChannelizer.java
index baa4551..2970dac 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
@@ -18,6 +18,13 @@
*/
package org.apache.tinkerpop.gremlin.server;
+import io.netty.handler.codec.spdy.SpdyOrHttpChooser;
+import io.netty.handler.ssl.ApplicationProtocolConfig;
+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 org.apache.ivy.util.FileUtil;
import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
import org.apache.tinkerpop.gremlin.server.handler.IteratorHandler;
@@ -26,19 +33,19 @@ import org.apache.tinkerpop.gremlin.server.handler.OpSelectorHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.ssl.SslHandler;
import org.javatuples.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.TrustManager;
+import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
+import java.nio.file.Files;
import java.security.KeyStore;
+import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@@ -61,7 +68,7 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
private static final Logger logger = LoggerFactory.getLogger(AbstractChannelizer.class);
protected Settings settings;
protected GremlinExecutor gremlinExecutor;
- protected Optional<SSLEngine> sslEngine;
+ protected Optional<SslContext> sslContext;
protected Graphs graphs;
protected ExecutorService gremlinExecutorService;
protected ScheduledExecutorService scheduledExecutorService;
@@ -105,7 +112,10 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
// and fail the server startup
configureSerializers();
- this.sslEngine = settings.optionalSsl().isPresent() && settings.ssl.enabled ? Optional.ofNullable(createSslEngine()) : Optional.empty();
+ // configure ssl if present
+ sslContext = settings.optionalSsl().isPresent() && settings.ssl.enabled ?
+ Optional.ofNullable(createSSLContext(settings)) : Optional.empty();
+ if (sslContext.isPresent()) logger.info("SSL enabled");
// these handlers don't share any state and can thus be initialized once per pipeline
this.opSelectorHandler = new OpSelectorHandler(settings, graphs, gremlinExecutor, scheduledExecutorService);
@@ -117,7 +127,7 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
public void initChannel(final SocketChannel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
- sslEngine.ifPresent(ssl -> pipeline.addLast(PIPELINE_SSL, new SslHandler(ssl)));
+ if (sslContext.isPresent()) pipeline.addLast(PIPELINE_SSL, sslContext.get().newHandler(ch.alloc()));
// the implementation provides the method by which Gremlin Server will process requests. the end of the
// pipeline must decode to an incoming RequestMessage instances and encode to a outgoing ResponseMessage
@@ -155,7 +165,7 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
}).filter(Optional::isPresent).map(Optional::get).flatMap(serializer ->
Stream.of(serializer.mimeTypesSupported()).map(mimeType -> Pair.with(mimeType, serializer))
).forEach(pair -> {
- final String mimeType = pair.getValue0().toString();
+ final String mimeType = pair.getValue0();
final MessageSerializer serializer = pair.getValue1();
if (serializers.containsKey(mimeType))
logger.warn("{} already has {} configured. It will not be replaced by {}. Check configuration for serializer duplication or other issues.",
@@ -172,46 +182,40 @@ public abstract class AbstractChannelizer extends ChannelInitializer<SocketChann
}
}
- private SSLEngine createSslEngine() {
- try {
- logger.info("SSL was enabled. Initializing SSLEngine instance...");
- final SSLEngine engine = createSSLContext(settings).createSSLEngine();
- engine.setUseClientMode(false);
- logger.info("SSLEngine was properly configured and initialized.");
- return engine;
- } catch (Exception ex) {
- logger.warn("SSL could not be enabled. Check the ssl section of the configuration file.", ex);
- return null;
- }
- }
-
- private SSLContext createSSLContext(final Settings settings) throws Exception {
+ private SslContext createSSLContext(final Settings settings) {
final Settings.SslSettings sslSettings = settings.ssl;
+ final SslProvider provider = SslProvider.JDK;
- TrustManager[] managers = null;
- if (sslSettings.trustStoreFile != null) {
- final KeyStore ts = KeyStore.getInstance(Optional.ofNullable(sslSettings.trustStoreFormat).orElseThrow(() -> new IllegalStateException("The trustStoreFormat is not set")));
- try (final InputStream trustStoreInputStream = new FileInputStream(Optional.ofNullable(sslSettings.trustStoreFile).orElseThrow(() -> new IllegalStateException("The trustStoreFile is not set")))) {
- ts.load(trustStoreInputStream, sslSettings.trustStorePassword.toCharArray());
- }
+ final SslContextBuilder builder;
- final String trustStoreAlgorithm = Optional.ofNullable(sslSettings.trustStoreAlgorithm).orElse(TrustManagerFactory.getDefaultAlgorithm());
- final TrustManagerFactory tmf = TrustManagerFactory.getInstance(trustStoreAlgorithm);
- tmf.init(ts);
- managers = tmf.getTrustManagers();
- }
-
- final KeyStore ks = KeyStore.getInstance(Optional.ofNullable(sslSettings.keyStoreFormat).orElseThrow(() -> new IllegalStateException("The keyStoreFormat is not set")));
- try (final InputStream keyStoreInputStream = new FileInputStream(Optional.ofNullable(sslSettings.keyStoreFile).orElseThrow(() -> new IllegalStateException("The keyStoreFile is not set")))) {
- ks.load(keyStoreInputStream, sslSettings.keyStorePassword.toCharArray());
+ // 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 {
+ 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
+ // trustManager is also ok (default will be used)
+ builder = SslContextBuilder.forServer(keyCertChainFile, keyFile, sslSettings.keyPassword)
+ .trustManager(trustCertChainFile);
}
- final String keyManagerAlgorithm = Optional.ofNullable(sslSettings.keyManagerAlgorithm).orElse(KeyManagerFactory.getDefaultAlgorithm());
- final KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyManagerAlgorithm);
- kmf.init(ks, Optional.ofNullable(sslSettings.keyManagerPassword).orElseThrow(() -> new IllegalStateException("The keyManagerPassword is not set")).toCharArray());
+ builder.sslProvider(provider);
- final SSLContext serverContext = SSLContext.getInstance("TLS");
- serverContext.init(kmf.getKeyManagers(), managers, null);
- return serverContext;
+ try {
+ return builder.build();
+ } catch (SSLException ssle) {
+ logger.error("There was an error enabling SSL", ssle);
+ return null;
+ }
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/21033372/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Settings.java
index c878b5a..4f3cb2c 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
@@ -277,16 +277,33 @@ public class Settings {
* Settings to configure SSL support.
*/
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}.
+ */
public boolean enabled = false;
- public String keyManagerAlgorithm = "SunX509";
- public String keyStoreFormat = "JKS";
- public String keyStoreFile = null;
- public String keyStorePassword = null;
- public String keyManagerPassword = null;
- public String trustStoreFile = null;
- public String trustStoreFormat = null;
- public String trustStorePassword = null;
- public String trustStoreAlgorithm = null;
+
+ /**
+ * The X.509 certificate chain file in PEM format.
+ */
+ public String keyCertChainFile = null;
+
+ /**
+ * The PKCS#8 private key file in PEM format.
+ */
+ public String keyFile = null;
+
+ /**
+ * The password of the {@link #keyFile}, or {@code null} if it's not password-protected
+ */
+ 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.
+ */
+ public String trustCertChainFile = null;
}
/**