This is an automated email from the ASF dual-hosted git repository.
jonmeredith pushed a commit to branch cassandra-4.1
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-4.1 by this push:
new b9586501a6 Internode legacy SSL storage port certificate is not hot
reloaded on update
b9586501a6 is described below
commit b9586501a6b6cdfe465302448018785652c9b966
Author: Jon Meredith <[email protected]>
AuthorDate: Thu Sep 21 16:07:29 2023 -0600
Internode legacy SSL storage port certificate is not hot reloaded on update
patch by Jon Meredith; reviewed by Dinesh Joshi, Francisco Guerrero for
CASSANDRA-18681
---
CHANGES.txt | 1 +
.../cassandra/net/InboundConnectionInitiator.java | 3 +-
.../org/apache/cassandra/net/InboundSockets.java | 12 +++
.../org/apache/cassandra/net/MessagingService.java | 1 +
.../cassandra/net/MessagingServiceMBeanImpl.java | 10 +-
.../cassandra/net/OutboundConnectionInitiator.java | 4 +-
.../org/apache/cassandra/security/SSLFactory.java | 82 +++++++++-------
.../cassandra/transport/PipelineConfigurator.java | 8 +-
.../apache/cassandra/transport/SimpleClient.java | 3 +-
.../test/AbstractEncryptionOptionsImpl.java | 2 +-
.../security/DefaultSslContextFactoryTest.java | 2 +-
.../security/PEMBasedSslContextFactoryTest.java | 2 +-
.../apache/cassandra/security/SSLFactoryTest.java | 107 ++++++++++++++-------
13 files changed, 153 insertions(+), 84 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index adc7860393..d902ca1e1c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
4.1.4
+ * Internode legacy SSL storage port certificate is not hot reloaded on update
(CASSANDRA-18681)
* Nodetool paxos-only repair is no longer incremental (CASSANDRA-18466)
* Waiting indefinitely on ReceivedMessage response in StreamSession#receive()
can cause deadlock (CASSANDRA-18733)
* Allow empty keystore_password in encryption_options (CASSANDRA-18778)
diff --git a/src/java/org/apache/cassandra/net/InboundConnectionInitiator.java
b/src/java/org/apache/cassandra/net/InboundConnectionInitiator.java
index 807d0262d8..3067b587c9 100644
--- a/src/java/org/apache/cassandra/net/InboundConnectionInitiator.java
+++ b/src/java/org/apache/cassandra/net/InboundConnectionInitiator.java
@@ -549,7 +549,8 @@ public class InboundConnectionInitiator
{
final boolean verifyPeerCertificate = true;
SslContext sslContext =
SSLFactory.getOrCreateSslContext(encryptionOptions, verifyPeerCertificate,
-
ISslContextFactory.SocketType.SERVER);
+
ISslContextFactory.SocketType.SERVER,
+
SSL_FACTORY_CONTEXT_DESCRIPTION);
InetSocketAddress peer =
encryptionOptions.require_endpoint_verification ? (InetSocketAddress)
channel.remoteAddress() : null;
SslHandler sslHandler = newSslHandler(channel, sslContext, peer);
logger.trace("{} inbound netty SslContext: context={}, engine={}",
description, sslContext.getClass().getName(),
sslHandler.engine().getClass().getName());
diff --git a/src/java/org/apache/cassandra/net/InboundSockets.java
b/src/java/org/apache/cassandra/net/InboundSockets.java
index 58cd88e6d9..80309aa443 100644
--- a/src/java/org/apache/cassandra/net/InboundSockets.java
+++ b/src/java/org/apache/cassandra/net/InboundSockets.java
@@ -24,6 +24,8 @@ import java.util.function.Consumer;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
@@ -43,6 +45,7 @@ import org.apache.cassandra.utils.concurrent.FutureCombiner;
class InboundSockets
{
+ private static Logger logger =
LoggerFactory.getLogger(InboundSockets.class);
/**
* A simple struct to wrap up the components needed for each listening
socket.
*/
@@ -219,6 +222,15 @@ class InboundSockets
if (settings.encryption.legacy_ssl_storage_port_enabled)
{
+ // Initialize hot reloading here rather than in
org.apache.cassandra.security.SSLFactory.initHotReloading
+ // as the legacySettings.encryption.sslContextFactory is not
shared outside the messaging system.
+ // Any SslContexts created will be checked when
checkCertFilesForHotReloading is called if initialization
+ // is successful.
+ try {
+
legacySettings.encryption.sslContextFactoryInstance.initHotReloading();
+ } catch (Throwable tr) {
+ logger.warn("Unable to initialize hot reloading for legacy
internode socket - continuing disabled", tr);
+ }
out.add(new InboundSocket(legacySettings));
/*
diff --git a/src/java/org/apache/cassandra/net/MessagingService.java
b/src/java/org/apache/cassandra/net/MessagingService.java
index f14835661e..910623aae6 100644
--- a/src/java/org/apache/cassandra/net/MessagingService.java
+++ b/src/java/org/apache/cassandra/net/MessagingService.java
@@ -213,6 +213,7 @@ public class MessagingService extends
MessagingServiceMBeanImpl
public static final int current_version = VERSION_40;
static AcceptVersions accept_messaging = new
AcceptVersions(minimum_version, current_version);
static AcceptVersions accept_streaming = new
AcceptVersions(current_version, current_version);
+ public static String SSL_FACTORY_CONTEXT_DESCRIPTION =
"server_encryption_options";
public enum Version
{
diff --git a/src/java/org/apache/cassandra/net/MessagingServiceMBeanImpl.java
b/src/java/org/apache/cassandra/net/MessagingServiceMBeanImpl.java
index b77fa8396e..3b89834a31 100644
--- a/src/java/org/apache/cassandra/net/MessagingServiceMBeanImpl.java
+++ b/src/java/org/apache/cassandra/net/MessagingServiceMBeanImpl.java
@@ -17,15 +17,12 @@
*/
package org.apache.cassandra.net;
-import java.io.IOException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.locator.InetAddressAndPort;
import org.apache.cassandra.metrics.InternodeOutboundMetrics;
import org.apache.cassandra.metrics.MessagingMetrics;
@@ -276,12 +273,9 @@ public class MessagingServiceMBeanImpl implements
MessagingServiceMBean
}
@Override
- public void reloadSslCertificates() throws IOException
+ public void reloadSslCertificates()
{
- final EncryptionOptions.ServerEncryptionOptions serverOpts =
DatabaseDescriptor.getInternodeMessagingEncyptionOptions();
- final EncryptionOptions clientOpts =
DatabaseDescriptor.getNativeProtocolEncryptionOptions();
- SSLFactory.validateSslCerts(serverOpts, clientOpts);
- SSLFactory.checkCertFilesForHotReloading(serverOpts, clientOpts);
+ SSLFactory.forceCheckCertFiles();
}
@Override
diff --git a/src/java/org/apache/cassandra/net/OutboundConnectionInitiator.java
b/src/java/org/apache/cassandra/net/OutboundConnectionInitiator.java
index a187068ce7..5de2a080d9 100644
--- a/src/java/org/apache/cassandra/net/OutboundConnectionInitiator.java
+++ b/src/java/org/apache/cassandra/net/OutboundConnectionInitiator.java
@@ -59,6 +59,7 @@ import org.apache.cassandra.utils.JVMStabilityInspector;
import org.apache.cassandra.utils.memory.BufferPools;
import static java.util.concurrent.TimeUnit.*;
+import static
org.apache.cassandra.net.MessagingService.SSL_FACTORY_CONTEXT_DESCRIPTION;
import static org.apache.cassandra.net.MessagingService.VERSION_40;
import static org.apache.cassandra.net.HandshakeProtocol.*;
import static org.apache.cassandra.net.ConnectionType.STREAMING;
@@ -203,7 +204,8 @@ public class OutboundConnectionInitiator<SuccessType
extends OutboundConnectionI
{
// check if we should actually encrypt this connection
SslContext sslContext =
SSLFactory.getOrCreateSslContext(settings.encryption, true,
-
ISslContextFactory.SocketType.CLIENT);
+
ISslContextFactory.SocketType.CLIENT,
+
SSL_FACTORY_CONTEXT_DESCRIPTION);
// for some reason channel.remoteAddress() will return null
InetAddressAndPort address = settings.to;
InetSocketAddress peer =
settings.encryption.require_endpoint_verification ? new
InetSocketAddress(address.getAddress(), address.getPort()) : null;
diff --git a/src/java/org/apache/cassandra/security/SSLFactory.java
b/src/java/org/apache/cassandra/security/SSLFactory.java
index e06da1f0cb..51bde34258 100644
--- a/src/java/org/apache/cassandra/security/SSLFactory.java
+++ b/src/java/org/apache/cassandra/security/SSLFactory.java
@@ -21,6 +21,7 @@ package org.apache.cassandra.security;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -42,7 +43,6 @@ import io.netty.handler.ssl.SslContext;
import io.netty.util.ReferenceCountUtil;
import org.apache.cassandra.concurrent.ScheduledExecutors;
import org.apache.cassandra.config.Config;
-import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.security.ISslContextFactory.SocketType;
@@ -130,9 +130,10 @@ public final class SSLFactory
* get a netty {@link SslContext} instance
*/
public static SslContext getOrCreateSslContext(EncryptionOptions options,
boolean verifyPeerCertificate,
- SocketType socketType)
throws IOException
+ SocketType socketType,
+ String contextDescription)
throws IOException
{
- CacheKey key = new CacheKey(options, socketType);
+ CacheKey key = new CacheKey(options, socketType, contextDescription);
SslContext sslContext;
sslContext = cachedSslContexts.get(key);
@@ -175,42 +176,47 @@ public final class SSLFactory
* @throws IllegalStateException if {@link
#initHotReloading(EncryptionOptions.ServerEncryptionOptions, EncryptionOptions,
boolean)}
* is not called first
*/
- public static void
checkCertFilesForHotReloading(EncryptionOptions.ServerEncryptionOptions
serverOpts,
- EncryptionOptions
clientOpts)
+ public static void checkCertFilesForHotReloading()
{
if (!isHotReloadingInitialized)
throw new IllegalStateException("Hot reloading functionality has
not been initialized.");
+ checkCachedContextsForReload(false);
+ }
- logger.debug("Checking whether certificates have been updated for
server {} and client {}",
-
serverOpts.sslContextFactoryInstance.getClass().getName(),
clientOpts.sslContextFactoryInstance.getClass().getName());
-
- if (serverOpts != null)
- {
- checkCertFilesForHotReloading(serverOpts,
"server_encryption_options", true);
- }
- if (clientOpts != null)
- {
- checkCertFilesForHotReloading(clientOpts,
"client_encryption_options", clientOpts.require_client_auth);
- }
+ /**
+ * Forces revalidation and loading of SSL certifcates if valid
+ */
+ public static void forceCheckCertFiles()
+ {
+ checkCachedContextsForReload(true);
}
- private static void checkCertFilesForHotReloading(EncryptionOptions
options, String contextDescription,
- boolean
verifyPeerCertificate)
+ private static void checkCachedContextsForReload(boolean forceReload)
{
- try
+ List<CacheKey> keysToCheck = new
ArrayList<>(Collections.list(cachedSslContexts.keys()));
+ while (!keysToCheck.isEmpty())
{
- if (options.sslContextFactoryInstance.shouldReload())
+ CacheKey key = keysToCheck.remove(keysToCheck.size()-1);
+ final EncryptionOptions opts = key.encryptionOptions;
+
+ logger.debug("Checking whether certificates have been updated for
{}", key.contextDescription);
+ if (forceReload || opts.sslContextFactoryInstance.shouldReload())
{
- logger.info("SSL certificates have been updated for {}.
Resetting the ssl contexts for new " +
- "connections.", options.getClass().getName());
- validateSslContext(contextDescription, options,
verifyPeerCertificate, false);
- clearSslContextCache(options);
+ try
+ {
+ validateSslContext(key.contextDescription, opts,
+ opts instanceof
EncryptionOptions.ServerEncryptionOptions || opts.require_client_auth, false);
+ logger.info("SSL certificates have been updated for {}.
Resetting the ssl contexts for new " +
+ "connections.", key.contextDescription);
+ clearSslContextCache(key.encryptionOptions, keysToCheck);
+ }
+ catch (Throwable tr)
+ {
+ logger.error("Failed to hot reload the SSL Certificates!
Please check the certificate files for {}.",
+ key.contextDescription, tr);
+ }
}
}
- catch(Exception e)
- {
- logger.error("Failed to hot reload the SSL Certificates! Please
check the certificate files.", e);
- }
}
/**
@@ -225,12 +231,16 @@ public final class SSLFactory
cachedSslContexts.clear();
}
- private static void clearSslContextCache(EncryptionOptions options)
+ /**
+ * Clear all cachedSslContexts with this encryption option and remove them
from future keys to check
+ */
+ private static void clearSslContextCache(EncryptionOptions options,
List<CacheKey> keysToCheck)
{
cachedSslContexts.forEachKey(1, cacheKey -> {
- if (cacheKey.encryptionOptions.equals(options))
+ if (Objects.equals(options, cacheKey.encryptionOptions))
{
cachedSslContexts.remove(cacheKey);
+ keysToCheck.remove(cacheKey);
}
});
}
@@ -261,9 +271,7 @@ public final class SSLFactory
if (!isHotReloadingInitialized)
{
ScheduledExecutors.scheduledTasks
- .scheduleWithFixedDelay(() -> checkCertFilesForHotReloading(
-
DatabaseDescriptor.getInternodeMessagingEncyptionOptions(),
-
DatabaseDescriptor.getNativeProtocolEncryptionOptions()),
+
.scheduleWithFixedDelay(SSLFactory::checkCertFilesForHotReloading,
DEFAULT_HOT_RELOAD_INITIAL_DELAY_SEC,
DEFAULT_HOT_RELOAD_PERIOD_SEC,
TimeUnit.SECONDS);
}
@@ -420,11 +428,13 @@ public final class SSLFactory
{
private final EncryptionOptions encryptionOptions;
private final SocketType socketType;
+ private final String contextDescription;
- public CacheKey(EncryptionOptions encryptionOptions, SocketType
socketType)
+ public CacheKey(EncryptionOptions encryptionOptions, SocketType
socketType, String contextDescription)
{
this.encryptionOptions = encryptionOptions;
this.socketType = socketType;
+ this.contextDescription = contextDescription;
}
public boolean equals(Object o)
@@ -433,7 +443,8 @@ public final class SSLFactory
if (o == null || getClass() != o.getClass()) return false;
CacheKey cacheKey = (CacheKey) o;
return (socketType == cacheKey.socketType &&
- Objects.equals(encryptionOptions,
cacheKey.encryptionOptions));
+ Objects.equals(encryptionOptions,
cacheKey.encryptionOptions) &&
+ Objects.equals(contextDescription,
cacheKey.contextDescription));
}
public int hashCode()
@@ -441,6 +452,7 @@ public final class SSLFactory
int result = 0;
result += 31 * socketType.hashCode();
result += 31 * encryptionOptions.hashCode();
+ result += 31 * contextDescription.hashCode();
return result;
}
}
diff --git a/src/java/org/apache/cassandra/transport/PipelineConfigurator.java
b/src/java/org/apache/cassandra/transport/PipelineConfigurator.java
index 81ff13605e..cefba02c59 100644
--- a/src/java/org/apache/cassandra/transport/PipelineConfigurator.java
+++ b/src/java/org/apache/cassandra/transport/PipelineConfigurator.java
@@ -63,6 +63,8 @@ public class PipelineConfigurator
// which will throttle a system under any normal load.
private static final boolean DEBUG =
Boolean.getBoolean("cassandra.unsafe_verbose_debug_client_protocol");
+ public static final String SSL_FACTORY_CONTEXT_DESCRIPTION =
"client_encryption_options";
+
// Stateless handlers
private static final ConnectionLimitHandler connectionLimitHandler = new
ConnectionLimitHandler();
@@ -164,7 +166,8 @@ public class PipelineConfigurator
return channel -> {
SslContext sslContext =
SSLFactory.getOrCreateSslContext(encryptionOptions,
encryptionOptions.require_client_auth,
-
ISslContextFactory.SocketType.SERVER);
+
ISslContextFactory.SocketType.SERVER,
+
SSL_FACTORY_CONTEXT_DESCRIPTION);
channel.pipeline().addFirst(SSL_HANDLER, new
ByteToMessageDecoder()
{
@@ -198,7 +201,8 @@ public class PipelineConfigurator
return channel -> {
SslContext sslContext =
SSLFactory.getOrCreateSslContext(encryptionOptions,
encryptionOptions.require_client_auth,
-
ISslContextFactory.SocketType.SERVER);
+
ISslContextFactory.SocketType.SERVER,
+
SSL_FACTORY_CONTEXT_DESCRIPTION);
channel.pipeline().addFirst(SSL_HANDLER,
sslContext.newHandler(channel.alloc()));
};
default:
diff --git a/src/java/org/apache/cassandra/transport/SimpleClient.java
b/src/java/org/apache/cassandra/transport/SimpleClient.java
index 43bb8addee..5ea0190aea 100644
--- a/src/java/org/apache/cassandra/transport/SimpleClient.java
+++ b/src/java/org/apache/cassandra/transport/SimpleClient.java
@@ -54,6 +54,7 @@ import
org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
import static org.apache.cassandra.transport.CQLMessageHandler.envelopeSize;
import static org.apache.cassandra.transport.Flusher.MAX_FRAMED_PAYLOAD_SIZE;
+import static
org.apache.cassandra.transport.PipelineConfigurator.SSL_FACTORY_CONTEXT_DESCRIPTION;
import static
org.apache.cassandra.utils.concurrent.NonBlockingRateLimiter.NO_OP_LIMITER;
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
@@ -623,7 +624,7 @@ public class SimpleClient implements Closeable
{
super.initChannel(channel);
SslContext sslContext =
SSLFactory.getOrCreateSslContext(encryptionOptions,
encryptionOptions.require_client_auth,
-
ISslContextFactory.SocketType.CLIENT);
+
ISslContextFactory.SocketType.CLIENT, SSL_FACTORY_CONTEXT_DESCRIPTION);
channel.pipeline().addFirst("ssl",
sslContext.newHandler(channel.alloc()));
}
}
diff --git
a/test/distributed/org/apache/cassandra/distributed/test/AbstractEncryptionOptionsImpl.java
b/test/distributed/org/apache/cassandra/distributed/test/AbstractEncryptionOptionsImpl.java
index 1c5ddbf6b5..b488867433 100644
---
a/test/distributed/org/apache/cassandra/distributed/test/AbstractEncryptionOptionsImpl.java
+++
b/test/distributed/org/apache/cassandra/distributed/test/AbstractEncryptionOptionsImpl.java
@@ -200,7 +200,7 @@ public class AbstractEncryptionOptionsImpl extends
TestBaseImpl
SslContext sslContext = SSLFactory.getOrCreateSslContext(
encryptionOptions.withAcceptedProtocols(acceptedProtocols).withCipherSuites(cipherSuites),
- true, ISslContextFactory.SocketType.CLIENT);
+ true, ISslContextFactory.SocketType.CLIENT, "test");
EventLoopGroup workerGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
diff --git
a/test/unit/org/apache/cassandra/security/DefaultSslContextFactoryTest.java
b/test/unit/org/apache/cassandra/security/DefaultSslContextFactoryTest.java
index 0657eb67a6..bec9d20042 100644
--- a/test/unit/org/apache/cassandra/security/DefaultSslContextFactoryTest.java
+++ b/test/unit/org/apache/cassandra/security/DefaultSslContextFactoryTest.java
@@ -62,7 +62,7 @@ public class DefaultSslContextFactoryTest
.withKeyStorePassword("cassandra")
.withRequireClientAuth(false)
.withCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA");
- SslContext sslContext = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SslContext sslContext = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
Assert.assertNotNull(sslContext);
if (OpenSsl.isAvailable())
Assert.assertTrue(sslContext instanceof OpenSslContext);
diff --git
a/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryTest.java
b/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryTest.java
index 243d300539..f44e34492e 100644
--- a/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryTest.java
+++ b/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryTest.java
@@ -216,7 +216,7 @@ public class PEMBasedSslContextFactoryTest
.withRequireClientAuth(false)
.withCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA")
.withSslContextFactory(sslContextFactory);
- SslContext sslContext = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SslContext sslContext = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
Assert.assertNotNull(sslContext);
if (OpenSsl.isAvailable())
Assert.assertTrue(sslContext instanceof OpenSslContext);
diff --git a/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
b/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
index e5aa4b1057..91e4062be4 100644
--- a/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
+++ b/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
@@ -19,7 +19,10 @@
package org.apache.cassandra.security;
import org.apache.cassandra.io.util.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;
@@ -61,6 +64,7 @@ public class SSLFactoryTest
@Before
public void setup()
{
+ SSLFactory.clearSslContextCache();
encryptionOptions = new ServerEncryptionOptions()
.withTrustStore("test/conf/cassandra_ssl_test.truststore")
.withTrustStorePassword("cassandra")
@@ -91,20 +95,24 @@ public class SSLFactoryTest
{
ServerEncryptionOptions options =
addKeystoreOptions(encryptionOptions)
.withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
+ ServerEncryptionOptions legacyOptions =
options.withOptional(false).withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
+ options.sslContextFactoryInstance.initHotReloading();
+ legacyOptions.sslContextFactoryInstance.initHotReloading();
- SSLFactory.initHotReloading(options, options, true);
-
- SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SslContext oldLegacyCtx =
SSLFactory.getOrCreateSslContext(legacyOptions, true,
ISslContextFactory.SocketType.CLIENT, "test legacy");
File keystoreFile = new File(options.keystore);
- SSLFactory.checkCertFilesForHotReloading(options, options);
+ SSLFactory.checkCertFilesForHotReloading();
keystoreFile.trySetLastModified(System.currentTimeMillis() +
15000);
- SSLFactory.checkCertFilesForHotReloading(options, options);
- SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SSLFactory.checkCertFilesForHotReloading();
+ SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SslContext newLegacyCtx =
SSLFactory.getOrCreateSslContext(legacyOptions, true,
ISslContextFactory.SocketType.CLIENT, "test legacy");
Assert.assertNotSame(oldCtx, newCtx);
+ Assert.assertNotSame(oldLegacyCtx, newLegacyCtx);
}
catch (Exception e)
{
@@ -122,21 +130,26 @@ public class SSLFactoryTest
try
{
ServerEncryptionOptions options =
addPEMKeystoreOptions(encryptionOptions)
-
.withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
-
- SSLFactory.initHotReloading(options, options, true);
-
- SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+
.withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.dc);
+ // emulate InboundSockets and share the cert but with different
options, no extra hot reloading init
+ ServerEncryptionOptions legacyOptions =
options.withOptional(false).withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
+ options.sslContextFactoryInstance.initHotReloading();
+ legacyOptions.sslContextFactoryInstance.initHotReloading();
+
+ SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SslContext oldLegacyCtx =
SSLFactory.getOrCreateSslContext(legacyOptions, true,
ISslContextFactory.SocketType.CLIENT, "test legacy");
File keystoreFile = new File(options.keystore);
- SSLFactory.checkCertFilesForHotReloading(options, options);
+ SSLFactory.checkCertFilesForHotReloading();
keystoreFile.trySetLastModified(System.currentTimeMillis() +
15000);
- SSLFactory.checkCertFilesForHotReloading(options, options);
- SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SSLFactory.checkCertFilesForHotReloading();
+ SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SslContext newLegacyCtx =
SSLFactory.getOrCreateSslContext(legacyOptions, true,
ISslContextFactory.SocketType.CLIENT, "test legacy");
Assert.assertNotSame(oldCtx, newCtx);
+ Assert.assertNotSame(oldLegacyCtx, newLegacyCtx);
}
catch (Exception e)
{
@@ -164,20 +177,26 @@ public class SSLFactoryTest
try
{
ServerEncryptionOptions options =
addKeystoreOptions(encryptionOptions);
+ // emulate InboundSockets and share the cert but with different
options, no extra hot reloading init
+ ServerEncryptionOptions legacyOptions =
options.withOptional(false).withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
- SSLFactory.initHotReloading(options, options, true);
- SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
- File keystoreFile = new File(options.keystore);
+ File testKeystoreFile = new File(options.keystore + ".test");
+ FileUtils.copyFile(new File(options.keystore).toJavaIOFile(),
testKeystoreFile.toJavaIOFile());
+ options = options.withKeyStore(testKeystoreFile.path());
- SSLFactory.checkCertFilesForHotReloading(options, options);
- keystoreFile.trySetLastModified(System.currentTimeMillis() + 5000);
+ SSLFactory.initHotReloading(options, options, true); //
deliberately not initializing with legacyOptions to match
InboundSockets.addBindings
- ServerEncryptionOptions modOptions = new
ServerEncryptionOptions(options)
- .withKeyStorePassword("bad
password");
- SSLFactory.checkCertFilesForHotReloading(modOptions, modOptions);
- SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SslContext oldLegacyCtx =
SSLFactory.getOrCreateSslContext(options, true,
ISslContextFactory.SocketType.CLIENT, "test legacy");
+
+ changeKeystorePassword(options.keystore,
options.keystore_password, "bad password");
+
+ SSLFactory.checkCertFilesForHotReloading();
+ SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SslContext newLegacyCtx =
SSLFactory.getOrCreateSslContext(options, true,
ISslContextFactory.SocketType.CLIENT, "test legacy");
Assert.assertSame(oldCtx, newCtx);
+ Assert.assertSame(oldLegacyCtx, newLegacyCtx);
}
finally
{
@@ -198,14 +217,14 @@ public class SSLFactoryTest
SSLFactory.initHotReloading(options, options, true);
- SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
- SSLFactory.checkCertFilesForHotReloading(options, options);
+ SslContext oldCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
+ SSLFactory.checkCertFilesForHotReloading();
testKeystoreFile.trySetLastModified(System.currentTimeMillis() +
15000);
FileUtils.forceDelete(testKeystoreFile.toJavaIOFile());
- SSLFactory.checkCertFilesForHotReloading(options, options);
- SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT);
+ SSLFactory.checkCertFilesForHotReloading();
+ SslContext newCtx = SSLFactory.getOrCreateSslContext(options,
true, ISslContextFactory.SocketType.CLIENT, "test");
Assert.assertSame(oldCtx, newCtx);
}
@@ -228,7 +247,7 @@ public class SSLFactoryTest
.withCipherSuites("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
SslContext ctx1 = SSLFactory.getOrCreateSslContext(options, true,
-
ISslContextFactory.SocketType.SERVER);
+
ISslContextFactory.SocketType.SERVER, "test");
Assert.assertTrue(ctx1.isServer());
Assert.assertEquals(ctx1.cipherSuites(), options.cipher_suites);
@@ -236,7 +255,7 @@ public class SSLFactoryTest
options =
options.withCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
SslContext ctx2 = SSLFactory.getOrCreateSslContext(options, true,
-
ISslContextFactory.SocketType.CLIENT);
+
ISslContextFactory.SocketType.CLIENT, "test");
Assert.assertTrue(ctx2.isClient());
Assert.assertEquals(ctx2.cipherSuites(), options.cipher_suites);
@@ -255,7 +274,7 @@ public class SSLFactoryTest
.withRequireClientAuth(true)
.withRequireEndpointVerification(false);
- SSLFactory.CacheKey cacheKey1 = new
SSLFactory.CacheKey(encryptionOptions1, ISslContextFactory.SocketType.SERVER
+ SSLFactory.CacheKey cacheKey1 = new
SSLFactory.CacheKey(encryptionOptions1, ISslContextFactory.SocketType.SERVER,
"test"
);
Map<String,String> parameters2 = new HashMap<>();
@@ -268,7 +287,7 @@ public class SSLFactoryTest
.withRequireClientAuth(true)
.withRequireEndpointVerification(false);
- SSLFactory.CacheKey cacheKey2 = new
SSLFactory.CacheKey(encryptionOptions2, ISslContextFactory.SocketType.SERVER
+ SSLFactory.CacheKey cacheKey2 = new
SSLFactory.CacheKey(encryptionOptions2, ISslContextFactory.SocketType.SERVER,
"test"
);
Assert.assertEquals(cacheKey1, cacheKey2);
@@ -285,7 +304,7 @@ public class SSLFactoryTest
.withSslContextFactory(new
ParameterizedClass(DummySslContextFactoryImpl.class.getName(), parameters1))
.withProtocol("TLSv1.1");
- SSLFactory.CacheKey cacheKey1 = new
SSLFactory.CacheKey(encryptionOptions1, ISslContextFactory.SocketType.SERVER
+ SSLFactory.CacheKey cacheKey1 = new
SSLFactory.CacheKey(encryptionOptions1, ISslContextFactory.SocketType.SERVER,
"test"
);
Map<String,String> parameters2 = new HashMap<>();
@@ -296,9 +315,31 @@ public class SSLFactoryTest
.withSslContextFactory(new
ParameterizedClass(DummySslContextFactoryImpl.class.getName(), parameters2))
.withProtocol("TLSv1.1");
- SSLFactory.CacheKey cacheKey2 = new
SSLFactory.CacheKey(encryptionOptions2, ISslContextFactory.SocketType.SERVER
+ SSLFactory.CacheKey cacheKey2 = new
SSLFactory.CacheKey(encryptionOptions2, ISslContextFactory.SocketType.SERVER,
"test"
);
Assert.assertNotEquals(cacheKey1, cacheKey2);
}
+
+ void changeKeystorePassword(String filename, String currentPassword,
String newPassword)
+ {
+ try
+ {
+ KeyStore keystore =
KeyStore.getInstance(KeyStore.getDefaultType());
+ char[] loadPasswd = currentPassword.toCharArray();
+ char[] storePasswd = newPassword.toCharArray();
+ try (FileInputStream is = new FileInputStream(filename))
+ {
+ keystore.load(is, loadPasswd);
+ }
+ try (FileOutputStream os = new FileOutputStream(filename))
+ {
+ keystore.store(os, storePasswd);
+ }
+ }
+ catch (Throwable tr)
+ {
+ throw new RuntimeException(tr);
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]