Merge branch 'cassandra-4.1' into cassandra-5.0

This commit is contained in:
Jon Meredith 2023-09-25 14:25:31 -06:00
commit a4be70930f
14 changed files with 153 additions and 86 deletions

View File

@ -7,6 +7,7 @@
* Fix SAI's SegmentMetadata min and max primary keys (CASSANDRA-18734)
* Remove commons-codec dependency (CASSANDRA-18772)
Merged from 4.1:
* Internode legacy SSL storage port certificate is not hot reloaded on update (CASSANDRA-18681)
* Nodetool paxos-only repair is no longer incremental (CASSANDRA-18466)
Merged from 4.0:
* JMH improvements - faster build and async profiler (CASSANDRA-18871)

View File

@ -20,7 +20,7 @@
<project default="jar" name="ssl-factory-example">
<property name="cassandra.dir" value="../.." />
<property name="cassandra.dir.lib" value="${cassandra.dir}/lib" />
<property name="cassandra.dir.lib" value="${cassandra.dir}/build/lib" />
<property name="cassandra.classes" value="${cassandra.dir}/build/classes/main" />
<property name="cassandra.test.lib" value="${cassandra.dir}/build/test/lib" />
<property name="build.src" value="${basedir}/src" />

View File

@ -65,6 +65,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.cassandra.auth.IInternodeAuthenticator.InternodeConnectionDirection.INBOUND;
import static org.apache.cassandra.concurrent.ExecutorFactory.Global.executorFactory;
import static org.apache.cassandra.net.InternodeConnectionUtils.DISCARD_HANDLER_NAME;
import static org.apache.cassandra.net.InternodeConnectionUtils.SSL_FACTORY_CONTEXT_DESCRIPTION;
import static org.apache.cassandra.net.InternodeConnectionUtils.SSL_HANDLER_NAME;
import static org.apache.cassandra.net.InternodeConnectionUtils.certificates;
import static org.apache.cassandra.net.MessagingService.*;
@ -522,7 +523,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());

View File

@ -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));
/*

View File

@ -38,6 +38,7 @@ public class InternodeConnectionUtils
{
public static String SSL_HANDLER_NAME = "ssl";
public static String DISCARD_HANDLER_NAME = "discard";
public static String SSL_FACTORY_CONTEXT_DESCRIPTION = "server_encryption_options";
private static final Logger logger = LoggerFactory.getLogger(InternodeConnectionUtils.class);
public static Certificate[] certificates(Channel channel)

View File

@ -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

View File

@ -66,6 +66,7 @@ import static java.util.concurrent.TimeUnit.*;
import static org.apache.cassandra.auth.IInternodeAuthenticator.InternodeConnectionDirection.OUTBOUND;
import static org.apache.cassandra.auth.IInternodeAuthenticator.InternodeConnectionDirection.OUTBOUND_PRECONNECT;
import static org.apache.cassandra.net.InternodeConnectionUtils.DISCARD_HANDLER_NAME;
import static org.apache.cassandra.net.InternodeConnectionUtils.SSL_FACTORY_CONTEXT_DESCRIPTION;
import static org.apache.cassandra.net.InternodeConnectionUtils.SSL_HANDLER_NAME;
import static org.apache.cassandra.net.InternodeConnectionUtils.certificates;
import static org.apache.cassandra.net.HandshakeProtocol.*;
@ -249,7 +250,7 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
{
requireClientAuth = settings.withEncryption();
}
return SSLFactory.getOrCreateSslContext(settings.encryption, requireClientAuth, ISslContextFactory.SocketType.CLIENT);
return SSLFactory.getOrCreateSslContext(settings.encryption, requireClientAuth, ISslContextFactory.SocketType.CLIENT, SSL_FACTORY_CONTEXT_DESCRIPTION);
}
}

View File

@ -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;
@ -41,7 +42,6 @@ import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslContext;
import io.netty.util.ReferenceCountUtil;
import org.apache.cassandra.concurrent.ScheduledExecutors;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.security.ISslContextFactory.SocketType;
@ -131,9 +131,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);
@ -176,41 +177,46 @@ 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)
/**
* Forces revalidation and loading of SSL certifcates if valid
*/
public static void forceCheckCertFiles()
{
checkCertFilesForHotReloading(serverOpts, "server_encryption_options", true);
}
if (clientOpts != null)
{
checkCertFilesForHotReloading(clientOpts, "client_encryption_options", clientOpts.require_client_auth);
}
checkCachedContextsForReload(true);
}
private static void checkCertFilesForHotReloading(EncryptionOptions options, String contextDescription,
boolean verifyPeerCertificate)
private static void checkCachedContextsForReload(boolean forceReload)
{
List<CacheKey> keysToCheck = new ArrayList<>(Collections.list(cachedSslContexts.keys()));
while (!keysToCheck.isEmpty())
{
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())
{
try
{
if (options.sslContextFactoryInstance.shouldReload())
{
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.", options.getClass().getName());
validateSslContext(contextDescription, options, verifyPeerCertificate, false);
clearSslContextCache(options);
"connections.", key.contextDescription);
clearSslContextCache(key.encryptionOptions, keysToCheck);
}
}
catch(Exception e)
catch (Throwable tr)
{
logger.error("Failed to hot reload the SSL Certificates! Please check the certificate files.", e);
logger.error("Failed to hot reload the SSL Certificates! Please check the certificate files for {}.",
key.contextDescription, tr);
}
}
}
}
@ -226,12 +232,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);
}
});
}
@ -262,9 +272,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);
}
@ -421,11 +429,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)
@ -434,7 +444,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()
@ -442,6 +453,7 @@ public final class SSLFactory
int result = 0;
result += 31 * socketType.hashCode();
result += 31 * encryptionOptions.hashCode();
result += 31 * contextDescription.hashCode();
return result;
}
}

View File

@ -66,6 +66,8 @@ public class PipelineConfigurator
// which will throttle a system under any normal load.
private static final boolean DEBUG = TEST_UNSAFE_VERBOSE_DEBUG_CLIENT_PROTOCOL.getBoolean();
public static final String SSL_FACTORY_CONTEXT_DESCRIPTION = "client_encryption_options";
// Stateless handlers
private static final ConnectionLimitHandler connectionLimitHandler = new ConnectionLimitHandler();
@ -167,7 +169,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()
{
@ -202,7 +205,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);
InetSocketAddress peer = encryptionOptions.require_endpoint_verification ? (InetSocketAddress) channel.remoteAddress() : null;
channel.pipeline().addFirst(SSL_HANDLER, newSslHandler(channel, sslContext, peer));
};

View File

@ -55,6 +55,7 @@ import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
import static org.apache.cassandra.net.SocketFactory.newSslHandler;
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;
@ -624,7 +625,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);
InetSocketAddress peer = encryptionOptions.require_endpoint_verification ? new InetSocketAddress(host, port) : null;
channel.pipeline().addFirst("ssl", newSslHandler(channel, sslContext, peer));
}

View File

@ -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();

View File

@ -73,7 +73,7 @@ public class DefaultSslContextFactoryTest
.withOutboundKeystorePassword("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);

View File

@ -218,7 +218,7 @@ public class PEMBasedSslContextFactoryTest
.withRequireClientAuth(false)
.withCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA")
.withSslContextFactory(sslContextFactory);
SslContext sslContext = SSLFactory.getOrCreateSslContext(options, true, ISslContextFactory.SocketType.SERVER);
SslContext sslContext = SSLFactory.getOrCreateSslContext(options, true, ISslContextFactory.SocketType.SERVER, "test");
Assert.assertNotNull(sslContext);
if (OpenSsl.isAvailable())
Assert.assertTrue(sslContext instanceof OpenSslContext);
@ -239,7 +239,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);

View File

@ -19,6 +19,7 @@
package org.apache.cassandra.security;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@ -76,6 +77,7 @@ public class SSLFactoryTest
@Before
public void setup()
{
SSLFactory.clearSslContextCache();
encryptionOptions = new ServerEncryptionOptions()
.withTrustStore("test/conf/cassandra_ssl_test.truststore")
.withTrustStorePassword("cassandra")
@ -112,20 +114,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)
{
@ -177,21 +183,26 @@ public class SSLFactoryTest
try
{
ServerEncryptionOptions options = addPEMKeystoreOptions(encryptionOptions)
.withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
.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();
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)
{
@ -219,20 +230,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(legacyOptions, 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(legacyOptions, true, ISslContextFactory.SocketType.CLIENT, "test legacy");
Assert.assertSame(oldCtx, newCtx);
Assert.assertSame(oldLegacyCtx, newLegacyCtx);
}
finally
{
@ -253,14 +270,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);
}
@ -282,7 +299,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);
@ -290,7 +307,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);
@ -309,7 +326,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<>();
@ -322,7 +339,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);
@ -339,7 +356,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<>();
@ -350,7 +367,7 @@ 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);
@ -387,4 +404,26 @@ public class SSLFactoryTest
final Certificate[] certificates = keyManager1.getCertificateChain("cassandra_ssl_test");
return certificates[0];
}
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);
}
}
}