Repository: cassandra Updated Branches: refs/heads/trunk f109f200a -> 11496039f
Correct and clarify SSLFactory.getSslContext method and call sites patch by Dinesh Joshi; reviewed by jasobrown for CASSANDRA-14314 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/11496039 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/11496039 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/11496039 Branch: refs/heads/trunk Commit: 11496039fb18bb45407246602e31740c56d28157 Parents: f109f20 Author: Dinesh A. Joshi <dinesh.jo...@apple.com> Authored: Sat Mar 17 17:17:42 2018 -0700 Committer: Jason Brown <jasedbr...@gmail.com> Committed: Thu Mar 22 06:38:56 2018 -0700 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/config/DatabaseDescriptor.java | 6 +- .../cassandra/config/EncryptionOptions.java | 35 +++++ .../apache/cassandra/net/MessagingService.java | 6 +- .../cassandra/net/async/NettyFactory.java | 6 +- .../cassandra/net/async/OptionalSslHandler.java | 2 +- .../apache/cassandra/security/SSLFactory.java | 154 +++++++++++-------- .../service/NativeTransportService.java | 3 +- .../streaming/DefaultConnectionFactory.java | 2 +- .../org/apache/cassandra/transport/Server.java | 7 +- .../cassandra/transport/SimpleClient.java | 5 +- .../cassandra/net/MessagingServiceTest.java | 8 +- .../async/OutboundMessagingConnectionTest.java | 7 +- .../cassandra/security/SSLFactoryTest.java | 46 +++++- .../service/NativeTransportServiceTest.java | 13 +- 15 files changed, 194 insertions(+), 107 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index c092a9f..f86a380 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0 + * Correct and clarify SSLFactory.getSslContext method and call sites (CASSANDRA-14314) * Use zero as default score in DynamicEndpointSnitch (CASSANDRA-14252) * Handle static and partition deletion properly on ThrottledUnfilteredIterator (CASSANDRA-14315) * NodeTool clientstats should show SSL Cipher (CASSANDRA-14322) http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/config/DatabaseDescriptor.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 2e772c5..bf00d40 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -2005,17 +2005,17 @@ public class DatabaseDescriptor conf.dynamic_snitch_badness_threshold = dynamicBadnessThreshold; } - public static EncryptionOptions.ServerEncryptionOptions getServerEncryptionOptions() + public static EncryptionOptions.ServerEncryptionOptions getInternodeMessagingEncyptionOptions() { return conf.server_encryption_options; } - public static void setServerEncryptionOptions(EncryptionOptions.ServerEncryptionOptions encryptionOptions) + public static void setInternodeMessagingEncyptionOptions(EncryptionOptions.ServerEncryptionOptions encryptionOptions) { conf.server_encryption_options = encryptionOptions; } - public static EncryptionOptions getClientEncryptionOptions() + public static EncryptionOptions getNativeProtocolEncryptionOptions() { return conf.client_encryption_options; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/config/EncryptionOptions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/EncryptionOptions.java b/src/java/org/apache/cassandra/config/EncryptionOptions.java index 5260dff..45579fb 100644 --- a/src/java/org/apache/cassandra/config/EncryptionOptions.java +++ b/src/java/org/apache/cassandra/config/EncryptionOptions.java @@ -17,6 +17,9 @@ */ package org.apache.cassandra.config; +import java.util.Arrays; +import java.util.Objects; + public class EncryptionOptions { public String keystore = "conf/.keystore"; @@ -54,6 +57,38 @@ public class EncryptionOptions optional = options.optional; } + @Override + public boolean equals(Object o) + { + if (o == this) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + EncryptionOptions opt = (EncryptionOptions)o; + return Objects.equals(keystore, opt.keystore) && + Objects.equals(truststore, opt.truststore) && + Objects.equals(algorithm, opt.algorithm) && + Objects.equals(protocol, opt.protocol) && + Arrays.equals(cipher_suites, opt.cipher_suites) && + require_client_auth == opt.require_client_auth && + require_endpoint_verification == opt.require_endpoint_verification; + } + + @Override + public int hashCode() + { + int result = 0; + result += 31 * (keystore == null ? 0 : keystore.hashCode()); + result += 31 * (truststore == null ? 0 : truststore.hashCode()); + result += 31 * (algorithm == null ? 0 : algorithm.hashCode()); + result += 31 * (protocol == null ? 0 : protocol.hashCode()); + result += 31 * Arrays.hashCode(cipher_suites); + result += 31 * Boolean.hashCode(require_client_auth); + result += 31 * Boolean.hashCode(require_endpoint_verification); + return result; + } + public static class ServerEncryptionOptions extends EncryptionOptions { public enum InternodeEncryption http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/net/MessagingService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/net/MessagingService.java b/src/java/org/apache/cassandra/net/MessagingService.java index 573cf7d..c6ef986 100644 --- a/src/java/org/apache/cassandra/net/MessagingService.java +++ b/src/java/org/apache/cassandra/net/MessagingService.java @@ -737,7 +737,7 @@ public final class MessagingService implements MessagingServiceMBean public void listen() { - listen(DatabaseDescriptor.getServerEncryptionOptions()); + listen(DatabaseDescriptor.getInternodeMessagingEncyptionOptions()); } public void listen(ServerEncryptionOptions serverEncryptionOptions) @@ -1606,7 +1606,7 @@ public final class MessagingService implements MessagingServiceMBean InetAddressAndPort preferredRemote = SystemKeyspace.getPreferredIP(to); InetAddressAndPort local = FBUtilities.getLocalAddressAndPort(); - ServerEncryptionOptions encryptionOptions = secure ? DatabaseDescriptor.getServerEncryptionOptions() : null; + ServerEncryptionOptions encryptionOptions = secure ? DatabaseDescriptor.getInternodeMessagingEncyptionOptions() : null; IInternodeAuthenticator authenticator = DatabaseDescriptor.getInternodeAuthenticator(); pool = new OutboundMessagingPool(preferredRemote, local, encryptionOptions, backPressure.newState(to), authenticator); @@ -1656,7 +1656,7 @@ public final class MessagingService implements MessagingServiceMBean public static boolean isEncryptedConnection(InetAddressAndPort address) { IEndpointSnitch snitch = DatabaseDescriptor.getEndpointSnitch(); - switch (DatabaseDescriptor.getServerEncryptionOptions().internode_encryption) + switch (DatabaseDescriptor.getInternodeMessagingEncyptionOptions().internode_encryption) { case none: return false; // if nothing needs to be encrypted then return immediately. http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/net/async/NettyFactory.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/net/async/NettyFactory.java b/src/java/org/apache/cassandra/net/async/NettyFactory.java index d891043..86ed4e7 100644 --- a/src/java/org/apache/cassandra/net/async/NettyFactory.java +++ b/src/java/org/apache/cassandra/net/async/NettyFactory.java @@ -122,7 +122,7 @@ public final class NettyFactory NettyFactory(boolean useEpoll) { this.useEpoll = useEpoll; - acceptGroup = getEventLoopGroup(useEpoll, determineAcceptGroupSize(DatabaseDescriptor.getServerEncryptionOptions()), + acceptGroup = getEventLoopGroup(useEpoll, determineAcceptGroupSize(DatabaseDescriptor.getInternodeMessagingEncyptionOptions()), "MessagingService-NettyAcceptor-Thread", false); inboundGroup = getEventLoopGroup(useEpoll, FBUtilities.getAvailableProcessors(), "MessagingService-NettyInbound-Thread", false); outboundGroup = getEventLoopGroup(useEpoll, FBUtilities.getAvailableProcessors(), "MessagingService-NettyOutbound-Thread", true); @@ -287,7 +287,7 @@ public final class NettyFactory } else { - SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, true, true); + SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, true, SSLFactory.ConnectionType.INTERNODE_MESSAGING, SSLFactory.SocketType.SERVER); InetSocketAddress peer = encryptionOptions.require_endpoint_verification ? channel.remoteAddress() : null; SslHandler sslHandler = newSslHandler(channel, sslContext, peer); logger.trace("creating inbound netty SslContext: context={}, engine={}", sslContext.getClass().getName(), sslHandler.engine().getClass().getName()); @@ -362,7 +362,7 @@ public final class NettyFactory // order of handlers: ssl -> logger -> handshakeHandler if (params.encryptionOptions != null) { - SslContext sslContext = SSLFactory.getSslContext(params.encryptionOptions, true, false); + SslContext sslContext = SSLFactory.getSslContext(params.encryptionOptions, true, SSLFactory.ConnectionType.INTERNODE_MESSAGING, SSLFactory.SocketType.CLIENT); // for some reason channel.remoteAddress() will return null InetAddressAndPort address = params.connectionId.remote(); InetSocketAddress peer = params.encryptionOptions.require_endpoint_verification ? new InetSocketAddress(address.address, address.port) : null; http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java b/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java index b60ae13..d57518c 100644 --- a/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java +++ b/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java @@ -51,7 +51,7 @@ public class OptionalSslHandler extends ByteToMessageDecoder if (SslHandler.isEncrypted(in)) { // Connection uses SSL/TLS, replace the detection handler with a SslHandler and so use encryption. - SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, true, true); + SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, true, SSLFactory.ConnectionType.INTERNODE_MESSAGING, SSLFactory.SocketType.SERVER); Channel channel = ctx.channel(); InetSocketAddress peer = encryptionOptions.require_endpoint_verification ? (InetSocketAddress) channel.remoteAddress() : null; SslHandler sslHandler = NettyFactory.newSslHandler(channel, sslContext, peer); http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/security/SSLFactory.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/security/SSLFactory.java b/src/java/org/apache/cassandra/security/SSLFactory.java index 395ea42..d64dded 100644 --- a/src/java/org/apache/cassandra/security/SSLFactory.java +++ b/src/java/org/apache/cassandra/security/SSLFactory.java @@ -30,9 +30,9 @@ import java.util.Arrays; import java.util.Date; import java.util.Enumeration; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; @@ -54,33 +54,47 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.SupportedCipherSuiteFilter; +import io.netty.util.ReferenceCountUtil; import org.apache.cassandra.concurrent.ScheduledExecutors; import org.apache.cassandra.config.EncryptionOptions; /** * A Factory for providing and setting up client {@link SSLSocket}s. Also provides * methods for creating both JSSE {@link SSLContext} instances as well as netty {@link SslContext} instances. - * + * <p> * Netty {@link SslContext} instances are expensive to create (as well as to destroy) and consume a lof of resources * (especially direct memory), but instances can be reused across connections (assuming the SSL params are the same). - * Hence we cache created instances in {@link #clientSslContext} and {@link #serverSslContext}. + * Hence we cache created instances in {@link #cachedSslContexts}. */ public final class SSLFactory { private static final Logger logger = LoggerFactory.getLogger(SSLFactory.class); - @VisibleForTesting - static volatile boolean checkedExpiry = false; + /** + * Indicator if a connection is shared with a client application ({@link ConnectionType#NATIVE_TRANSPORT}) + * or another cassandra node ({@link ConnectionType#INTERNODE_MESSAGING}). + */ + public enum ConnectionType + { + NATIVE_TRANSPORT, INTERNODE_MESSAGING + } /** - * A cached reference of the {@link SslContext} for client-facing connections. + * Indicates if the process holds the inbound/listening end of the socket ({@link SocketType#SERVER})), or the + * outbound side ({@link SocketType#CLIENT}). */ - private static final AtomicReference<SslContext> clientSslContext = new AtomicReference<>(); + public enum SocketType + { + SERVER, CLIENT + } + + @VisibleForTesting + static volatile boolean checkedExpiry = false; /** - * A cached reference of the {@link SslContext} for peer-to-peer, internode messaging connections. + * Cached references of SSL Contexts */ - private static final AtomicReference<SslContext> serverSslContext = new AtomicReference<>(); + private static final ConcurrentHashMap<CacheKey, SslContext> cachedSslContexts = new ConcurrentHashMap<>(); /** * List of files that trigger hot reloading of SSL certificates @@ -107,21 +121,13 @@ public final class SSLFactory */ private static class HotReloadableFile { - enum Type - { - SERVER, - CLIENT - } - private final File file; private volatile long lastModTime; - private final Type certType; - HotReloadableFile(String path, Type type) + HotReloadableFile(String path) { file = new File(path); lastModTime = file.lastModified(); - certType = type; } boolean shouldReload() @@ -131,16 +137,6 @@ public final class SSLFactory lastModTime = curModTime; return result; } - - public boolean isServer() - { - return certType == Type.SERVER; - } - - public boolean isClient() - { - return certType == Type.CLIENT; - } } /** @@ -172,7 +168,7 @@ public final class SSLFactory try (InputStream tsf = Files.newInputStream(Paths.get(options.truststore))) { TrustManagerFactory tmf = TrustManagerFactory.getInstance( - options.algorithm == null ? TrustManagerFactory.getDefaultAlgorithm() : options.algorithm); + options.algorithm == null ? TrustManagerFactory.getDefaultAlgorithm() : options.algorithm); KeyStore ts = KeyStore.getInstance(options.store_type); ts.load(tsf, options.truststore_password.toCharArray()); tmf.init(ts); @@ -189,7 +185,7 @@ public final class SSLFactory try (InputStream ksf = Files.newInputStream(Paths.get(options.keystore))) { KeyManagerFactory kmf = KeyManagerFactory.getInstance( - options.algorithm == null ? KeyManagerFactory.getDefaultAlgorithm() : options.algorithm); + options.algorithm == null ? KeyManagerFactory.getDefaultAlgorithm() : options.algorithm); KeyStore ks = KeyStore.getInstance(options.store_type); ks.load(ksf, options.keystore_password.toCharArray()); if (!checkedExpiry) @@ -233,26 +229,41 @@ public final class SSLFactory /** * get a netty {@link SslContext} instance */ - public static SslContext getSslContext(EncryptionOptions options, boolean buildTruststore, boolean forServer) throws IOException + public static SslContext getSslContext(EncryptionOptions options, boolean buildTruststore, ConnectionType connectionType, + SocketType socketType) throws IOException { - return getSslContext(options, buildTruststore, forServer, OpenSsl.isAvailable()); + return getSslContext(options, buildTruststore, connectionType, socketType, OpenSsl.isAvailable()); } /** * Get a netty {@link SslContext} instance. */ @VisibleForTesting - static SslContext getSslContext(EncryptionOptions options, boolean buildTruststore, boolean forServer, boolean useOpenSsl) throws IOException + static SslContext getSslContext(EncryptionOptions options, boolean buildTruststore, ConnectionType connectionType, + SocketType socketType, boolean useOpenSsl) throws IOException { - + CacheKey key = new CacheKey(options, connectionType, socketType); SslContext sslContext; - if (forServer && (sslContext = serverSslContext.get()) != null) + sslContext = cachedSslContexts.get(key); + if (sslContext != null) return sslContext; - if (!forServer && (sslContext = clientSslContext.get()) != null) + sslContext = createNettySslContext(options, buildTruststore, connectionType, socketType, useOpenSsl); + SslContext previous = cachedSslContexts.putIfAbsent(key, sslContext); + if (previous == null) return sslContext; + ReferenceCountUtil.release(sslContext); + return previous; + } + + /** + * Create a Netty {@link SslContext} + */ + static SslContext createNettySslContext(EncryptionOptions options, boolean buildTruststore, ConnectionType connectionType, + SocketType socketType, boolean useOpenSsl) throws IOException + { /* There is a case where the netty/openssl combo might not support using KeyManagerFactory. specifically, I've seen this with the netty-tcnative dynamic openssl implementation. using the netty-tcnative static-boringssl @@ -261,12 +272,9 @@ public final class SSLFactory {@link SslContextBuilder#forServer(File, File, String)}). However, we are not supporting that now to keep the config/yaml API simple. */ - KeyManagerFactory kmf = null; - if (forServer || options.require_client_auth) - kmf = buildKeyManagerFactory(options); - + KeyManagerFactory kmf = buildKeyManagerFactory(options); SslContextBuilder builder; - if (forServer) + if (socketType == SocketType.SERVER) { builder = SslContextBuilder.forServer(kmf); builder.clientAuth(options.require_client_auth ? ClientAuth.REQUIRE : ClientAuth.NONE); @@ -286,19 +294,14 @@ public final class SSLFactory if (buildTruststore) builder.trustManager(buildTrustManagerFactory(options)); - SslContext ctx = builder.build(); - AtomicReference<SslContext> ref = forServer ? serverSslContext : clientSslContext; - if (ref.compareAndSet(null, ctx)) - return ctx; - - return ref.get(); + return builder.build(); } /** * Performs a lightweight check whether the certificate files have been refreshed. * * @throws IllegalStateException if {@link #initHotReloading(EncryptionOptions.ServerEncryptionOptions, EncryptionOptions, boolean)} - * is not called first + * is not called first */ public static void checkCertFilesForHotReloading() { @@ -307,16 +310,10 @@ public final class SSLFactory logger.trace("Checking whether certificates have been updated"); - if (hotReloadableFiles.stream().anyMatch(f -> f.isServer() && f.shouldReload())) - { - logger.info("Server ssl certificates have been updated. Reseting the context for new peer connections."); - serverSslContext.set(null); - } - - if (hotReloadableFiles.stream().anyMatch(f -> f.isClient() && f.shouldReload())) + if (hotReloadableFiles.stream().anyMatch(HotReloadableFile::shouldReload)) { - logger.info("Client ssl certificates have been updated. Reseting the context for new client connections."); - clientSslContext.set(null); + logger.info("SSL certificates have been updated. Reseting the ssl contexts for new connections."); + cachedSslContexts.clear(); } } @@ -339,14 +336,14 @@ public final class SSLFactory if (serverEncryptionOptions.enabled) { - fileList.add(new HotReloadableFile(serverEncryptionOptions.keystore, HotReloadableFile.Type.SERVER)); - fileList.add(new HotReloadableFile(serverEncryptionOptions.truststore, HotReloadableFile.Type.SERVER)); + fileList.add(new HotReloadableFile(serverEncryptionOptions.keystore)); + fileList.add(new HotReloadableFile(serverEncryptionOptions.truststore)); } if (clientEncryptionOptions.enabled) { - fileList.add(new HotReloadableFile(clientEncryptionOptions.keystore, HotReloadableFile.Type.CLIENT)); - fileList.add(new HotReloadableFile(clientEncryptionOptions.truststore, HotReloadableFile.Type.CLIENT)); + fileList.add(new HotReloadableFile(clientEncryptionOptions.keystore)); + fileList.add(new HotReloadableFile(clientEncryptionOptions.truststore)); } hotReloadableFiles = ImmutableList.copyOf(fileList); @@ -360,4 +357,37 @@ public final class SSLFactory isHotReloadingInitialized = true; } + + static class CacheKey + { + private final EncryptionOptions encryptionOptions; + private final ConnectionType connectionType; + private final SocketType socketType; + + public CacheKey(EncryptionOptions encryptionOptions, ConnectionType connectionType, SocketType socketType) + { + this.encryptionOptions = encryptionOptions; + this.connectionType = connectionType; + this.socketType = socketType; + } + + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CacheKey cacheKey = (CacheKey) o; + return (connectionType == cacheKey.connectionType && + socketType == cacheKey.socketType && + Objects.equals(encryptionOptions, cacheKey.encryptionOptions)); + } + + public int hashCode() + { + int result = 0; + result += 31 * connectionType.hashCode(); + result += 31 * socketType.hashCode(); + result += 31 * encryptionOptions.hashCode(); + return result; + } + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/service/NativeTransportService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/NativeTransportService.java b/src/java/org/apache/cassandra/service/NativeTransportService.java index cec9b2b..d70e56e 100644 --- a/src/java/org/apache/cassandra/service/NativeTransportService.java +++ b/src/java/org/apache/cassandra/service/NativeTransportService.java @@ -29,7 +29,6 @@ import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -92,7 +91,7 @@ public class NativeTransportService .withEventLoopGroup(workerGroup) .withHost(nativeAddr); - if (!DatabaseDescriptor.getClientEncryptionOptions().enabled) + if (!DatabaseDescriptor.getNativeProtocolEncryptionOptions().enabled) { servers = Collections.singleton(builder.withSSL(false).withPort(nativePort).build()); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/streaming/DefaultConnectionFactory.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/streaming/DefaultConnectionFactory.java b/src/java/org/apache/cassandra/streaming/DefaultConnectionFactory.java index d9ed8be..609d2a0 100644 --- a/src/java/org/apache/cassandra/streaming/DefaultConnectionFactory.java +++ b/src/java/org/apache/cassandra/streaming/DefaultConnectionFactory.java @@ -49,7 +49,7 @@ public class DefaultConnectionFactory implements StreamConnectionFactory @Override public Channel createConnection(OutboundConnectionIdentifier connectionId, int protocolVersion) throws IOException { - ServerEncryptionOptions encryptionOptions = DatabaseDescriptor.getServerEncryptionOptions(); + ServerEncryptionOptions encryptionOptions = DatabaseDescriptor.getInternodeMessagingEncyptionOptions(); if (encryptionOptions.internode_encryption == ServerEncryptionOptions.InternodeEncryption.none) encryptionOptions = null; http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/transport/Server.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/transport/Server.java b/src/java/org/apache/cassandra/transport/Server.java index 0f666d8..7aade66 100644 --- a/src/java/org/apache/cassandra/transport/Server.java +++ b/src/java/org/apache/cassandra/transport/Server.java @@ -24,8 +24,6 @@ import java.net.UnknownHostException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -140,7 +138,7 @@ public class Server implements CassandraDaemon.Server if (this.useSSL) { - final EncryptionOptions clientEnc = DatabaseDescriptor.getClientEncryptionOptions(); + final EncryptionOptions clientEnc = DatabaseDescriptor.getNativeProtocolEncryptionOptions(); if (clientEnc.optional) { @@ -407,7 +405,8 @@ public class Server implements CassandraDaemon.Server protected final SslHandler createSslHandler(ByteBufAllocator allocator) throws IOException { - SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, encryptionOptions.require_client_auth, true); + SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, encryptionOptions.require_client_auth, + SSLFactory.ConnectionType.NATIVE_TRANSPORT, SSLFactory.SocketType.SERVER); return sslContext.newHandler(allocator); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/src/java/org/apache/cassandra/transport/SimpleClient.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/transport/SimpleClient.java b/src/java/org/apache/cassandra/transport/SimpleClient.java index 07463e2..db7de8d 100644 --- a/src/java/org/apache/cassandra/transport/SimpleClient.java +++ b/src/java/org/apache/cassandra/transport/SimpleClient.java @@ -52,12 +52,10 @@ import org.apache.cassandra.transport.messages.PrepareMessage; import org.apache.cassandra.transport.messages.QueryMessage; import org.apache.cassandra.transport.messages.ResultMessage; import org.apache.cassandra.transport.messages.StartupMessage; -import org.apache.cassandra.utils.MD5Digest; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; -import io.netty.handler.ssl.SslHandler; public class SimpleClient implements Closeable { @@ -283,7 +281,8 @@ public class SimpleClient implements Closeable protected void initChannel(Channel channel) throws Exception { super.initChannel(channel); - SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, encryptionOptions.require_client_auth, true); + SslContext sslContext = SSLFactory.getSslContext(encryptionOptions, encryptionOptions.require_client_auth, + SSLFactory.ConnectionType.NATIVE_TRANSPORT, SSLFactory.SocketType.CLIENT); channel.pipeline().addFirst("ssl", sslContext.newHandler(channel.alloc())); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/test/unit/org/apache/cassandra/net/MessagingServiceTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/net/MessagingServiceTest.java b/test/unit/org/apache/cassandra/net/MessagingServiceTest.java index 4ce3422..c3ebe32 100644 --- a/test/unit/org/apache/cassandra/net/MessagingServiceTest.java +++ b/test/unit/org/apache/cassandra/net/MessagingServiceTest.java @@ -22,7 +22,6 @@ package org.apache.cassandra.net; import java.io.IOException; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collections; @@ -48,9 +47,6 @@ import org.apache.cassandra.config.EncryptionOptions.ServerEncryptionOptions; import org.apache.cassandra.db.SystemKeyspace; import org.apache.cassandra.db.monitoring.ApproximateTime; import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.io.util.DataInputPlus.DataInputStreamPlus; -import org.apache.cassandra.io.util.DataOutputStreamPlus; -import org.apache.cassandra.io.util.WrappedDataOutputStreamPlus; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.net.MessagingService.ServerChannel; import org.apache.cassandra.net.async.NettyFactory; @@ -96,7 +92,7 @@ public class MessagingServiceTest DatabaseDescriptor.setBackPressureStrategy(new MockBackPressureStrategy(Collections.emptyMap())); DatabaseDescriptor.setBroadcastAddress(InetAddress.getByName("127.0.0.1")); originalAuthenticator = DatabaseDescriptor.getInternodeAuthenticator(); - originalServerEncryptionOptions = DatabaseDescriptor.getServerEncryptionOptions(); + originalServerEncryptionOptions = DatabaseDescriptor.getInternodeMessagingEncyptionOptions(); originalListenAddress = InetAddressAndPort.getByAddressOverrideDefaults(DatabaseDescriptor.getListenAddress(), DatabaseDescriptor.getStoragePort()); } @@ -115,7 +111,7 @@ public class MessagingServiceTest public void tearDown() { DatabaseDescriptor.setInternodeAuthenticator(originalAuthenticator); - DatabaseDescriptor.setServerEncryptionOptions(originalServerEncryptionOptions); + DatabaseDescriptor.setInternodeMessagingEncyptionOptions(originalServerEncryptionOptions); DatabaseDescriptor.setShouldListenOnBroadcastAddress(false); DatabaseDescriptor.setListenAddress(originalListenAddress.address); FBUtilities.reset(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/test/unit/org/apache/cassandra/net/async/OutboundMessagingConnectionTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/net/async/OutboundMessagingConnectionTest.java b/test/unit/org/apache/cassandra/net/async/OutboundMessagingConnectionTest.java index bf6e066..6a8dc83 100644 --- a/test/unit/org/apache/cassandra/net/async/OutboundMessagingConnectionTest.java +++ b/test/unit/org/apache/cassandra/net/async/OutboundMessagingConnectionTest.java @@ -20,7 +20,6 @@ package org.apache.cassandra.net.async; import java.io.IOException; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -88,14 +87,14 @@ public class OutboundMessagingConnectionTest omc.setChannelWriter(ChannelWriter.create(channel, omc::handleMessageResult, Optional.empty())); snitch = DatabaseDescriptor.getEndpointSnitch(); - encryptionOptions = DatabaseDescriptor.getServerEncryptionOptions(); + encryptionOptions = DatabaseDescriptor.getInternodeMessagingEncyptionOptions(); } @After public void tearDown() { DatabaseDescriptor.setEndpointSnitch(snitch); - DatabaseDescriptor.setServerEncryptionOptions(encryptionOptions); + DatabaseDescriptor.setInternodeMessagingEncyptionOptions(encryptionOptions); channel.finishAndReleaseAll(); } @@ -506,7 +505,7 @@ public class OutboundMessagingConnectionTest ServerEncryptionOptions encryptionOptions = new ServerEncryptionOptions(); encryptionOptions.enabled = true; encryptionOptions.internode_encryption = ServerEncryptionOptions.InternodeEncryption.all; - DatabaseDescriptor.setServerEncryptionOptions(encryptionOptions); + DatabaseDescriptor.setInternodeMessagingEncyptionOptions(encryptionOptions); omc = new OutboundMessagingConnection(connectionId, encryptionOptions, Optional.empty(), new AllowAllInternodeAuthenticator()); int peerVersion = MessagingService.VERSION_30; MessagingService.instance().setVersion(connectionId.remote(), MessagingService.VERSION_30); http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/test/unit/org/apache/cassandra/security/SSLFactoryTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/security/SSLFactoryTest.java b/test/unit/org/apache/cassandra/security/SSLFactoryTest.java index 5153a11..19e88de 100644 --- a/test/unit/org/apache/cassandra/security/SSLFactoryTest.java +++ b/test/unit/org/apache/cassandra/security/SSLFactoryTest.java @@ -30,7 +30,9 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.netty.handler.ssl.JdkSslContext; import io.netty.handler.ssl.OpenSsl; +import io.netty.handler.ssl.OpenSslContext; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.util.SelfSignedCertificate; import org.apache.cassandra.config.DatabaseDescriptor; @@ -93,16 +95,20 @@ public class SSLFactoryTest } EncryptionOptions options = addKeystoreOptions(encryptionOptions); - SslContext sslContext = SSLFactory.getSslContext(options, true, true, true); + SslContext sslContext = SSLFactory.getSslContext(options, true, SSLFactory.ConnectionType.NATIVE_TRANSPORT, + SSLFactory.SocketType.CLIENT, true); Assert.assertNotNull(sslContext); + Assert.assertTrue(sslContext instanceof OpenSslContext); } @Test public void getSslContext_JdkSsl() throws IOException { EncryptionOptions options = addKeystoreOptions(encryptionOptions); - SslContext sslContext = SSLFactory.getSslContext(options, true, true, false); + SslContext sslContext = SSLFactory.getSslContext(options, true, SSLFactory.ConnectionType.NATIVE_TRANSPORT, + SSLFactory.SocketType.CLIENT, false); Assert.assertNotNull(sslContext); + Assert.assertTrue(sslContext instanceof JdkSslContext); Assert.assertEquals(Arrays.asList(encryptionOptions.cipher_suites), sslContext.cipherSuites()); } @@ -113,14 +119,14 @@ public class SSLFactoryTest return options; } - @Test (expected = IOException.class) + @Test(expected = IOException.class) public void buildTrustManagerFactory_NoFile() throws IOException { encryptionOptions.truststore = "/this/is/probably/not/a/file/on/your/test/machine"; SSLFactory.buildTrustManagerFactory(encryptionOptions); } - @Test (expected = IOException.class) + @Test(expected = IOException.class) public void buildTrustManagerFactory_BadPassword() throws IOException { encryptionOptions.truststore_password = "HomeOfBadPasswords"; @@ -134,7 +140,7 @@ public class SSLFactoryTest Assert.assertNotNull(trustManagerFactory); } - @Test (expected = IOException.class) + @Test(expected = IOException.class) public void buildKeyManagerFactory_NoFile() throws IOException { EncryptionOptions options = addKeystoreOptions(encryptionOptions); @@ -142,7 +148,7 @@ public class SSLFactoryTest SSLFactory.buildKeyManagerFactory(options); } - @Test (expected = IOException.class) + @Test(expected = IOException.class) public void buildKeyManagerFactory_BadPassword() throws IOException { EncryptionOptions options = addKeystoreOptions(encryptionOptions); @@ -169,7 +175,8 @@ public class SSLFactoryTest SSLFactory.initHotReloading((ServerEncryptionOptions) options, options, true); - SslContext oldCtx = SSLFactory.getSslContext(options, true, true, OpenSsl.isAvailable()); + SslContext oldCtx = SSLFactory.getSslContext(options, true, SSLFactory.ConnectionType.NATIVE_TRANSPORT, + SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable()); File keystoreFile = new File(options.keystore); SSLFactory.checkCertFilesForHotReloading(); @@ -177,7 +184,8 @@ public class SSLFactoryTest keystoreFile.setLastModified(System.currentTimeMillis()); SSLFactory.checkCertFilesForHotReloading(); - SslContext newCtx = SSLFactory.getSslContext(options, true, true, OpenSsl.isAvailable()); + SslContext newCtx = SSLFactory.getSslContext(options, true, SSLFactory.ConnectionType.NATIVE_TRANSPORT, + SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable()); Assert.assertNotSame(oldCtx, newCtx); } @@ -190,4 +198,26 @@ public class SSLFactoryTest DatabaseDescriptor.loadConfig(); } } + + @Test + public void getSslContext_ParamChanges() throws IOException + { + EncryptionOptions options = addKeystoreOptions(encryptionOptions); + options.enabled = true; + options.cipher_suites = new String[]{ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }; + + SslContext ctx1 = SSLFactory.getSslContext(options, true, SSLFactory.ConnectionType.NATIVE_TRANSPORT, + SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable()); + + Assert.assertTrue(ctx1.isClient()); + Assert.assertArrayEquals(ctx1.cipherSuites().toArray(), options.cipher_suites); + + options.cipher_suites = new String[]{ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" }; + + SslContext ctx2 = SSLFactory.getSslContext(options, true, SSLFactory.ConnectionType.NATIVE_TRANSPORT, + SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable()); + + Assert.assertTrue(ctx2.isClient()); + Assert.assertArrayEquals(ctx2.cipherSuites().toArray(), options.cipher_suites); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/11496039/test/unit/org/apache/cassandra/service/NativeTransportServiceTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/service/NativeTransportServiceTest.java b/test/unit/org/apache/cassandra/service/NativeTransportServiceTest.java index 334a9af..c918fd6 100644 --- a/test/unit/org/apache/cassandra/service/NativeTransportServiceTest.java +++ b/test/unit/org/apache/cassandra/service/NativeTransportServiceTest.java @@ -20,7 +20,6 @@ package org.apache.cassandra.service; import java.util.Arrays; import java.util.function.BooleanSupplier; import java.util.function.Consumer; -import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -48,7 +47,7 @@ public class NativeTransportServiceTest @After public void resetConfig() { - DatabaseDescriptor.getClientEncryptionOptions().enabled = false; + DatabaseDescriptor.getNativeProtocolEncryptionOptions().enabled = false; DatabaseDescriptor.setNativeTransportPortSSL(null); } @@ -129,8 +128,8 @@ public class NativeTransportServiceTest public void testSSLOnly() { // default ssl settings: client encryption enabled and default native transport port used for ssl only - DatabaseDescriptor.getClientEncryptionOptions().enabled = true; - DatabaseDescriptor.getClientEncryptionOptions().optional = false; + DatabaseDescriptor.getNativeProtocolEncryptionOptions().enabled = true; + DatabaseDescriptor.getNativeProtocolEncryptionOptions().optional = false; withService((NativeTransportService service) -> { @@ -146,8 +145,8 @@ public class NativeTransportServiceTest public void testSSLOptional() { // default ssl settings: client encryption enabled and default native transport port used for optional ssl - DatabaseDescriptor.getClientEncryptionOptions().enabled = true; - DatabaseDescriptor.getClientEncryptionOptions().optional = true; + DatabaseDescriptor.getNativeProtocolEncryptionOptions().enabled = true; + DatabaseDescriptor.getNativeProtocolEncryptionOptions().optional = true; withService((NativeTransportService service) -> { @@ -163,7 +162,7 @@ public class NativeTransportServiceTest public void testSSLWithNonSSL() { // ssl+non-ssl settings: client encryption enabled and additional ssl port specified - DatabaseDescriptor.getClientEncryptionOptions().enabled = true; + DatabaseDescriptor.getNativeProtocolEncryptionOptions().enabled = true; DatabaseDescriptor.setNativeTransportPortSSL(8432); withService((NativeTransportService service) -> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org