This closes #1834
This commit is contained in:
commit
9c40a514f2
|
@ -33,6 +33,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
@ -40,6 +41,7 @@ import java.util.concurrent.Executor;
|
|||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
@ -49,6 +51,7 @@ import javax.security.auth.login.LoginContext;
|
|||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
|
@ -90,13 +93,13 @@ import io.netty.handler.codec.http.HttpVersion;
|
|||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.util.AttributeKey;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import io.netty.util.ResourceLeakDetector.Level;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||
|
||||
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
||||
|
@ -216,6 +219,8 @@ public class NettyConnector extends AbstractConnector {
|
|||
|
||||
private String enabledProtocols;
|
||||
|
||||
private String sslProvider;
|
||||
|
||||
private boolean verifyHost;
|
||||
|
||||
private boolean trustAll;
|
||||
|
@ -354,6 +359,8 @@ public class NettyConnector extends AbstractConnector {
|
|||
|
||||
trustAll = ConfigurationHelper.getBooleanProperty(TransportConstants.TRUST_ALL_PROP_NAME, TransportConstants.DEFAULT_TRUST_ALL, configuration);
|
||||
|
||||
sslProvider = ConfigurationHelper.getStringProperty(TransportConstants.SSL_PROVIDER, TransportConstants.DEFAULT_SSL_PROVIDER, configuration);
|
||||
|
||||
sniHost = ConfigurationHelper.getStringProperty(TransportConstants.SNIHOST_PROP_NAME, TransportConstants.DEFAULT_SNIHOST_CONFIG, configuration);
|
||||
|
||||
kerb5Config = ConfigurationHelper.getStringProperty(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, TransportConstants.DEFAULT_SSL_KRB5_CONFIG, configuration);
|
||||
|
@ -484,67 +491,30 @@ public class NettyConnector extends AbstractConnector {
|
|||
bootstrap.option(ChannelOption.SO_REUSEADDR, true);
|
||||
channelGroup = new DefaultChannelGroup("activemq-connector", GlobalEventExecutor.INSTANCE);
|
||||
|
||||
final SSLContext context;
|
||||
final String realKeyStorePath;
|
||||
final String realKeyStoreProvider;
|
||||
final String realKeyStorePassword;
|
||||
final String realTrustStorePath;
|
||||
final String realTrustStoreProvider;
|
||||
final String realTrustStorePassword;
|
||||
|
||||
if (sslEnabled) {
|
||||
try {
|
||||
if (useDefaultSslContext) {
|
||||
context = SSLContext.getDefault();
|
||||
} else {
|
||||
// HORNETQ-680 - override the server-side config if client-side system properties are set
|
||||
String realKeyStorePath = keyStorePath;
|
||||
String realKeyStoreProvider = keyStoreProvider;
|
||||
String realKeyStorePassword = keyStorePassword;
|
||||
if (System.getProperty(JAVAX_KEYSTORE_PATH_PROP_NAME) != null) {
|
||||
realKeyStorePath = System.getProperty(JAVAX_KEYSTORE_PATH_PROP_NAME);
|
||||
}
|
||||
if (System.getProperty(JAVAX_KEYSTORE_PASSWORD_PROP_NAME) != null) {
|
||||
realKeyStorePassword = System.getProperty(JAVAX_KEYSTORE_PASSWORD_PROP_NAME);
|
||||
}
|
||||
// HORNETQ-680 - override the server-side config if client-side system properties are set
|
||||
|
||||
if (System.getProperty(ACTIVEMQ_KEYSTORE_PROVIDER_PROP_NAME) != null) {
|
||||
realKeyStoreProvider = System.getProperty(ACTIVEMQ_KEYSTORE_PROVIDER_PROP_NAME);
|
||||
}
|
||||
if (System.getProperty(ACTIVEMQ_KEYSTORE_PATH_PROP_NAME) != null) {
|
||||
realKeyStorePath = System.getProperty(ACTIVEMQ_KEYSTORE_PATH_PROP_NAME);
|
||||
}
|
||||
if (System.getProperty(ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME) != null) {
|
||||
realKeyStorePassword = System.getProperty(ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME);
|
||||
}
|
||||
realKeyStorePath = Stream.of(System.getProperty(JAVAX_KEYSTORE_PATH_PROP_NAME), System.getProperty(ACTIVEMQ_KEYSTORE_PATH_PROP_NAME), keyStorePath).map(v -> useDefaultSslContext ? keyStorePath : v).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
realKeyStorePassword = Stream.of(System.getProperty(JAVAX_KEYSTORE_PASSWORD_PROP_NAME), System.getProperty(ACTIVEMQ_KEYSTORE_PASSWORD_PROP_NAME), keyStorePassword).map(v -> useDefaultSslContext ? keyStorePassword : v).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
realKeyStoreProvider = Stream.of(System.getProperty(ACTIVEMQ_KEYSTORE_PROVIDER_PROP_NAME), keyStoreProvider).map(v -> useDefaultSslContext ? keyStoreProvider : v).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
|
||||
String realTrustStorePath = trustStorePath;
|
||||
String realTrustStoreProvider = trustStoreProvider;
|
||||
String realTrustStorePassword = trustStorePassword;
|
||||
if (System.getProperty(JAVAX_TRUSTSTORE_PATH_PROP_NAME) != null) {
|
||||
realTrustStorePath = System.getProperty(JAVAX_TRUSTSTORE_PATH_PROP_NAME);
|
||||
}
|
||||
if (System.getProperty(JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME) != null) {
|
||||
realTrustStorePassword = System.getProperty(JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME);
|
||||
}
|
||||
|
||||
if (System.getProperty(ACTIVEMQ_TRUSTSTORE_PROVIDER_PROP_NAME) != null) {
|
||||
realTrustStoreProvider = System.getProperty(ACTIVEMQ_TRUSTSTORE_PROVIDER_PROP_NAME);
|
||||
}
|
||||
if (System.getProperty(ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME) != null) {
|
||||
realTrustStorePath = System.getProperty(ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME);
|
||||
}
|
||||
if (System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME) != null) {
|
||||
realTrustStorePassword = System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME);
|
||||
}
|
||||
context = SSLSupport.createContext(realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword, trustAll, crlPath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
close();
|
||||
IllegalStateException ise = new IllegalStateException("Unable to create NettyConnector for " + host + ":" + port);
|
||||
ise.initCause(e);
|
||||
throw ise;
|
||||
}
|
||||
realTrustStorePath = Stream.of(System.getProperty(JAVAX_TRUSTSTORE_PATH_PROP_NAME), System.getProperty(ACTIVEMQ_TRUSTSTORE_PATH_PROP_NAME), trustStorePath).map(v -> useDefaultSslContext ? trustStorePath : v).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
realTrustStorePassword = Stream.of(System.getProperty(JAVAX_TRUSTSTORE_PASSWORD_PROP_NAME), System.getProperty(ACTIVEMQ_TRUSTSTORE_PASSWORD_PROP_NAME), trustStorePassword).map(v -> useDefaultSslContext ? trustStorePassword : v).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
realTrustStoreProvider = Stream.of(System.getProperty(ACTIVEMQ_TRUSTSTORE_PROVIDER_PROP_NAME), trustStoreProvider).map(v -> useDefaultSslContext ? trustStoreProvider : v).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
} else {
|
||||
context = null; // Unused
|
||||
}
|
||||
|
||||
if (context != null && useServlet) {
|
||||
// TODO: Fix me
|
||||
//bootstrap.setOption("sslContext", context);
|
||||
realKeyStorePath = null;
|
||||
realKeyStoreProvider = null;
|
||||
realKeyStorePassword = null;
|
||||
realTrustStorePath = null;
|
||||
realTrustStoreProvider = null;
|
||||
realTrustStorePassword = null;
|
||||
}
|
||||
|
||||
bootstrap.handler(new ChannelInitializer<Channel>() {
|
||||
|
@ -553,25 +523,13 @@ public class NettyConnector extends AbstractConnector {
|
|||
final ChannelPipeline pipeline = channel.pipeline();
|
||||
if (sslEnabled && !useServlet) {
|
||||
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null) {
|
||||
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
verifyHost = true;
|
||||
SSLEngine engine;
|
||||
if (sslProvider.equals(TransportConstants.OPENSSL_PROVIDER)) {
|
||||
engine = loadOpenSslEngine(channel.alloc(), realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword);
|
||||
} else {
|
||||
engine = loadJdkSslEngine(useDefaultSslContext, realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword);
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.createSSLEngine(sniHost != null ? sniHost : host, port);
|
||||
} else {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
engine.setUseClientMode(true);
|
||||
|
||||
engine.setWantClientAuth(true);
|
||||
|
@ -640,7 +598,72 @@ public class NettyConnector extends AbstractConnector {
|
|||
|
||||
batchFlusherFuture = scheduledThreadPool.scheduleWithFixedDelay(flusher, batchDelay, batchDelay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
ActiveMQClientLogger.LOGGER.startedNettyConnector(connectorType, TransportConstants.NETTY_VERSION, host, port);
|
||||
ActiveMQClientLogger.LOGGER.startedNettyConnector(connectorType, TransportConstants.NETTY_VERSION, host, port);
|
||||
}
|
||||
|
||||
private SSLEngine loadJdkSslEngine(boolean useDefaultSslContext,
|
||||
String realKeyStoreProvider,
|
||||
String realKeyStorePath,
|
||||
String realKeyStorePassword,
|
||||
String realTrustStoreProvider,
|
||||
String realTrustStorePath,
|
||||
String realTrustStorePassword) throws Exception {
|
||||
SSLContext context;
|
||||
if (useDefaultSslContext) {
|
||||
context = SSLContext.getDefault();
|
||||
} else {
|
||||
context = SSLSupport.createContext(realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword, trustAll, crlPath);
|
||||
}
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null) {
|
||||
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
verifyHost = true;
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.createSSLEngine(host, port);
|
||||
} else {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
}
|
||||
});
|
||||
return engine;
|
||||
}
|
||||
|
||||
private SSLEngine loadOpenSslEngine(ByteBufAllocator alloc,
|
||||
String realKeyStoreProvider,
|
||||
String realKeyStorePath,
|
||||
String realKeyStorePassword,
|
||||
String realTrustStoreProvider,
|
||||
String realTrustStorePath,
|
||||
String realTrustStorePassword) throws Exception {
|
||||
|
||||
SslContext context = SSLSupport.createNettyContext(realKeyStoreProvider, realKeyStorePath, realKeyStorePassword, realTrustStoreProvider, realTrustStorePath, realTrustStorePassword, sslProvider);
|
||||
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null) {
|
||||
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
verifyHost = true;
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.newEngine(alloc, sniHost != null ? sniHost : host, port);
|
||||
} else {
|
||||
return context.newEngine(alloc);
|
||||
}
|
||||
}
|
||||
});
|
||||
return engine;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -113,6 +113,8 @@ public class TransportConstants {
|
|||
|
||||
public static final String USE_DEFAULT_SSL_CONTEXT_PROP_NAME = "useDefaultSslContext";
|
||||
|
||||
public static final String SSL_PROVIDER = "sslProvider";
|
||||
|
||||
public static final String NETTY_VERSION;
|
||||
|
||||
/**
|
||||
|
@ -201,6 +203,10 @@ public class TransportConstants {
|
|||
|
||||
public static final boolean DEFAULT_VERIFY_HOST = false;
|
||||
|
||||
public static final String DEFAULT_SSL_PROVIDER = "JDK";
|
||||
|
||||
public static final String OPENSSL_PROVIDER = "OPENSSL";
|
||||
|
||||
public static final boolean DEFAULT_TRUST_ALL = false;
|
||||
|
||||
public static final boolean DEFAULT_USE_DEFAULT_SSL_CONTEXT = false;
|
||||
|
@ -316,6 +322,7 @@ public class TransportConstants {
|
|||
allowableAcceptorKeys.add(TransportConstants.BACKLOG_PROP_NAME);
|
||||
allowableAcceptorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
|
||||
allowableAcceptorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
|
||||
allowableAcceptorKeys.add(TransportConstants.SSL_PROVIDER);
|
||||
|
||||
ALLOWABLE_ACCEPTOR_KEYS = Collections.unmodifiableSet(allowableAcceptorKeys);
|
||||
|
||||
|
@ -361,6 +368,7 @@ public class TransportConstants {
|
|||
allowableConnectorKeys.add(ActiveMQDefaultConfiguration.getPropPasswordCodec());
|
||||
allowableConnectorKeys.add(TransportConstants.NETTY_CONNECT_TIMEOUT);
|
||||
allowableConnectorKeys.add(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME);
|
||||
allowableConnectorKeys.add(TransportConstants.SSL_PROVIDER);
|
||||
allowableConnectorKeys.add(TransportConstants.HANDSHAKE_TIMEOUT);
|
||||
allowableConnectorKeys.add(TransportConstants.CRL_PATH_PROP_NAME);
|
||||
|
||||
|
|
|
@ -16,14 +16,6 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.remoting.impl.ssl;
|
||||
|
||||
import java.security.Security;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.util.Collection;
|
||||
import javax.net.ssl.CertPathTrustManagerParameters;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
|
@ -37,12 +29,24 @@ import java.net.MalformedURLException;
|
|||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.SecureRandom;
|
||||
import org.apache.activemq.artemis.utils.ClassloadingUtil;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
|
||||
import org.apache.activemq.artemis.utils.ClassloadingUtil;
|
||||
|
||||
/**
|
||||
* Please note, this class supports PKCS#11 keystores, but there are no specific tests in the ActiveMQ Artemis test-suite to
|
||||
|
@ -99,6 +103,21 @@ public class SSLSupport {
|
|||
return context;
|
||||
}
|
||||
|
||||
public static SslContext createNettyContext(final String keystoreProvider,
|
||||
final String keystorePath,
|
||||
final String keystorePassword,
|
||||
final String trustStoreProvider,
|
||||
final String trustStorePath,
|
||||
final String trustStorePassword,
|
||||
final String sslProvider) throws Exception {
|
||||
|
||||
KeyStore keyStore = SSLSupport.loadKeystore(keystoreProvider, keystorePath, keystorePassword);
|
||||
String alias = keyStore.aliases().nextElement();
|
||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, keystorePassword.toCharArray());
|
||||
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(alias);
|
||||
return SslContextBuilder.forServer(privateKey, certificate).sslProvider(SslProvider.valueOf(sslProvider)).trustManager(SSLSupport.loadTrustManagerFactory(trustStoreProvider, trustStorePath, trustStorePassword, false, null)).build();
|
||||
}
|
||||
|
||||
public static String[] parseCommaSeparatedListIntoArray(String suites) {
|
||||
String[] cipherSuites = suites.split(",");
|
||||
for (int i = 0; i < cipherSuites.length; i++) {
|
||||
|
@ -120,15 +139,14 @@ public class SSLSupport {
|
|||
}
|
||||
|
||||
// Private -------------------------------------------------------
|
||||
|
||||
private static TrustManager[] loadTrustManager(final String trustStoreProvider,
|
||||
final String trustStorePath,
|
||||
final String trustStorePassword,
|
||||
final boolean trustAll,
|
||||
final String crlPath) throws Exception {
|
||||
private static TrustManagerFactory loadTrustManagerFactory(final String trustStoreProvider,
|
||||
final String trustStorePath,
|
||||
final String trustStorePassword,
|
||||
final boolean trustAll,
|
||||
final String crlPath) throws Exception {
|
||||
if (trustAll) {
|
||||
//This is useful for testing but not should be used outside of that purpose
|
||||
return InsecureTrustManagerFactory.INSTANCE.getTrustManagers();
|
||||
return InsecureTrustManagerFactory.INSTANCE;
|
||||
} else if (trustStorePath == null && (trustStoreProvider == null || !"PKCS11".equals(trustStoreProvider.toUpperCase()))) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -153,12 +171,22 @@ public class SSLSupport {
|
|||
if (!initialized) {
|
||||
trustMgrFactory.init(trustStore);
|
||||
}
|
||||
|
||||
return trustMgrFactory.getTrustManagers();
|
||||
|
||||
return trustMgrFactory;
|
||||
}
|
||||
}
|
||||
|
||||
private static TrustManager[] loadTrustManager(final String trustStoreProvider,
|
||||
final String trustStorePath,
|
||||
final String trustStorePassword,
|
||||
final boolean trustAll,
|
||||
final String crlPath) throws Exception {
|
||||
TrustManagerFactory trustManagerFactory = loadTrustManagerFactory(trustStoreProvider, trustStorePath, trustStorePassword, trustAll, crlPath);
|
||||
if (trustManagerFactory == null) {
|
||||
return null;
|
||||
}
|
||||
return trustManagerFactory.getTrustManagers();
|
||||
}
|
||||
|
||||
private static Collection<? extends CRL> loadCRL(String crlPath) throws Exception {
|
||||
if (crlPath == null) {
|
||||
return null;
|
||||
|
@ -196,14 +224,24 @@ public class SSLSupport {
|
|||
private static KeyManager[] loadKeyManagers(final String keyStoreProvider,
|
||||
final String keystorePath,
|
||||
final String keystorePassword) throws Exception {
|
||||
|
||||
KeyManagerFactory factory = loadKeyManagerFactory(keyStoreProvider, keystorePath, keystorePassword);
|
||||
if (factory == null) {
|
||||
return null;
|
||||
}
|
||||
return factory.getKeyManagers();
|
||||
}
|
||||
|
||||
private static KeyManagerFactory loadKeyManagerFactory(final String keyStoreProvider,
|
||||
final String keystorePath,
|
||||
final String keystorePassword) throws Exception {
|
||||
if (keystorePath == null && (keyStoreProvider == null || !"PKCS11".equals(keyStoreProvider.toUpperCase()))) {
|
||||
return null;
|
||||
} else {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
KeyStore ks = SSLSupport.loadKeystore(keyStoreProvider, keystorePath, keystorePassword);
|
||||
kmf.init(ks, keystorePassword == null ? null : keystorePassword.toCharArray());
|
||||
|
||||
return kmf.getKeyManagers();
|
||||
return kmf;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
@ -63,6 +64,7 @@ import io.netty.channel.local.LocalAddress;
|
|||
import io.netty.channel.local.LocalServerChannel;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
|
@ -164,6 +166,8 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
|
||||
private final boolean needClientAuth;
|
||||
|
||||
private final String sslProvider;
|
||||
|
||||
private final boolean verifyHost;
|
||||
|
||||
private final String kerb5Config;
|
||||
|
@ -270,6 +274,8 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
needClientAuth = ConfigurationHelper.getBooleanProperty(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, TransportConstants.DEFAULT_NEED_CLIENT_AUTH, configuration);
|
||||
|
||||
verifyHost = ConfigurationHelper.getBooleanProperty(TransportConstants.VERIFY_HOST_PROP_NAME, TransportConstants.DEFAULT_VERIFY_HOST, configuration);
|
||||
|
||||
sslProvider = ConfigurationHelper.getStringProperty(TransportConstants.SSL_PROVIDER, TransportConstants.DEFAULT_SSL_PROVIDER, configuration);
|
||||
} else {
|
||||
keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER;
|
||||
keyStorePath = TransportConstants.DEFAULT_KEYSTORE_PATH;
|
||||
|
@ -282,6 +288,7 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
enabledProtocols = TransportConstants.DEFAULT_ENABLED_PROTOCOLS;
|
||||
needClientAuth = TransportConstants.DEFAULT_NEED_CLIENT_AUTH;
|
||||
verifyHost = TransportConstants.DEFAULT_VERIFY_HOST;
|
||||
sslProvider = TransportConstants.DEFAULT_SSL_PROVIDER;
|
||||
}
|
||||
|
||||
tcpNoDelay = ConfigurationHelper.getBooleanProperty(TransportConstants.TCP_NODELAY_PROPNAME, TransportConstants.DEFAULT_TCP_NODELAY, configuration);
|
||||
|
@ -364,7 +371,7 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
public void initChannel(Channel channel) throws Exception {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
if (sslEnabled) {
|
||||
pipeline.addLast("ssl", getSslHandler());
|
||||
pipeline.addLast("ssl", getSslHandler(channel.alloc()));
|
||||
pipeline.addLast("sslHandshakeExceptionHandler", new SslHandshakeExceptionHandler());
|
||||
}
|
||||
pipeline.addLast(protocolHandler.getProtocolDecoder());
|
||||
|
@ -451,36 +458,13 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
startServerChannels();
|
||||
}
|
||||
|
||||
public synchronized SslHandler getSslHandler() throws Exception {
|
||||
final SSLContext context;
|
||||
try {
|
||||
if (kerb5Config == null && keyStorePath == null && TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER.equals(keyStoreProvider))
|
||||
throw new IllegalArgumentException("If \"" + TransportConstants.SSL_ENABLED_PROP_NAME +
|
||||
"\" is true then \"" + TransportConstants.KEYSTORE_PATH_PROP_NAME + "\" must be non-null " +
|
||||
"unless an alternative \"" + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME + "\" has been specified.");
|
||||
context = SSLSupport.createContext(keyStoreProvider, keyStorePath, keyStorePassword, trustStoreProvider, trustStorePath, trustStorePassword, crlPath);
|
||||
} catch (Exception e) {
|
||||
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
|
||||
ise.initCause(e);
|
||||
throw ise;
|
||||
public synchronized SslHandler getSslHandler(ByteBufAllocator alloc) throws Exception {
|
||||
SSLEngine engine;
|
||||
if (sslProvider.equals(TransportConstants.OPENSSL_PROVIDER)) {
|
||||
engine = loadOpenSslEngine(alloc);
|
||||
} else {
|
||||
engine = loadJdkSslEngine();
|
||||
}
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null) {
|
||||
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.createSSLEngine(host, port);
|
||||
} else {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
engine.setUseClientMode(false);
|
||||
|
||||
|
@ -539,6 +523,68 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
return new SslHandler(engine);
|
||||
}
|
||||
|
||||
private SSLEngine loadJdkSslEngine() throws Exception {
|
||||
final SSLContext context;
|
||||
try {
|
||||
if (kerb5Config == null && keyStorePath == null && TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER.equals(keyStoreProvider))
|
||||
throw new IllegalArgumentException("If \"" + TransportConstants.SSL_ENABLED_PROP_NAME + "\" is true then \"" + TransportConstants.KEYSTORE_PATH_PROP_NAME + "\" must be non-null " + "unless an alternative \"" + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME + "\" has been specified.");
|
||||
context = SSLSupport.createContext(keyStoreProvider, keyStorePath, keyStorePassword, trustStoreProvider, trustStorePath, trustStorePassword, crlPath);
|
||||
} catch (Exception e) {
|
||||
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
|
||||
ise.initCause(e);
|
||||
throw ise;
|
||||
}
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null) {
|
||||
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.createSSLEngine(host, port);
|
||||
} else {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
}
|
||||
});
|
||||
return engine;
|
||||
}
|
||||
|
||||
private SSLEngine loadOpenSslEngine(ByteBufAllocator alloc) throws Exception {
|
||||
final SslContext context;
|
||||
try {
|
||||
if (kerb5Config == null && keyStorePath == null && TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER.equals(keyStoreProvider))
|
||||
throw new IllegalArgumentException("If \"" + TransportConstants.SSL_ENABLED_PROP_NAME + "\" is true then \"" + TransportConstants.KEYSTORE_PATH_PROP_NAME + "\" must be non-null " + "unless an alternative \"" + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME + "\" has been specified.");
|
||||
context = SSLSupport.createNettyContext(keyStoreProvider, keyStorePath, keyStorePassword, trustStoreProvider, trustStorePath, trustStorePassword, sslProvider);
|
||||
} catch (Exception e) {
|
||||
IllegalStateException ise = new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
|
||||
ise.initCause(e);
|
||||
throw ise;
|
||||
}
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null) {
|
||||
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.newEngine(alloc, host, port);
|
||||
} else {
|
||||
return context.newEngine(alloc);
|
||||
}
|
||||
}
|
||||
});
|
||||
return engine;
|
||||
}
|
||||
|
||||
private void startServerChannels() {
|
||||
String[] hosts = TransportConfiguration.splitHosts(host);
|
||||
for (String h : hosts) {
|
||||
|
|
|
@ -433,6 +433,16 @@ following additional properties:
|
|||
|
||||
Valid values are `true` or `false`. Default is `false`.
|
||||
|
||||
- `sslProvider`
|
||||
|
||||
Used to change the SSL Provider between `JDK` and `OPENSSL`. The default is `JDK`.
|
||||
If used with `OPENSSL` you can add `netty-tcnative` to your classpath to use the native
|
||||
installed openssl. This can be useful if you want to use special ciphersuite - elliptic curve combinations
|
||||
which are support through openssl but not through the JDK provider. See https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations
|
||||
for more information's.
|
||||
|
||||
|
||||
|
||||
## Configuring Netty HTTP
|
||||
|
||||
Netty HTTP tunnels packets over the HTTP protocol. It can be useful in
|
||||
|
|
Loading…
Reference in New Issue