This is an automated email from the ASF dual-hosted git repository.
aweisberg pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push:
new 367cdc9 SSL Cert Hot Reloading should check for sanity of the new
keystore/truststore before loading it
367cdc9 is described below
commit 367cdc95514d4550db57054c90fb794fc29179d1
Author: Ariel Weisberg <[email protected]>
AuthorDate: Fri Feb 8 11:55:38 2019 -0500
SSL Cert Hot Reloading should check for sanity of the new
keystore/truststore before loading it
Patch by Dinesh Joshi; reviewed by Ariel Weisberg for CASSANDRA-14991
---
CHANGES.txt | 1 +
.../cassandra/config/DatabaseDescriptor.java | 8 +-
.../org/apache/cassandra/net/MessagingService.java | 8 +-
.../cassandra/net/MessagingServiceMBean.java | 3 +-
.../apache/cassandra/net/async/NettyFactory.java | 4 +-
.../cassandra/net/async/OptionalSslHandler.java | 2 +-
.../org/apache/cassandra/security/SSLFactory.java | 109 ++++++++++++-------
src/java/org/apache/cassandra/tools/NodeProbe.java | 2 +-
.../cassandra/tools/ReloadSslCertificates.java | 13 ++-
.../org/apache/cassandra/transport/Server.java | 3 +-
.../apache/cassandra/transport/SimpleClient.java | 2 +-
.../apache/cassandra/security/SSLFactoryTest.java | 117 ++++++++++++++++++---
12 files changed, 207 insertions(+), 65 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index e8d4598..89c558a8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
4.0
+ * SSL Cert Hot Reloading should check for sanity of the new
keystore/truststore before loading it (CASSANDRA-14991)
* Avoid leaking threads when failing anticompactions and rate limit
anticompactions (CASSANDRA-15002)
* Validate token() arguments early instead of throwing NPE at execution
(CASSANDRA-14989)
* Add a new tool to dump audit logs (CASSANDRA-14885)
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 5feaea3..9b7a6e5 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -902,7 +902,13 @@ public class DatabaseDescriptor
public static void applySslContextHotReload()
{
- SSLFactory.initHotReloading(conf.server_encryption_options,
conf.client_encryption_options, false);
+ try
+ {
+ SSLFactory.initHotReloading(conf.server_encryption_options,
conf.client_encryption_options, false);
+ } catch(IOException e)
+ {
+ throw new ConfigurationException("Failed to initialize SSL hot
reloading", e);
+ }
}
public static void applySeedProvider()
diff --git a/src/java/org/apache/cassandra/net/MessagingService.java
b/src/java/org/apache/cassandra/net/MessagingService.java
index f5c064e..f72cd61 100644
--- a/src/java/org/apache/cassandra/net/MessagingService.java
+++ b/src/java/org/apache/cassandra/net/MessagingService.java
@@ -56,6 +56,7 @@ import org.apache.cassandra.concurrent.ScheduledExecutors;
import org.apache.cassandra.concurrent.Stage;
import org.apache.cassandra.concurrent.StageManager;
import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.config.EncryptionOptions.ServerEncryptionOptions;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.ConsistencyLevel;
@@ -1716,8 +1717,11 @@ public final class MessagingService implements
MessagingServiceMBean
}
@Override
- public void reloadSslCertificates()
+ public void reloadSslCertificates() throws IOException
{
- SSLFactory.checkCertFilesForHotReloading();
+ final ServerEncryptionOptions serverOpts =
DatabaseDescriptor.getInternodeMessagingEncyptionOptions();
+ final EncryptionOptions clientOpts =
DatabaseDescriptor.getNativeProtocolEncryptionOptions();
+ SSLFactory.validateSslCerts(serverOpts, clientOpts);
+ SSLFactory.checkCertFilesForHotReloading(serverOpts, clientOpts);
}
}
diff --git a/src/java/org/apache/cassandra/net/MessagingServiceMBean.java
b/src/java/org/apache/cassandra/net/MessagingServiceMBean.java
index 6adb891..732a5ed 100644
--- a/src/java/org/apache/cassandra/net/MessagingServiceMBean.java
+++ b/src/java/org/apache/cassandra/net/MessagingServiceMBean.java
@@ -19,6 +19,7 @@ package org.apache.cassandra.net;
+import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Map;
@@ -130,5 +131,5 @@ public interface MessagingServiceMBean
public int getVersion(String address) throws UnknownHostException;
- void reloadSslCertificates();
+ void reloadSslCertificates() throws IOException;
}
diff --git a/src/java/org/apache/cassandra/net/async/NettyFactory.java
b/src/java/org/apache/cassandra/net/async/NettyFactory.java
index 81de5d8..3752927 100644
--- a/src/java/org/apache/cassandra/net/async/NettyFactory.java
+++ b/src/java/org/apache/cassandra/net/async/NettyFactory.java
@@ -292,7 +292,7 @@ public final class NettyFactory
}
else
{
- SslContext sslContext =
SSLFactory.getSslContext(encryptionOptions, true,
SSLFactory.ConnectionType.INTERNODE_MESSAGING, SSLFactory.SocketType.SERVER);
+ SslContext sslContext =
SSLFactory.getSslContext(encryptionOptions, true, 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());
@@ -369,7 +369,7 @@ public final class NettyFactory
// order of handlers: ssl -> logger -> handshakeHandler
if (params.encryptionOptions != null)
{
- SslContext sslContext =
SSLFactory.getSslContext(params.encryptionOptions, true,
SSLFactory.ConnectionType.INTERNODE_MESSAGING, SSLFactory.SocketType.CLIENT);
+ SslContext sslContext =
SSLFactory.getSslContext(params.encryptionOptions, true,
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;
diff --git a/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java
b/src/java/org/apache/cassandra/net/async/OptionalSslHandler.java
index d57518c..3b4f794 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,
SSLFactory.ConnectionType.INTERNODE_MESSAGING, SSLFactory.SocketType.SERVER);
+ SslContext sslContext =
SSLFactory.getSslContext(encryptionOptions, true, SSLFactory.SocketType.SERVER);
Channel channel = ctx.channel();
InetSocketAddress peer =
encryptionOptions.require_endpoint_verification ? (InetSocketAddress)
channel.remoteAddress() : null;
SslHandler sslHandler = NettyFactory.newSslHandler(channel,
sslContext, peer);
diff --git a/src/java/org/apache/cassandra/security/SSLFactory.java
b/src/java/org/apache/cassandra/security/SSLFactory.java
index d64dded..700142d 100644
--- a/src/java/org/apache/cassandra/security/SSLFactory.java
+++ b/src/java/org/apache/cassandra/security/SSLFactory.java
@@ -56,6 +56,7 @@ 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.DatabaseDescriptor;
import org.apache.cassandra.config.EncryptionOptions;
/**
@@ -71,15 +72,6 @@ public final class SSLFactory
private static final Logger logger =
LoggerFactory.getLogger(SSLFactory.class);
/**
- * 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
- }
-
- /**
* Indicates if the process holds the inbound/listening end of the socket
({@link SocketType#SERVER})), or the
* outbound side ({@link SocketType#CLIENT}).
*/
@@ -229,27 +221,28 @@ public final class SSLFactory
/**
* get a netty {@link SslContext} instance
*/
- public static SslContext getSslContext(EncryptionOptions options, boolean
buildTruststore, ConnectionType connectionType,
+ public static SslContext getSslContext(EncryptionOptions options, boolean
buildTruststore,
SocketType socketType) throws
IOException
{
- return getSslContext(options, buildTruststore, connectionType,
socketType, OpenSsl.isAvailable());
+ return getSslContext(options, buildTruststore, socketType,
OpenSsl.isAvailable());
}
/**
* Get a netty {@link SslContext} instance.
*/
@VisibleForTesting
- static SslContext getSslContext(EncryptionOptions options, boolean
buildTruststore, ConnectionType connectionType,
+ static SslContext getSslContext(EncryptionOptions options, boolean
buildTruststore,
SocketType socketType, boolean useOpenSsl)
throws IOException
{
- CacheKey key = new CacheKey(options, connectionType, socketType);
+ CacheKey key = new CacheKey(options, socketType);
SslContext sslContext;
sslContext = cachedSslContexts.get(key);
if (sslContext != null)
return sslContext;
- sslContext = createNettySslContext(options, buildTruststore,
connectionType, socketType, useOpenSsl);
+ sslContext = createNettySslContext(options, buildTruststore,
socketType, useOpenSsl);
+
SslContext previous = cachedSslContexts.putIfAbsent(key, sslContext);
if (previous == null)
return sslContext;
@@ -261,7 +254,7 @@ public final class SSLFactory
/**
* Create a Netty {@link SslContext}
*/
- static SslContext createNettySslContext(EncryptionOptions options, boolean
buildTruststore, ConnectionType connectionType,
+ static SslContext createNettySslContext(EncryptionOptions options, boolean
buildTruststore,
SocketType socketType, boolean
useOpenSsl) throws IOException
{
/*
@@ -303,7 +296,8 @@ public final class SSLFactory
* @throws IllegalStateException if {@link
#initHotReloading(EncryptionOptions.ServerEncryptionOptions, EncryptionOptions,
boolean)}
* is not called first
*/
- public static void checkCertFilesForHotReloading()
+ public static void
checkCertFilesForHotReloading(EncryptionOptions.ServerEncryptionOptions
serverOpts,
+ EncryptionOptions
clientOpts)
{
if (!isHotReloadingInitialized)
throw new IllegalStateException("Hot reloading functionality has
not been initialized.");
@@ -313,61 +307,104 @@ public final class SSLFactory
if
(hotReloadableFiles.stream().anyMatch(HotReloadableFile::shouldReload))
{
logger.info("SSL certificates have been updated. Reseting the ssl
contexts for new connections.");
- cachedSslContexts.clear();
+ try
+ {
+ validateSslCerts(serverOpts, clientOpts);
+ cachedSslContexts.clear();
+ } catch(Exception e)
+ {
+ logger.error("Failed to hot reload the SSL Certificates!
Please check the certificate files.", e);
+ }
}
}
/**
* Determines whether to hot reload certificates and schedules a periodic
task for it.
*
- * @param serverEncryptionOptions
- * @param clientEncryptionOptions
+ * @param serverOpts Server encryption options (Internode)
+ * @param clientOpts Client encryption options (Native Protocol)
*/
- public static synchronized void
initHotReloading(EncryptionOptions.ServerEncryptionOptions
serverEncryptionOptions,
- EncryptionOptions
clientEncryptionOptions,
- boolean force)
+ public static synchronized void
initHotReloading(EncryptionOptions.ServerEncryptionOptions serverOpts,
+ EncryptionOptions
clientOpts,
+ boolean force) throws
IOException
{
if (isHotReloadingInitialized && !force)
return;
logger.debug("Initializing hot reloading SSLContext");
+ validateSslCerts(serverOpts, clientOpts);
+
List<HotReloadableFile> fileList = new ArrayList<>();
- if (serverEncryptionOptions.enabled)
+ if (serverOpts != null && serverOpts.enabled)
{
- fileList.add(new
HotReloadableFile(serverEncryptionOptions.keystore));
- fileList.add(new
HotReloadableFile(serverEncryptionOptions.truststore));
+ fileList.add(new HotReloadableFile(serverOpts.keystore));
+ fileList.add(new HotReloadableFile(serverOpts.truststore));
}
- if (clientEncryptionOptions.enabled)
+ if (clientOpts != null && clientOpts.enabled)
{
- fileList.add(new
HotReloadableFile(clientEncryptionOptions.keystore));
- fileList.add(new
HotReloadableFile(clientEncryptionOptions.truststore));
+ fileList.add(new HotReloadableFile(clientOpts.keystore));
+ fileList.add(new HotReloadableFile(clientOpts.truststore));
}
hotReloadableFiles = ImmutableList.copyOf(fileList);
if (!isHotReloadingInitialized)
{
-
ScheduledExecutors.scheduledTasks.scheduleWithFixedDelay(SSLFactory::checkCertFilesForHotReloading,
-
DEFAULT_HOT_RELOAD_INITIAL_DELAY_SEC,
-
DEFAULT_HOT_RELOAD_PERIOD_SEC, TimeUnit.SECONDS);
+ ScheduledExecutors.scheduledTasks
+ .scheduleWithFixedDelay(() -> checkCertFilesForHotReloading(
+
DatabaseDescriptor.getInternodeMessagingEncyptionOptions(),
+
DatabaseDescriptor.getNativeProtocolEncryptionOptions()),
+ DEFAULT_HOT_RELOAD_INITIAL_DELAY_SEC,
+ DEFAULT_HOT_RELOAD_PERIOD_SEC,
TimeUnit.SECONDS);
}
isHotReloadingInitialized = true;
}
+
+ /**
+ * Sanity checks all certificates to ensure we can actually load them
+ */
+ public static void
validateSslCerts(EncryptionOptions.ServerEncryptionOptions serverOpts,
EncryptionOptions clientOpts) throws IOException
+ {
+ try
+ {
+ // Ensure we're able to create both server & client SslContexts
+ if (serverOpts != null && serverOpts.enabled)
+ {
+ createNettySslContext(serverOpts, true, SocketType.SERVER,
OpenSsl.isAvailable());
+ createNettySslContext(serverOpts, true, SocketType.CLIENT,
OpenSsl.isAvailable());
+ }
+ } catch (Exception e)
+ {
+ throw new IOException("Failed to create SSL context using
server_encryption_options!", e);
+ }
+
+ try
+ {
+ // Ensure we're able to create both server & client SslContexts
+ if (clientOpts != null && clientOpts.enabled)
+ {
+ createNettySslContext(clientOpts,
clientOpts.require_client_auth, SocketType.SERVER, OpenSsl.isAvailable());
+ createNettySslContext(clientOpts,
clientOpts.require_client_auth, SocketType.CLIENT, OpenSsl.isAvailable());
+ }
+ } catch (Exception e)
+ {
+ throw new IOException("Failed to create SSL context using
client_encryption_options!", e);
+ }
+ }
+
static class CacheKey
{
private final EncryptionOptions encryptionOptions;
- private final ConnectionType connectionType;
private final SocketType socketType;
- public CacheKey(EncryptionOptions encryptionOptions, ConnectionType
connectionType, SocketType socketType)
+ public CacheKey(EncryptionOptions encryptionOptions, SocketType
socketType)
{
this.encryptionOptions = encryptionOptions;
- this.connectionType = connectionType;
this.socketType = socketType;
}
@@ -376,15 +413,13 @@ public final class SSLFactory
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CacheKey cacheKey = (CacheKey) o;
- return (connectionType == cacheKey.connectionType &&
- socketType == cacheKey.socketType &&
+ return (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;
diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java
b/src/java/org/apache/cassandra/tools/NodeProbe.java
index 197dd50..a2bff26 100644
--- a/src/java/org/apache/cassandra/tools/NodeProbe.java
+++ b/src/java/org/apache/cassandra/tools/NodeProbe.java
@@ -1746,7 +1746,7 @@ public class NodeProbe implements AutoCloseable
return arsProxy;
}
- public void reloadSslCerts()
+ public void reloadSslCerts() throws IOException
{
msProxy.reloadSslCertificates();
}
diff --git a/src/java/org/apache/cassandra/tools/ReloadSslCertificates.java
b/src/java/org/apache/cassandra/tools/ReloadSslCertificates.java
index f38b8c0..a572648 100644
--- a/src/java/org/apache/cassandra/tools/ReloadSslCertificates.java
+++ b/src/java/org/apache/cassandra/tools/ReloadSslCertificates.java
@@ -17,6 +17,8 @@
*/
package org.apache.cassandra.tools;
+import java.io.IOException;
+
import io.airlift.airline.Command;
@Command(name = "reloadssl", description = "Signals Cassandra to reload SSL
certificates")
@@ -25,6 +27,13 @@ public class ReloadSslCertificates extends
NodeTool.NodeToolCmd
@Override
public void execute(NodeProbe probe)
{
- probe.reloadSslCerts();
+ try
+ {
+ probe.reloadSslCerts();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Failed to reload SSL certificates.
Please check the SSL certificates", e);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/java/org/apache/cassandra/transport/Server.java
b/src/java/org/apache/cassandra/transport/Server.java
index 67532ac..056a4a0 100644
--- a/src/java/org/apache/cassandra/transport/Server.java
+++ b/src/java/org/apache/cassandra/transport/Server.java
@@ -406,8 +406,7 @@ public class Server implements CassandraDaemon.Server
protected final SslHandler createSslHandler(ByteBufAllocator
allocator) throws IOException
{
- SslContext sslContext =
SSLFactory.getSslContext(encryptionOptions,
encryptionOptions.require_client_auth,
-
SSLFactory.ConnectionType.NATIVE_TRANSPORT, SSLFactory.SocketType.SERVER);
+ SslContext sslContext =
SSLFactory.getSslContext(encryptionOptions,
encryptionOptions.require_client_auth, SSLFactory.SocketType.SERVER);
return sslContext.newHandler(allocator);
}
}
diff --git a/src/java/org/apache/cassandra/transport/SimpleClient.java
b/src/java/org/apache/cassandra/transport/SimpleClient.java
index 1334448..0db9136 100644
--- a/src/java/org/apache/cassandra/transport/SimpleClient.java
+++ b/src/java/org/apache/cassandra/transport/SimpleClient.java
@@ -293,7 +293,7 @@ public class SimpleClient implements Closeable
{
super.initChannel(channel);
SslContext sslContext =
SSLFactory.getSslContext(encryptionOptions,
encryptionOptions.require_client_auth,
-
SSLFactory.ConnectionType.NATIVE_TRANSPORT, SSLFactory.SocketType.CLIENT);
+
SSLFactory.SocketType.CLIENT);
channel.pipeline().addFirst("ssl",
sslContext.newHandler(channel.alloc()));
}
}
diff --git a/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
b/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
index 19e88de..b253c59 100644
--- a/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
+++ b/test/unit/org/apache/cassandra/security/SSLFactoryTest.java
@@ -24,6 +24,7 @@ import java.security.cert.CertificateException;
import java.util.Arrays;
import javax.net.ssl.TrustManagerFactory;
+import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -95,8 +96,7 @@ public class SSLFactoryTest
}
EncryptionOptions options = addKeystoreOptions(encryptionOptions);
- SslContext sslContext = SSLFactory.getSslContext(options, true,
SSLFactory.ConnectionType.NATIVE_TRANSPORT,
-
SSLFactory.SocketType.CLIENT, true);
+ SslContext sslContext = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, true);
Assert.assertNotNull(sslContext);
Assert.assertTrue(sslContext instanceof OpenSslContext);
}
@@ -105,8 +105,7 @@ public class SSLFactoryTest
public void getSslContext_JdkSsl() throws IOException
{
EncryptionOptions options = addKeystoreOptions(encryptionOptions);
- SslContext sslContext = SSLFactory.getSslContext(options, true,
SSLFactory.ConnectionType.NATIVE_TRANSPORT,
-
SSLFactory.SocketType.CLIENT, false);
+ SslContext sslContext = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, false);
Assert.assertNotNull(sslContext);
Assert.assertTrue(sslContext instanceof JdkSslContext);
Assert.assertEquals(Arrays.asList(encryptionOptions.cipher_suites),
sslContext.cipherSuites());
@@ -175,17 +174,17 @@ public class SSLFactoryTest
SSLFactory.initHotReloading((ServerEncryptionOptions) options,
options, true);
- SslContext oldCtx = SSLFactory.getSslContext(options, true,
SSLFactory.ConnectionType.NATIVE_TRANSPORT,
-
SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable());
+ SslContext oldCtx = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl
+
.isAvailable());
File keystoreFile = new File(options.keystore);
- SSLFactory.checkCertFilesForHotReloading();
+ SSLFactory.checkCertFilesForHotReloading((ServerEncryptionOptions)
options, options);
Thread.sleep(5000);
- keystoreFile.setLastModified(System.currentTimeMillis());
+ FileUtils.touch(keystoreFile);
- SSLFactory.checkCertFilesForHotReloading();
- SslContext newCtx = SSLFactory.getSslContext(options, true,
SSLFactory.ConnectionType.NATIVE_TRANSPORT,
-
SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable());
+ SSLFactory.checkCertFilesForHotReloading((ServerEncryptionOptions)
options, options);;
+ SslContext newCtx = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl
+
.isAvailable());
Assert.assertNotSame(oldCtx, newCtx);
}
@@ -199,6 +198,94 @@ public class SSLFactoryTest
}
}
+ @Test(expected = IOException.class)
+ public void testSslFactorySslInit_BadPassword_ThrowsException() throws
IOException
+ {
+ EncryptionOptions options = addKeystoreOptions(encryptionOptions);
+ options.keystore_password = "bad password";
+ options.enabled = true;
+
+ SSLFactory.initHotReloading((ServerEncryptionOptions) options,
options, true);
+ }
+
+ @Test
+ public void
testSslFactoryHotReload_BadPassword_DoesNotClearExistingSslContext() throws
IOException,
+
InterruptedException
+ {
+ try
+ {
+ addKeystoreOptions(encryptionOptions);
+
+ EncryptionOptions options = new
ServerEncryptionOptions(encryptionOptions);
+ options.enabled = true;
+
+ SSLFactory.initHotReloading((ServerEncryptionOptions) options,
options, true);
+ SslContext oldCtx = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl
+
.isAvailable());
+ File keystoreFile = new File(options.keystore);
+
+ SSLFactory.checkCertFilesForHotReloading((ServerEncryptionOptions)
options, options);
+ Thread.sleep(5000);
+ FileUtils.touch(keystoreFile);
+
+ options.keystore_password = "bad password";
+ SSLFactory.checkCertFilesForHotReloading((ServerEncryptionOptions)
options, options);;
+ SslContext newCtx = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl
+
.isAvailable());
+
+ Assert.assertSame(oldCtx, newCtx);
+ }
+ catch (Exception e)
+ {
+ throw e;
+ }
+ finally
+ {
+ DatabaseDescriptor.loadConfig();
+ }
+ }
+
+ @Test
+ public void
testSslFactoryHotReload_CorruptOrNonExistentFile_DoesNotClearExistingSslContext()
throws IOException,
+
InterruptedException
+ {
+ try
+ {
+ addKeystoreOptions(encryptionOptions);
+
+ File testKeystoreFile = new File(encryptionOptions.keystore +
".test");
+ FileUtils.copyFile(new
File(encryptionOptions.keystore),testKeystoreFile);
+ encryptionOptions.keystore = testKeystoreFile.getPath();
+
+ EncryptionOptions options = new
ServerEncryptionOptions(encryptionOptions);
+ options.enabled = true;
+
+ SSLFactory.initHotReloading((ServerEncryptionOptions) options,
options, true);
+ SslContext oldCtx = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl
+
.isAvailable());
+ SSLFactory.checkCertFilesForHotReloading((ServerEncryptionOptions)
options, options);
+ Thread.sleep(5000);
+
+ FileUtils.touch(testKeystoreFile);
+ FileUtils.forceDelete(testKeystoreFile);
+
+ SSLFactory.checkCertFilesForHotReloading((ServerEncryptionOptions)
options, options);;
+ SslContext newCtx = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl
+
.isAvailable());
+
+ Assert.assertSame(oldCtx, newCtx);
+ }
+ catch (Exception e)
+ {
+ throw e;
+ }
+ finally
+ {
+ DatabaseDescriptor.loadConfig();
+ FileUtils.deleteQuietly(new File(encryptionOptions.keystore +
".test"));
+ }
+ }
+
@Test
public void getSslContext_ParamChanges() throws IOException
{
@@ -206,15 +293,15 @@ public class SSLFactoryTest
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());
+ SslContext ctx1 = SSLFactory.getSslContext(options, true,
+
SSLFactory.SocketType.SERVER, OpenSsl.isAvailable());
- Assert.assertTrue(ctx1.isClient());
+ Assert.assertTrue(ctx1.isServer());
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,
+ SslContext ctx2 = SSLFactory.getSslContext(options, true,
SSLFactory.SocketType.CLIENT, OpenSsl.isAvailable());
Assert.assertTrue(ctx2.isClient());
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]