This is an automated email from the ASF dual-hosted git repository.
smiklosovic 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 37fe4b679c Provide keystore_password_file and truststore_password_file
options to read credentials from a file
37fe4b679c is described below
commit 37fe4b679c28234de3ee2ac0694118d5be570300
Author: maulin-vasavada <[email protected]>
AuthorDate: Mon Feb 17 20:06:11 2025 -0800
Provide keystore_password_file and truststore_password_file options to read
credentials from a file
patch by Maulin Vasavada; reviewed by Stefan Miklosovic, Maxwell Guo for
CASSANDRA-13428
---
CHANGES.txt | 1 +
conf/cassandra.yaml | 29 ++
conf/cassandra_latest.yaml | 29 ++
.../pages/managing/operating/security.adoc | 52 +++-
.../KubernetesSecretsSslContextFactory.java | 12 +-
.../apache/cassandra/config/EncryptionOptions.java | 305 ++++++++++++++-------
.../apache/cassandra/config/JMXServerOptions.java | 6 +
.../security/FileBasedSslContextFactory.java | 60 +++-
.../cassandra-jmx-sslconfig-with-passwordfile.yaml | 74 +++++
...ra-pem-sslcontextfactory-with-passwordfile.yaml | 152 ++++++++++
.../cassandra_ssl_test_keystore_passwordfile.txt | 1 +
...ssandra_ssl_test_outbound_keystore_password.txt | 1 +
.../cassandra_ssl_test_truststore_passwordfile.txt | 1 +
.../config/EncryptionOptionsEqualityTest.java | 48 ++++
.../cassandra/config/EncryptionOptionsTest.java | 13 +-
.../security/FileBasedSslContextFactoryTest.java | 45 ++-
.../security/FileBasedStoreContextTest.java | 80 ++++++
...slContextFactoryConfigWithPasswordFileTest.java | 83 ++++++
.../apache/cassandra/transport/TlsTestUtils.java | 3 +
...uredWithYamlFileOptionsAndPasswordFileTest.java | 88 ++++++
20 files changed, 960 insertions(+), 123 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 34c1154950..9b84f503c4 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
5.1
+ * Provide keystore_password_file and truststore_password_file options to read
credentials from a file (CASSANDRA-13428)
* Unregistering a node should also remove it from tokenMap if it is there and
recalculate the placements (CASSANDRA-20346)
* Fix PartitionUpdate.isEmpty deserialization issue to avoid potential
EOFException (CASSANDRA-20345)
* Avoid adding LEFT nodes to tokenMap on upgrade from gossip (CASSANDRA-20344)
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index 9f8f24b584..6eb150f5df 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1723,6 +1723,10 @@ server_encryption_options:
# Set to a valid keystore if internode_encryption is dc, rack or all
keystore: conf/.keystore
#keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate file
+ # When keystore_password and keystore_password_file both are specified, the
keystore_password will take precedence
+ # The password in the file should be on the first line
+ #keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see
org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@@ -1734,11 +1738,20 @@ server_encryption_options:
# to create SSLContext. By default, outbound_keystore is the same as
keystore indicating mTLS is not enabled.
# outbound_keystore: conf/.keystore
# outbound_keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate file
+ # When outbound_keystore_password and outbound_keystore_password_file both
are specified,
+ # the outbound_keystore_password will take precedence
+ # The password in the file should be on the first line
+ #outbound_keystore_password_file: conf/outbound_keystore_passwordfile.txt
# Verify peer server certificates
require_client_auth: false
# Set to a valid trustore if require_client_auth is true
truststore: conf/.truststore
#truststore_password: cassandra
+ # Optional configuration to specify password for truststore in a separate
file
+ # When truststore_password and truststore_password_file both are specified,
the truststore_password will take precedence
+ # The password in the file should be on the first line
+ #truststore_password_file: conf/truststore_passwordfile.txt
# Verify that the host name in the certificate matches the connected host
require_endpoint_verification: false
# More advanced defaults:
@@ -1780,6 +1793,10 @@ client_encryption_options:
# Set keystore and keystore_password to valid keystores if enabled is true
keystore: conf/.keystore
#keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate file
+ # When keystore_password and keystore_password_file both are specified, the
keystore_password will take precedence
+ # The password in the file should be on the first line
+ #keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see
org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@@ -1794,6 +1811,10 @@ client_encryption_options:
# Set trustore and truststore_password if require_client_auth is true
# truststore: conf/.truststore
# truststore_password: cassandra
+ # Optional configuration to specify password for truststore in a separate
file
+ # When truststore_password and truststore_password_file both are specified,
the truststore_password will take precedence
+ # The password in the file should be on the first line
+ #truststore_password_file: conf/truststore_passwordfile.txt
# More advanced defaults:
# protocol: TLS
# store_type: JKS
@@ -1844,8 +1865,16 @@ client_encryption_options:
# accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
# keystore: conf/cassandra_ssl.keystore
# keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate
file
+ # When keystore_password and keystore_password_file both are specified,
the keystore_password will take precedence
+ # The password in the file should be on the first line
+ # keystore_password_file: conf/keystore_passwordfile.txt
# truststore: conf/cassandra_ssl.truststore
# truststore_password: cassandra
+ # Optional configuration to specify password for truststore in a separate
file
+ # When truststore_password and truststore_password_file both are
specified, the truststore_password will take precedence
+ # The password in the file should be on the first line
+ # truststore_password_file: conf/truststore_passwordfile.txt
#
# jmx authentication and authorization options.
# authenticate: false
diff --git a/conf/cassandra_latest.yaml b/conf/cassandra_latest.yaml
index f8d791b26f..9c86beeea8 100644
--- a/conf/cassandra_latest.yaml
+++ b/conf/cassandra_latest.yaml
@@ -1613,6 +1613,10 @@ server_encryption_options:
# Set to a valid keystore if internode_encryption is dc, rack or all
keystore: conf/.keystore
#keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate file
+ # When keystore_password and keystore_password_file both are specified, the
keystore_password will take precedence
+ # The password in the file should be on the first line
+ #keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see
org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@@ -1624,11 +1628,20 @@ server_encryption_options:
# to create SSLContext. By default, outbound_keystore is the same as
keystore indicating mTLS is not enabled.
# outbound_keystore: conf/.keystore
# outbound_keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate file
+ # When outbound_keystore_password and outbound_keystore_password_file both
are specified,
+ # the outbound_keystore_password will take precedence
+ # The password in the file should be on the first line
+ #outbound_keystore_password_file: conf/outbound_keystore_passwordfile.txt
# Verify peer server certificates
require_client_auth: false
# Set to a valid trustore if require_client_auth is true
truststore: conf/.truststore
#truststore_password: cassandra
+ # Optional configuration to specify password for truststore in a separate
file
+ # When truststore_password and truststore_password_file both are specified,
the truststore_password will take precedence
+ # The password in the file should be on the first line
+ #truststore_password_file: conf/truststore_passwordfile.txt
# Verify that the host name in the certificate matches the connected host
require_endpoint_verification: false
# More advanced defaults:
@@ -1663,6 +1676,10 @@ client_encryption_options:
# Set keystore and keystore_password to valid keystores if enabled is true
keystore: conf/.keystore
#keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate file
+ # When keystore_password and keystore_password_file both are specified, the
keystore_password will take precedence
+ # The password in the file should be on the first line
+ #keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see
org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@@ -1677,6 +1694,10 @@ client_encryption_options:
# Set trustore and truststore_password if require_client_auth is true
# truststore: conf/.truststore
# truststore_password: cassandra
+ # Optional configuration to specify password for truststore in a separate
file
+ # When truststore_password and truststore_password_file both are specified,
the truststore_password will take precedence
+ # The password in the file should be on the first line
+ #truststore_password_file: conf/truststore_passwordfile.txt
# More advanced defaults:
# protocol: TLS
# store_type: JKS
@@ -1718,8 +1739,16 @@ client_encryption_options:
# accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
# keystore: conf/cassandra_ssl.keystore
# keystore_password: cassandra
+ # Optional configuration to specify password for keystore in a separate
file
+ # When keystore_password and keystore_password_file both are specified,
the keystore_password will take precedence
+ # The password in the file should be on the first line
+ # keystore_password_file: conf/keystore_passwordfile.txt
# truststore: conf/cassandra_ssl.truststore
# truststore_password: cassandra
+ # Optional configuration to specify password for truststore in a separate
file
+ # When truststore_password and truststore_password_file both are
specified, the truststore_password will take precedence
+ # The password in the file should be on the first line
+ # truststore_password_file: conf/truststore_passwordfile.txt
#
# jmx authentication and authorization options.
# authenticate: false
diff --git a/doc/modules/cassandra/pages/managing/operating/security.adoc
b/doc/modules/cassandra/pages/managing/operating/security.adoc
index e7748e93fb..cdc76a625d 100644
--- a/doc/modules/cassandra/pages/managing/operating/security.adoc
+++ b/doc/modules/cassandra/pages/managing/operating/security.adoc
@@ -100,6 +100,28 @@ YAML!)
-----END CERTIFICATE-----
----
+* Configuration: PEM private key's password specified via a file
+
+[source,yaml]
+----
+ client/server_encryption_options:
+ ssl_context_factory:
+ class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+ parameters:
+ private_key: |
+ -----BEGIN ENCRYPTED PRIVATE KEY----- OR -----BEGIN PRIVATE
KEY-----
+ <your base64 encoded private key>
+ -----END ENCRYPTED PRIVATE KEY----- OR -----END PRIVATE KEY-----
+ -----BEGIN CERTIFICATE-----
+ <your base64 encoded certificate chain>
+ -----END CERTIFICATE-----
+ trusted_certificates: |
+ -----BEGIN CERTIFICATE-----
+ <your base64 encoded certificate>
+ -----END CERTIFICATE-----
+ keystore_password_file: "<file having your password for the encrypted
private key>"
+----
+
* Configuration: PEM keys/certs defined in files
[source,yaml]
@@ -112,6 +134,18 @@ YAML!)
truststore: <file path to the truststore file in the PEM format>
----
+* Configuration: PEM private key's password specified via a file
+
+[source,yaml]
+----
+ client/server_encryption_options:
+ ssl_context_factory:
+ class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+ keystore: <file path to the keystore file in the PEM format with the
private key and the certificate chain>
+ keystore_password_file: "<file having your password for the encrypted
private key>"
+ truststore: <file path to the truststore file in the PEM format>
+----
+
== SSL Certificate Hot Reloading
Beginning with Cassandra 4, Cassandra supports hot reloading of SSL
@@ -590,11 +624,27 @@ jmx_encryption_options:
truststore_password: cassandra
----
+Below is an example of configuring JMX SSL in `cassandra.yaml` with password
files for keystore and truststore.
+[source,yaml]
+----
+jmx_encryption_options:
+ enabled: true
+ cipher_suites:
[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
+ accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
+ keystore: test/conf/cassandra_ssl_test.keystore
+ keystore_password_file: test/conf/keystore_passwordfile.txt
+ truststore: test/conf/cassandra_ssl_test.truststore
+ truststore_password: cassandra
+ truststore_password_file: test/conf/truststore_passwordfile.txt
+----
+
Similar to `client/server_encryption_options`, you can specify PEM-based
key material or customize the SSL configuration using
`ssl_context_factory` in `jmx_encryption_options`.
-Below is an example of configuring PEM based key material,
+Below is an example of configuring PEM based key material. You can use
`keystore_password_file`
+configuration with in-line PEM as documented priorly in case you have stored
the password for the
+keystore in a file.
[source,yaml]
----
jmx_encryption_options:
diff --git
a/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
b/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
index ebeac6c4e8..12622d4458 100644
---
a/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
+++
b/examples/ssl-factory/src/org/apache/cassandra/security/KubernetesSecretsSslContextFactory.java
@@ -150,10 +150,12 @@ public class KubernetesSecretsSslContextFactory extends
FileBasedSslContextFacto
public KubernetesSecretsSslContextFactory()
{
keystoreContext = new
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.KEYSTORE.toString(),
KEYSTORE_PATH_VALUE),
-
getValueFromEnv(KEYSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_KEYSTORE_PASSWORD));
+
getValueFromEnv(KEYSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_KEYSTORE_PASSWORD),
+ null);
trustStoreContext = new
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.TRUSTSTORE.toString(),
TRUSTSTORE_PATH_VALUE),
-
getValueFromEnv(TRUSTSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_TRUSTSTORE_PASSWORD));
+
getValueFromEnv(TRUSTSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_TRUSTSTORE_PASSWORD),
+ null);
keystoreLastUpdatedTime = System.nanoTime();
keystoreUpdatedTimeSecretKeyPath =
getString(ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH,
@@ -168,11 +170,13 @@ public class KubernetesSecretsSslContextFactory extends
FileBasedSslContextFacto
super(parameters);
keystoreContext = new
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.KEYSTORE.toString(),
KEYSTORE_PATH_VALUE),
getValueFromEnv(getString(ConfigKeys.KEYSTORE_PASSWORD_ENV_VAR,
-
KEYSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_KEYSTORE_PASSWORD));
+
KEYSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_KEYSTORE_PASSWORD),
+ null);
trustStoreContext = new
FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.TRUSTSTORE.toString(),
TRUSTSTORE_PATH_VALUE),
getValueFromEnv(getString(ConfigKeys.TRUSTSTORE_PASSWORD_ENV_VAR,
-
TRUSTSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_TRUSTSTORE_PASSWORD));
+
TRUSTSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_TRUSTSTORE_PASSWORD),
+ null);
keystoreLastUpdatedTime = System.nanoTime();
keystoreUpdatedTimeSecretKeyPath =
getString(ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH,
KEYSTORE_UPDATED_TIMESTAMP_PATH_VALUE);
diff --git a/src/java/org/apache/cassandra/config/EncryptionOptions.java
b/src/java/org/apache/cassandra/config/EncryptionOptions.java
index 1cd3b7addd..07f78b9a5e 100644
--- a/src/java/org/apache/cassandra/config/EncryptionOptions.java
+++ b/src/java/org/apache/cassandra/config/EncryptionOptions.java
@@ -114,9 +114,13 @@ public class EncryptionOptions
public final String keystore;
@Nullable
public final String keystore_password;
+ @Nullable
+ public final String keystore_password_file;
public final String truststore;
@Nullable
public final String truststore_password;
+ @Nullable
+ public final String truststore_password_file;
public final List<String> cipher_suites;
protected String protocol;
protected List<String> accepted_protocols;
@@ -153,10 +157,13 @@ public class EncryptionOptions
{
KEYSTORE("keystore"),
KEYSTORE_PASSWORD("keystore_password"),
+ KEYSTORE_PASSWORD_FILE("keystore_password_file"),
OUTBOUND_KEYSTORE("outbound_keystore"),
OUTBOUND_KEYSTORE_PASSWORD("outbound_keystore_password"),
+ OUTBOUND_KEYSTORE_PASSWORD_FILE("outbound_keystore_password_file"),
TRUSTSTORE("truststore"),
TRUSTSTORE_PASSWORD("truststore_password"),
+ TRUSTSTORE_PASSWORD_FILE("truststore_password_file"),
CIPHER_SUITES("cipher_suites"),
PROTOCOL("protocol"),
ACCEPTED_PROTOCOLS("accepted_protocols"),
@@ -199,8 +206,10 @@ public class EncryptionOptions
new HashMap<>());
keystore = "conf/.keystore";
keystore_password = null;
+ keystore_password_file = null;
truststore = "conf/.truststore";
truststore_password = null;
+ truststore_password_file = null;
cipher_suites = null;
protocol = null;
accepted_protocols = null;
@@ -214,18 +223,22 @@ public class EncryptionOptions
certificate_validity_warn_threshold = null;
}
- public EncryptionOptions(ParameterizedClass ssl_context_factory, String
keystore, String keystore_password,
- String truststore, String truststore_password,
List<String> cipher_suites,
- String protocol, List<String> accepted_protocols,
String algorithm, String store_type,
- String require_client_auth, boolean
require_endpoint_verification, Boolean enabled,
- Boolean optional, DurationSpec.IntMinutesBound
max_certificate_validity_period,
+ public EncryptionOptions(ParameterizedClass ssl_context_factory,
+ String keystore, String keystore_password, String
keystore_password_file,
+ String truststore, String truststore_password,
String truststore_password_file,
+ List<String> cipher_suites, String protocol,
List<String> accepted_protocols,
+ String algorithm, String store_type, String
require_client_auth,
+ boolean require_endpoint_verification, Boolean
enabled, Boolean optional,
+ DurationSpec.IntMinutesBound
max_certificate_validity_period,
DurationSpec.IntMinutesBound
certificate_validity_warn_threshold)
{
this.ssl_context_factory = ssl_context_factory;
this.keystore = keystore;
this.keystore_password = keystore_password;
+ this.keystore_password_file = keystore_password_file;
this.truststore = truststore;
this.truststore_password = truststore_password;
+ this.truststore_password_file = truststore_password_file;
this.cipher_suites = cipher_suites;
this.protocol = protocol;
this.accepted_protocols = accepted_protocols;
@@ -244,8 +257,10 @@ public class EncryptionOptions
ssl_context_factory = options.ssl_context_factory;
keystore = options.keystore;
keystore_password = options.keystore_password;
+ keystore_password_file = options.keystore_password_file;
truststore = options.truststore;
truststore_password = options.truststore_password;
+ truststore_password_file = options.truststore_password_file;
cipher_suites = options.cipher_suites;
protocol = options.protocol;
accepted_protocols = options.accepted_protocols;
@@ -324,8 +339,10 @@ public class EncryptionOptions
*/
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.KEYSTORE, this.keystore);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.KEYSTORE_PASSWORD, this.keystore_password);
+ putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.KEYSTORE_PASSWORD_FILE, this.keystore_password_file);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.TRUSTSTORE, this.truststore);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.TRUSTSTORE_PASSWORD, this.truststore_password);
+ putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.TRUSTSTORE_PASSWORD_FILE, this.truststore_password_file);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.CIPHER_SUITES, this.cipher_suites);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.PROTOCOL, this.protocol);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.ACCEPTED_PROTOCOLS, this.accepted_protocols);
@@ -502,56 +519,72 @@ public class EncryptionOptions
public EncryptionOptions withSslContextFactory(ParameterizedClass
sslContextFactoryClass)
{
- return new EncryptionOptions(sslContextFactoryClass, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(sslContextFactoryClass, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withKeyStore(String keystore)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withKeyStorePassword(String keystore_password)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
+ store_type, require_client_auth,
require_endpoint_verification, enabled,
+ optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
+ }
+
+ public EncryptionOptions withKeyStorePasswordFile(String
keystore_password_file)
+ {
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withTrustStore(String truststore)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withTrustStorePassword(String truststore_password)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
+ store_type, require_client_auth,
require_endpoint_verification, enabled,
+ optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
+ }
+
+ public EncryptionOptions withTrustStorePasswordFile(String
truststore_password_file)
+ {
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withCipherSuites(List<String> cipher_suites)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withCipherSuites(String... cipher_suites)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password,
ImmutableList.copyOf(cipher_suites), protocol,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, ImmutableList.copyOf(cipher_suites), protocol,
accepted_protocols, algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional, max_certificate_validity_period,
max_certificate_validity_period).applyConfig();
@@ -559,8 +592,8 @@ public class EncryptionOptions
public EncryptionOptions withProtocol(String protocol)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
@@ -568,8 +601,8 @@ public class EncryptionOptions
public EncryptionOptions withAcceptedProtocols(List<String>
accepted_protocols)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols == null ? null :
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols == null ?
null :
ImmutableList.copyOf(accepted_protocols),
algorithm, store_type,
require_client_auth, require_endpoint_verification,
enabled, optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
@@ -578,64 +611,64 @@ public class EncryptionOptions
public EncryptionOptions withAlgorithm(String algorithm)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withStoreType(String store_type)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withRequireClientAuth(ClientAuth
require_client_auth)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth.value,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withRequireEndpointVerification(boolean
require_endpoint_verification)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withEnabled(boolean enabled)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withOptional(Boolean optional)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions
withMaxCertificateValidityPeriod(DurationSpec.IntMinutesBound
maxCertificateValidityPeriod)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional, maxCertificateValidityPeriod,
certificate_validity_warn_threshold).applyConfig();
}
public EncryptionOptions
withCertificateValidityWarnThreshold(DurationSpec.IntMinutesBound
certificateValidityWarnThreshold)
{
- return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, truststore,
- truststore_password, cipher_suites,
protocol, accepted_protocols, algorithm,
+ return new EncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file, truststore,
+ truststore_password,
truststore_password_file, cipher_suites, protocol, accepted_protocols,
algorithm,
store_type, require_client_auth,
require_endpoint_verification, enabled,
optional,
max_certificate_validity_period,
certificateValidityWarnThreshold).applyConfig();
}
@@ -659,8 +692,10 @@ public class EncryptionOptions
require_endpoint_verification ==
opt.require_endpoint_verification &&
Objects.equals(keystore, opt.keystore) &&
Objects.equals(keystore_password, opt.keystore_password) &&
+ Objects.equals(keystore_password_file,
opt.keystore_password_file) &&
Objects.equals(truststore, opt.truststore) &&
Objects.equals(truststore_password, opt.truststore_password) &&
+ Objects.equals(truststore_password_file,
opt.truststore_password_file) &&
Objects.equals(protocol, opt.protocol) &&
Objects.equals(accepted_protocols, opt.accepted_protocols) &&
Objects.equals(algorithm, opt.algorithm) &&
@@ -679,8 +714,10 @@ public class EncryptionOptions
int result = 0;
result += 31 * (keystore == null ? 0 : keystore.hashCode());
result += 31 * (keystore_password == null ? 0 :
keystore_password.hashCode());
+ result += 31 * (keystore_password_file == null ? 0 :
keystore_password_file.hashCode());
result += 31 * (truststore == null ? 0 : truststore.hashCode());
result += 31 * (truststore_password == null ? 0 :
truststore_password.hashCode());
+ result += 31 * (truststore_password_file == null ? 0 :
truststore_password_file.hashCode());
result += 31 * (protocol == null ? 0 : protocol.hashCode());
result += 31 * (accepted_protocols == null ? 0 :
accepted_protocols.hashCode());
result += 31 * (algorithm == null ? 0 : algorithm.hashCode());
@@ -707,6 +744,8 @@ public class EncryptionOptions
public final String outbound_keystore;
@Nullable
public final String outbound_keystore_password;
+ @Nullable
+ public final String outbound_keystore_password_file;
public ServerEncryptionOptions()
{
@@ -714,11 +753,13 @@ public class EncryptionOptions
this.legacy_ssl_storage_port_enabled = false;
this.outbound_keystore = null;
this.outbound_keystore_password = null;
+ this.outbound_keystore_password_file = null;
}
public ServerEncryptionOptions(ParameterizedClass
sslContextFactoryClass, String keystore,
- String keystore_password,String
outbound_keystore,
- String outbound_keystore_password,
String truststore, String truststore_password,
+ String keystore_password, String
keystore_password_file, String outbound_keystore,
+ String outbound_keystore_password,
String outbound_keystore_password_file,
+ String truststore, String
truststore_password, String truststore_password_file,
List<String> cipher_suites, String
protocol, List<String> accepted_protocols,
String algorithm, String store_type,
String require_client_auth,
boolean require_endpoint_verification,
Boolean optional,
@@ -726,13 +767,15 @@ public class EncryptionOptions
DurationSpec.IntMinutesBound
maxCertificateAgeMinutes,
DurationSpec.IntMinutesBound
certificateValidityWarnThreshold)
{
- super(sslContextFactoryClass, keystore, keystore_password,
truststore, truststore_password, cipher_suites,
+ super(sslContextFactoryClass, keystore, keystore_password,
keystore_password_file,
+ truststore, truststore_password, truststore_password_file,
cipher_suites,
protocol, accepted_protocols, algorithm, store_type,
require_client_auth, require_endpoint_verification,
null, optional, maxCertificateAgeMinutes,
certificateValidityWarnThreshold);
this.internode_encryption = internode_encryption;
this.legacy_ssl_storage_port_enabled =
legacy_ssl_storage_port_enabled;
this.outbound_keystore = outbound_keystore;
this.outbound_keystore_password = outbound_keystore_password;
+ this.outbound_keystore_password_file =
outbound_keystore_password_file;
}
public ServerEncryptionOptions(ServerEncryptionOptions options)
@@ -742,6 +785,7 @@ public class EncryptionOptions
this.legacy_ssl_storage_port_enabled =
options.legacy_ssl_storage_port_enabled;
this.outbound_keystore = options.outbound_keystore;
this.outbound_keystore_password =
options.outbound_keystore_password;
+ this.outbound_keystore_password_file =
options.outbound_keystore_password_file;
}
@Override
@@ -750,6 +794,7 @@ public class EncryptionOptions
super.fillSslContextParams(sslContextFactoryParameters);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.OUTBOUND_KEYSTORE, this.outbound_keystore);
putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.OUTBOUND_KEYSTORE_PASSWORD, this.outbound_keystore_password);
+ putSslContextFactoryParameter(sslContextFactoryParameters,
ConfigKey.OUTBOUND_KEYSTORE_PASSWORD_FILE,
this.outbound_keystore_password_file);
}
@Override
@@ -845,7 +890,8 @@ public class EncryptionOptions
return internode_encryption == opt.internode_encryption &&
legacy_ssl_storage_port_enabled ==
opt.legacy_ssl_storage_port_enabled &&
Objects.equals(outbound_keystore, opt.outbound_keystore) &&
- Objects.equals(outbound_keystore_password,
opt.outbound_keystore_password);
+ Objects.equals(outbound_keystore_password,
opt.outbound_keystore_password) &&
+ Objects.equals(outbound_keystore_password_file,
opt.outbound_keystore_password_file);
}
/**
@@ -861,15 +907,17 @@ public class EncryptionOptions
result += 31 * Boolean.hashCode(legacy_ssl_storage_port_enabled);
result += 31 * (outbound_keystore == null ? 0 :
outbound_keystore.hashCode());
result += 31 * (outbound_keystore_password == null ? 0 :
outbound_keystore_password.hashCode());
+ result += 31 * (outbound_keystore_password_file == null ? 0 :
outbound_keystore_password_file.hashCode());
return result;
}
@Override
public ServerEncryptionOptions
withSslContextFactory(ParameterizedClass sslContextFactoryClass)
{
- return new ServerEncryptionOptions(sslContextFactoryClass,
keystore, keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(sslContextFactoryClass,
keystore, keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -879,9 +927,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withKeyStore(String keystore)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -891,9 +940,23 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withKeyStorePassword(String
keystore_password)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
+ algorithm, store_type,
require_client_auth,
+ require_endpoint_verification,
optional, internode_encryption,
+
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
+
max_certificate_validity_period).applyConfigInternal();
+ }
+
+ @Override
+ public ServerEncryptionOptions withKeyStorePasswordFile(String
keystore_password_file)
+ {
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -903,9 +966,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withTrustStore(String truststore)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -915,9 +979,23 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withTrustStorePassword(String
truststore_password)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
+ algorithm, store_type,
require_client_auth,
+ require_endpoint_verification,
optional, internode_encryption,
+
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
+
max_certificate_validity_period).applyConfigInternal();
+ }
+
+ @Override
+ public ServerEncryptionOptions withTrustStorePasswordFile(String
truststore_password_file)
+ {
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -927,9 +1005,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withCipherSuites(List<String>
cipher_suites)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -939,10 +1018,11 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withCipherSuites(String...
cipher_suites)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
Arrays.asList(cipher_suites), protocol,
- accepted_protocols, algorithm,
store_type, require_client_auth,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ Arrays.asList(cipher_suites),
protocol, accepted_protocols,
+ algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
@@ -951,9 +1031,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withProtocol(String protocol)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -963,9 +1044,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withAcceptedProtocols(List<String>
accepted_protocols)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -975,9 +1057,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withAlgorithm(String algorithm)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -987,9 +1070,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withStoreType(String store_type)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -999,9 +1083,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withRequireClientAuth(ClientAuth
require_client_auth)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth.value,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1011,9 +1096,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withRequireEndpointVerification(boolean
require_endpoint_verification)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1022,9 +1108,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withOptional(boolean optional)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1033,9 +1120,10 @@ public class EncryptionOptions
public ServerEncryptionOptions
withInternodeEncryption(InternodeEncryption internode_encryption)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1044,9 +1132,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withLegacySslStoragePort(boolean
enable_legacy_ssl_storage_port)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
enable_legacy_ssl_storage_port,
max_certificate_validity_period,
@@ -1055,9 +1144,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withOutboundKeystore(String
outboundKeystore)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outboundKeystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outboundKeystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@@ -1066,21 +1156,34 @@ public class EncryptionOptions
public ServerEncryptionOptions withOutboundKeystorePassword(String
outboundKeystorePassword)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outboundKeystorePassword, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outboundKeystorePassword, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
}
+ public ServerEncryptionOptions withOutboundKeystorePasswordFile(String
outboundKeystorePasswordFile)
+ {
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outboundKeystorePasswordFile,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
+ algorithm, store_type,
require_client_auth,
+ require_endpoint_verification,
optional, internode_encryption,
+
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
+
max_certificate_validity_period).applyConfigInternal();
+ }
@Override
public ServerEncryptionOptions
withMaxCertificateValidityPeriod(DurationSpec.IntMinutesBound
maxCertificateValidityPeriod)
{
- return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password,
- outbound_keystore,
outbound_keystore_password, truststore,
- truststore_password,
cipher_suites, protocol, accepted_protocols,
+ return new ServerEncryptionOptions(ssl_context_factory, keystore,
keystore_password, keystore_password_file,
+ outbound_keystore,
outbound_keystore_password, outbound_keystore_password_file,
+ truststore,
truststore_password, truststore_password_file,
+ cipher_suites, protocol,
accepted_protocols,
algorithm, store_type,
require_client_auth,
require_endpoint_verification,
optional, internode_encryption,
legacy_ssl_storage_port_enabled, maxCertificateValidityPeriod,
diff --git a/src/java/org/apache/cassandra/config/JMXServerOptions.java
b/src/java/org/apache/cassandra/config/JMXServerOptions.java
index 8b51d3b756..705ab02bb8 100644
--- a/src/java/org/apache/cassandra/config/JMXServerOptions.java
+++ b/src/java/org/apache/cassandra/config/JMXServerOptions.java
@@ -194,11 +194,17 @@ public class JMXServerOptions
boolean sslEnabled = COM_SUN_MANAGEMENT_JMXREMOTE_SSL.getBoolean();
+ // CASSANDRA-13428: Support for specifying password file for keystores
is only added to the `encryption_options`
+ // in the `cassandra.yaml`. Since the JMX SSL Config can also leverage
it as per CASSANDRA-18508, password file
+ // support is not added to the JMX SSL configuration via the system
properties. Hence, `null` is used as
+ // the password file arguments for the keystore and the truststore
while constructing the encryption options here.
EncryptionOptions encryptionOptions = new EncryptionOptions(new
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
new HashMap<>()),
keystore,
keystorePassword,
+ null,
truststore,
truststorePassword,
+ null,
cipherSuites,
null, //
protocol
acceptedProtocols,
diff --git
a/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
b/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
index 39e584d257..e0867493d7 100644
--- a/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
+++ b/src/java/org/apache/cassandra/security/FileBasedSslContextFactory.java
@@ -36,9 +36,13 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.io.util.File;
+import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.utils.Clock;
+import static java.lang.String.format;
+
/**
* Abstract implementation for {@link ISslContextFactory} using file based,
standard keystore format with the ability
* to hot-reload the files upon file changes (detected by the {@code last
modified timestamp}).
@@ -60,18 +64,19 @@ public abstract class FileBasedSslContextFactory extends
AbstractSslContextFacto
public FileBasedSslContextFactory()
{
- keystoreContext = new FileBasedStoreContext("conf/.keystore",
"cassandra");
- outboundKeystoreContext = new FileBasedStoreContext("conf/.keystore",
"cassandra");
- trustStoreContext = new FileBasedStoreContext("conf/.truststore",
"cassandra");
+ keystoreContext = new FileBasedStoreContext("conf/.keystore",
"cassandra", null);
+ outboundKeystoreContext = new FileBasedStoreContext("conf/.keystore",
"cassandra", null);
+ trustStoreContext = new FileBasedStoreContext("conf/.truststore",
"cassandra", null);
}
public FileBasedSslContextFactory(Map<String, Object> parameters)
{
super(parameters);
- keystoreContext = new FileBasedStoreContext(getString("keystore"),
getString("keystore_password"));
+ keystoreContext = new FileBasedStoreContext(getString("keystore"),
getString("keystore_password"), getString("keystore_password_file"));
outboundKeystoreContext = new
FileBasedStoreContext(StringUtils.defaultString(getString("outbound_keystore"),
keystoreContext.filePath),
-
StringUtils.defaultString(getString("outbound_keystore_password"),
keystoreContext.password));
- trustStoreContext = new FileBasedStoreContext(getString("truststore"),
getString("truststore_password"));
+
StringUtils.defaultString(getString("outbound_keystore_password"),
keystoreContext.password),
+
StringUtils.defaultString(getString("outbound_keystore_password_file"),
keystoreContext.passwordFilePath));
+ trustStoreContext = new FileBasedStoreContext(getString("truststore"),
getString("truststore_password"), getString("truststore_password_file"));
}
@Override
@@ -135,7 +140,7 @@ public abstract class FileBasedSslContextFactory extends
AbstractSslContextFacto
if (password == null)
{
String keyName = isOutboundKeystore ? "outbound_" : "";
- final String msg = String.format("'%skeystore_password' must be
specified", keyName);
+ final String msg = format("'%skeystore_password' must be
specified", keyName);
throw new IllegalArgumentException(msg);
}
}
@@ -278,11 +283,13 @@ public abstract class FileBasedSslContextFactory extends
AbstractSslContextFacto
public volatile boolean checkedExpiry = false;
public String filePath;
public String password;
+ public String passwordFilePath;
- public FileBasedStoreContext(String keystore, String keystorePassword)
+ public FileBasedStoreContext(String keystoreFilePath, String
keystorePassword, String keystorePasswordFilePath)
{
- this.filePath = keystore;
- this.password = keystorePassword;
+ this.filePath = keystoreFilePath;
+ this.passwordFilePath = keystorePasswordFilePath;
+ this.password = resolvePassword(keystoreFilePath,
keystorePassword, keystorePasswordFilePath);
}
protected boolean hasKeystore()
@@ -294,5 +301,38 @@ public abstract class FileBasedSslContextFactory extends
AbstractSslContextFacto
{
return StringUtils.isEmpty(password) ||
keyPassword.equals(password);
}
+
+ private static String resolvePassword(String keystoreFilePath, String
password, String passwordFilePath)
+ {
+ if (password != null)
+ return password;
+
+ if (StringUtils.isEmpty(passwordFilePath))
+ return null;
+
+ File keystorePasswordFile = new File(passwordFilePath);
+
+ if (!keystorePasswordFile.exists())
+ {
+ final String msg = format("keystore password file %s does not
exist", keystorePasswordFile.path());
+ throw new ConfigurationException(msg);
+ }
+
+ try
+ {
+ // we expect a password to be on the first line
+ List<String> lines = FileUtils.readLines(keystorePasswordFile);
+ if (lines.isEmpty())
+ return "";
+
+ return lines.get(0);
+ }
+ catch (RuntimeException e)
+ {
+ throw new ConfigurationException(format("'Failed to read
keystore password from the %s for %s",
+ keystorePasswordFile,
keystoreFilePath),
+ e);
+ }
+ }
}
}
diff --git a/test/conf/cassandra-jmx-sslconfig-with-passwordfile.yaml
b/test/conf/cassandra-jmx-sslconfig-with-passwordfile.yaml
new file mode 100644
index 0000000000..0b495485d1
--- /dev/null
+++ b/test/conf/cassandra-jmx-sslconfig-with-passwordfile.yaml
@@ -0,0 +1,74 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Testing for pluggable ssl_context_factory option for client and server
encryption options with a valid and a missing
+# implementation classes.
+#
+cluster_name: Test Cluster
+# memtable_allocation_type: heap_buffers
+memtable_allocation_type: offheap_objects
+commitlog_sync: batch
+commitlog_segment_size: 5MiB
+commitlog_directory: build/test/cassandra/commitlog
+# commitlog_compression:
+# - class_name: LZ4Compressor
+cdc_raw_directory: build/test/cassandra/cdc_raw
+cdc_enabled: false
+hints_directory: build/test/cassandra/hints
+partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
+listen_address: 127.0.0.1
+storage_port: 7012
+ssl_storage_port: 17012
+start_native_transport: true
+native_transport_port: 9042
+column_index_size: 4KiB
+saved_caches_directory: build/test/cassandra/saved_caches
+data_file_directories:
+ - build/test/cassandra/data
+disk_access_mode: mmap_index_only
+seed_provider:
+ - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+ parameters:
+ - seeds: "127.0.0.1:7012"
+endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
+dynamic_snitch: true
+jmx_server_options:
+ enabled: true
+ jmx_encryption_options:
+ enabled: true
+ cipher_suites:
[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
+ accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
+ keystore: test/conf/cassandra_ssl_test.keystore
+ keystore_password_file:
test/conf/cassandra_ssl_test_keystore_passwordfile.txt
+ truststore: test/conf/cassandra_ssl_test.truststore
+ truststore_password_file:
test/conf/cassandra_ssl_test_truststore_passwordfile.txt
+incremental_backups: true
+concurrent_compactors: 4
+compaction_throughput: 0MiB/s
+row_cache_class_name: org.apache.cassandra.cache.OHCProvider
+row_cache_size: 16MiB
+user_defined_functions_enabled: true
+scripted_user_defined_functions_enabled: false
+prepared_statements_cache_size: 1MiB
+corrupted_tombstone_strategy: exception
+stream_entire_sstables: true
+stream_throughput_outbound: 24MiB/s
+sasi_indexes_enabled: true
+materialized_views_enabled: true
+file_cache_enabled: true
diff --git a/test/conf/cassandra-pem-sslcontextfactory-with-passwordfile.yaml
b/test/conf/cassandra-pem-sslcontextfactory-with-passwordfile.yaml
new file mode 100644
index 0000000000..19ef0f3cd7
--- /dev/null
+++ b/test/conf/cassandra-pem-sslcontextfactory-with-passwordfile.yaml
@@ -0,0 +1,152 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Testing for pluggable ssl_context_factory option for client and server
encryption options with a valid and a missing
+# implementation classes.
+#
+cluster_name: Test Cluster
+# memtable_allocation_type: heap_buffers
+memtable_allocation_type: offheap_objects
+commitlog_sync: periodic
+commitlog_sync_period: 10s
+commitlog_segment_size: 5MiB
+commitlog_directory: build/test/cassandra/commitlog
+# commitlog_compression:
+# - class_name: LZ4Compressor
+cdc_raw_directory: build/test/cassandra/cdc_raw
+cdc_enabled: false
+hints_directory: build/test/cassandra/hints
+partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
+listen_address: 127.0.0.1
+storage_port: 7012
+ssl_storage_port: 17012
+start_native_transport: true
+native_transport_port: 9042
+column_index_size: 4KiB
+saved_caches_directory: build/test/cassandra/saved_caches
+data_file_directories:
+ - build/test/cassandra/data
+disk_access_mode: mmap_index_only
+seed_provider:
+ - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+ parameters:
+ - seeds: "127.0.0.1:7012"
+endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
+dynamic_snitch: true
+client_encryption_options:
+ ssl_context_factory:
+ class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+ parameters:
+ private_key: |
+ -----BEGIN ENCRYPTED PRIVATE KEY-----
+ MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
+ g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
+ xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
+ L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
+ sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
+ f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
+ RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
+ 0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
+ evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
+ tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
+ wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
+ K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
+ zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
+ mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
+ WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
+ jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
+ eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
+ DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
+ AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
+ Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
+ Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
+ ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
+ bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
+ hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
+ RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
+ pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
+ FujZhqbKUDbYAcqTkoQ=
+ -----END ENCRYPTED PRIVATE KEY-----
+ -----BEGIN CERTIFICATE-----
+ MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
+ bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
+ VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
+ Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
+ EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
+ a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
+ FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+ MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
+ ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
+ q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
+ TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
+ TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
+ YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
+ N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
+ iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
+ IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
+ 6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
+ qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
+ HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
+ n3MVF9w=
+ -----END CERTIFICATE-----
+ trusted_certificates: |
+ -----BEGIN CERTIFICATE-----
+ MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
+ bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
+ VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
+ Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
+ EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
+ a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
+ FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+ MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
+ ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
+ q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
+ TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
+ TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
+ YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
+ N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
+ iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
+ IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
+ 6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
+ qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
+ HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
+ n3MVF9w=
+ -----END CERTIFICATE-----
+ keystore_password_file:
test/conf/cassandra_ssl_test_keystore_passwordfile.txt
+server_encryption_options:
+ ssl_context_factory:
+ class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
+ internode_encryption: none
+ keystore: test/conf/cassandra_ssl_test.keystore.pem
+ keystore_password_file:
test/conf/cassandra_ssl_test_keystore_passwordfile.txt
+ truststore: test/conf/cassandra_ssl_test.truststore.pem
+incremental_backups: true
+concurrent_compactors: 4
+compaction_throughput: 0MiB/s
+row_cache_class_name: org.apache.cassandra.cache.OHCProvider
+row_cache_size: 16MiB
+user_defined_functions_enabled: true
+scripted_user_defined_functions_enabled: false
+prepared_statements_cache_size: 1MiB
+corrupted_tombstone_strategy: exception
+stream_entire_sstables: true
+stream_throughput_outbound: 24MiB/s
+sasi_indexes_enabled: true
+materialized_views_enabled: true
+file_cache_enabled: true
diff --git a/test/conf/cassandra_ssl_test_keystore_passwordfile.txt
b/test/conf/cassandra_ssl_test_keystore_passwordfile.txt
new file mode 100644
index 0000000000..03ef327b7a
--- /dev/null
+++ b/test/conf/cassandra_ssl_test_keystore_passwordfile.txt
@@ -0,0 +1 @@
+cassandra
\ No newline at end of file
diff --git a/test/conf/cassandra_ssl_test_outbound_keystore_password.txt
b/test/conf/cassandra_ssl_test_outbound_keystore_password.txt
new file mode 100644
index 0000000000..03ef327b7a
--- /dev/null
+++ b/test/conf/cassandra_ssl_test_outbound_keystore_password.txt
@@ -0,0 +1 @@
+cassandra
\ No newline at end of file
diff --git a/test/conf/cassandra_ssl_test_truststore_passwordfile.txt
b/test/conf/cassandra_ssl_test_truststore_passwordfile.txt
new file mode 100644
index 0000000000..03ef327b7a
--- /dev/null
+++ b/test/conf/cassandra_ssl_test_truststore_passwordfile.txt
@@ -0,0 +1 @@
+cassandra
\ No newline at end of file
diff --git
a/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
b/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
index 317c8ec626..5e6d26b817 100644
--- a/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
+++ b/test/unit/org/apache/cassandra/config/EncryptionOptionsEqualityTest.java
@@ -81,6 +81,54 @@ public class EncryptionOptionsEqualityTest
assertEquals(encryptionOptions1.hashCode(),
encryptionOptions2.hashCode());
}
+ @Test
+ public void testKeystoreOptionsWithPasswordFile() {
+ EncryptionOptions encryptionOptions1 =
+ new EncryptionOptions()
+ .withStoreType("JKS")
+ .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+ .withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
+ .withTrustStore(TlsTestUtils.SERVER_TRUSTSTORE_PATH)
+
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE)
+ .withProtocol("TLSv1.1")
+ .withRequireClientAuth(REQUIRED)
+ .withRequireEndpointVerification(false);
+
+ EncryptionOptions encryptionOptions2 =
+ new EncryptionOptions()
+ .withStoreType("JKS")
+ .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+ .withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
+ .withTrustStore(TlsTestUtils.SERVER_TRUSTSTORE_PATH)
+
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE)
+ .withProtocol("TLSv1.1")
+ .withRequireClientAuth(REQUIRED)
+ .withRequireEndpointVerification(false);
+
+ assertEquals(encryptionOptions1, encryptionOptions2);
+ assertEquals(encryptionOptions1.hashCode(),
encryptionOptions2.hashCode());
+ }
+
+ @Test
+ public void testMismatchForKeystoreOptionsWithPasswordFile()
+ {
+ EncryptionOptions.ServerEncryptionOptions encryptionOptions1 =
createServerEncryptionOptions();
+ EncryptionOptions.ServerEncryptionOptions encryptionOptions2 =
createServerEncryptionOptions();
+
+ encryptionOptions1 = encryptionOptions1
+ .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+ .withKeyStorePassword(null)
+
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE);
+
+ encryptionOptions2 = encryptionOptions2
+ .withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
+ .withKeyStorePassword(null)
+
.withKeyStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE);
+
+ assertNotEquals(encryptionOptions1, encryptionOptions2);
+ assertNotEquals(encryptionOptions1.hashCode(),
encryptionOptions2.hashCode());
+ }
+
@Test
public void testSameCustomSslContextFactoryImplementation() {
diff --git a/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
b/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
index a295095dbb..5ef08eb060 100644
--- a/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
+++ b/test/unit/org/apache/cassandra/config/EncryptionOptionsTest.java
@@ -61,8 +61,8 @@ public class EncryptionOptionsTest
{
return new EncryptionOptionsTestCase(new EncryptionOptions(new
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
new HashMap<>()),
-
keystorePath, "dummypass",
-
"dummytruststore", "dummypass",
+
keystorePath, "dummypass", null,
+
"dummytruststore", "dummypass", null,
Collections.emptyList(), null, null, null, "JKS", "false", false, enabled,
optional, null, null)
.applyConfig(),
expected,
@@ -75,8 +75,8 @@ public class EncryptionOptionsTest
{
return new EncryptionOptionsTestCase(new EncryptionOptions(new
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
customSslContextFactoryParams),
-
keystorePath, "dummypass",
-
"dummytruststore", "dummypass",
+
keystorePath, "dummypass", null,
+
"dummytruststore", "dummypass", null,
Collections.emptyList(), null, null, null, "JKS", "false", false, enabled,
optional, null, null)
.applyConfig(),
expected,
@@ -127,7 +127,10 @@ public class EncryptionOptionsTest
EncryptionOptions.TlsEncryptionPolicy expected)
{
return new ServerEncryptionOptionsTestCase(new
EncryptionOptions.ServerEncryptionOptions(new
ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
-
new HashMap<>()), keystorePath,
"dummypass", keystorePath, "dummypass", "dummytruststore", "dummypass",
+
new HashMap<>()),
+
keystorePath, "dummypass", null,
+
keystorePath, "dummypass", null,
+
"dummytruststore", "dummypass", null,
Collections.emptyList(), null, null, null, "JKS", "false",
false, optional, internodeEncryption, false, null, null)
.applyConfig(),
expected,
diff --git
a/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
b/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
index 2916f0d460..d6d936ba0e 100644
---
a/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
+++
b/test/unit/org/apache/cassandra/security/FileBasedSslContextFactoryTest.java
@@ -31,6 +31,7 @@ import org.junit.Test;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.config.ParameterizedClass;
import org.apache.cassandra.distributed.shared.WithProperties;
+import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.transport.TlsTestUtils;
import static
org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
@@ -89,7 +90,7 @@ public class FileBasedSslContextFactoryTest
}
/**
- * Tests that empty {@code keystore_password} and {@code
outbound_keystore_password} is allowed.
+ * Tests that empty {@code keystore_password} and {@code
outbound_keystore_password} are allowed.
*/
@Test
public void testEmptyKeystorePasswords() throws SSLException
@@ -103,7 +104,7 @@ public class FileBasedSslContextFactoryTest
Assert.assertEquals("org.apache.cassandra.security.FileBasedSslContextFactoryTest$TestFileBasedSSLContextFactory",
localEncryptionOptions.ssl_context_factory.class_name);
Assert.assertEquals("keystore_password must be empty", "",
localEncryptionOptions.keystore_password);
- Assert.assertEquals("outbound_keystore_password must empty", "",
localEncryptionOptions.outbound_keystore_password);
+ Assert.assertEquals("outbound_keystore_password must be empty", "",
localEncryptionOptions.outbound_keystore_password);
TestFileBasedSSLContextFactory sslContextFactory =
(TestFileBasedSSLContextFactory)
localEncryptionOptions.sslContextFactoryInstance;
@@ -112,6 +113,46 @@ public class FileBasedSslContextFactoryTest
sslContextFactory.buildTrustManagerFactory();
}
+ @Test
+ public void testKeystorePasswordFile() throws SSLException
+ {
+ // Here we only override password configuration and specify
password_file configuration since keystore paths
+ // are already loaded in the `encryptionOptions`
+ EncryptionOptions.ServerEncryptionOptions localEncryptionOptions =
encryptionOptions
+
.withKeyStorePassword(null)
+
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
+
.withOutboundKeystorePassword(null)
+
.withOutboundKeystorePasswordFile(TlsTestUtils.SERVER_OUTBOUND_KEYSTORE_PASSWORD_FILE)
+
.withTrustStorePassword(null)
+
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE);
+
+
Assert.assertEquals("org.apache.cassandra.security.FileBasedSslContextFactoryTest$TestFileBasedSSLContextFactory",
+
localEncryptionOptions.ssl_context_factory.class_name);
+ TestFileBasedSSLContextFactory sslContextFactory =
+ (TestFileBasedSSLContextFactory)
localEncryptionOptions.sslContextFactoryInstance;
+
+ sslContextFactory.buildKeyManagerFactory();
+ sslContextFactory.buildTrustManagerFactory();
+ }
+
+ /**
+ * Tests for missing password configuration and non-existance file
specified in the password_file configuration.
+ * @throws SSLException
+ */
+ @Test(expected = ConfigurationException.class)
+ public void testBadKeystorePasswordFile() throws SSLException
+ {
+ // Here we only override password configuration and specify
password_file configuration since keystore paths
+ // are already loaded in the `encryptionOptions`
+ encryptionOptions
+ .withKeyStorePassword(null)
+ .withKeyStorePasswordFile("/path/to/non-existance-password-file")
+ .withOutboundKeystorePassword(null)
+
.withOutboundKeystorePasswordFile("/path/to/non-existance-password-file")
+ .withTrustStorePassword(null)
+ .withTrustStorePasswordFile("/path/to/non-existance-password-file");
+ }
+
/**
* Tests that an absent keystore_password for the {@code keystore} is
disallowed.
*/
diff --git
a/test/unit/org/apache/cassandra/security/FileBasedStoreContextTest.java
b/test/unit/org/apache/cassandra/security/FileBasedStoreContextTest.java
new file mode 100644
index 0000000000..cd1e52c61f
--- /dev/null
+++ b/test/unit/org/apache/cassandra/security/FileBasedStoreContextTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.security;
+
+import org.junit.Test;
+
+import org.apache.cassandra.exceptions.ConfigurationException;
+
+import static org.junit.Assert.assertEquals;
+
+public class FileBasedStoreContextTest
+{
+ /**
+ * Tests default behavior without keystore password file specified.
+ */
+ @Test
+ public void testPasswordConfiguration()
+ {
+ FileBasedSslContextFactory.FileBasedStoreContext wrapper = new
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
"cassandra", null);
+ assertEquals("Password must be loaded from the direct configuration",
"cassandra", wrapper.password);
+ }
+
+ /**
+ * Tests behavior when password for keystore is specified via a password
file.
+ */
+ @Test
+ public void testPasswordFileConfiguration()
+ {
+ FileBasedSslContextFactory.FileBasedStoreContext wrapper = new
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
null, "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
+ assertEquals("Password must be loaded from the password file",
"cassandra", wrapper.password);
+ }
+
+ /**
+ * Tests when password for keystore is specified via password
configuration and a password file both.
+ */
+ @Test
+ public void testPasswordAndPasswordFileConfiguration()
+ {
+ String expectedPassword = "cassandra123";
+ FileBasedSslContextFactory.FileBasedStoreContext wrapper = new
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
expectedPassword, "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
+ assertEquals("Password configuration must take precedence",
expectedPassword, wrapper.password);
+ }
+
+ /**
+ * Tests behavior when a non-existing password file is specified for
keystore's password and password configuration
+ * is {@code null}.
+ */
+ @Test(expected = ConfigurationException.class)
+ public void testMissingPasswordFile()
+ {
+ new
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
null, "passwordfile-that-doesnotexist");
+ }
+
+ /**
+ * Tests behavior when non-null empty password is specified in the
password configuration.
+ * The empty password via the configuration must take precedence in this
case.
+ */
+ @Test
+ public void testBlankPasswordConfiguration()
+ {
+ FileBasedSslContextFactory.FileBasedStoreContext wrapper = new
FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore",
"", "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
+ assertEquals("Password must be loaded from the direct configuration",
"", wrapper.password);
+ }
+}
diff --git
a/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryConfigWithPasswordFileTest.java
b/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryConfigWithPasswordFileTest.java
new file mode 100644
index 0000000000..fc837a3729
--- /dev/null
+++
b/test/unit/org/apache/cassandra/security/PEMBasedSslContextFactoryConfigWithPasswordFileTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.security;
+
+import javax.net.ssl.SSLException;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.config.Config;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.distributed.shared.WithProperties;
+
+import static
org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
+import static org.junit.Assert.assertEquals;
+
+public class PEMBasedSslContextFactoryConfigWithPasswordFileTest
+{
+ static WithProperties properties;
+
+ @BeforeClass
+ public static void setupDatabaseDescriptor()
+ {
+ properties = new WithProperties().set(CASSANDRA_CONFIG,
"cassandra-pem-sslcontextfactory-with-passwordfile.yaml");
+ }
+
+ @AfterClass
+ public static void tearDownDatabaseDescriptor()
+ {
+ properties.close();
+ }
+
+ @Test
+ public void testHappyPathInlinePEM() throws SSLException
+ {
+
+ Config config = DatabaseDescriptor.loadConfig();
+ config.client_encryption_options.applyConfig();
+
+ assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
+
config.client_encryption_options.ssl_context_factory.class_name);
+
assertEquals(config.client_encryption_options.ssl_context_factory.class_name,
+
config.client_encryption_options.sslContextFactoryInstance.getClass().getName());
+ PEMBasedSslContextFactory sslContextFactory =
+ (PEMBasedSslContextFactory)
config.client_encryption_options.sslContextFactoryInstance;
+ sslContextFactory.buildKeyManagerFactory();
+ sslContextFactory.buildTrustManagerFactory();
+ }
+
+ @Test
+ public void testHappyPathFileBasedPEM() throws SSLException
+ {
+
+ Config config = DatabaseDescriptor.loadConfig();
+ config.server_encryption_options.applyConfig();
+
+ assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
+
config.server_encryption_options.ssl_context_factory.class_name);
+
assertEquals(config.server_encryption_options.ssl_context_factory.class_name,
+
config.server_encryption_options.sslContextFactoryInstance.getClass().getName());
+ PEMBasedSslContextFactory sslContextFactory =
+ (PEMBasedSslContextFactory)
config.server_encryption_options.sslContextFactoryInstance;
+ sslContextFactory.buildKeyManagerFactory();
+ sslContextFactory.buildTrustManagerFactory();
+ }
+}
diff --git a/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
b/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
index f3994e7613..30a6054127 100644
--- a/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
+++ b/test/unit/org/apache/cassandra/transport/TlsTestUtils.java
@@ -58,16 +58,19 @@ public class TlsTestUtils
public static String SERVER_KEYSTORE_PATH_PEM =
"test/conf/cassandra_ssl_test.keystore.pem";
public static String SERVER_KEYSTORE_PATH_UNENCRYPTED_PEM =
"test/conf/cassandra_ssl_test.unencrypted_keystore.pem";
public static String SERVER_KEYSTORE_PASSWORD = "cassandra";
+ public static String SERVER_KEYSTORE_PASSWORD_FILE =
"test/conf/cassandra_ssl_test_keystore_passwordfile.txt";
public static String SERVER_KEYSTORE_ENDPOINT_VERIFY_PATH =
"test/conf/cassandra_ssl_test_endpoint_verify.keystore";
public static String SERVER_KEYSTORE_ENDPOINT_VERIFY_PASSWORD =
"cassandra";
public static String SERVER_OUTBOUND_KEYSTORE_PATH =
"test/conf/cassandra_ssl_test_outbound.keystore";
public static String SERVER_OUTBOUND_KEYSTORE_PASSWORD = "cassandra";
+ public static String SERVER_OUTBOUND_KEYSTORE_PASSWORD_FILE =
"test/conf/cassandra_ssl_test_outbound_keystore_password.txt";
public static String SERVER_TRUSTSTORE_PATH =
"test/conf/cassandra_ssl_test.truststore";
public static String SERVER_TRUSTSTORE_PEM_PATH =
"test/conf/cassandra_ssl_test.truststore.pem";
public static String SERVER_TRUSTSTORE_PASSWORD = "cassandra";
+ public static String SERVER_TRUSTSTORE_PASSWORD_FILE =
"test/conf/cassandra_ssl_test_truststore_passwordfile.txt";
// To regenerate:
// 1. generate keystore
diff --git
a/test/unit/org/apache/cassandra/utils/jmx/JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest.java
b/test/unit/org/apache/cassandra/utils/jmx/JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest.java
new file mode 100644
index 0000000000..ae2b7e6128
--- /dev/null
+++
b/test/unit/org/apache/cassandra/utils/jmx/JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.utils.jmx;
+
+import java.net.InetAddress;
+import java.util.Map;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.net.ssl.SSLException;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.JMXServerOptions;
+import org.apache.cassandra.distributed.shared.WithProperties;
+import org.apache.cassandra.utils.JMXServerUtils;
+
+import static
org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
+import static
org.apache.cassandra.config.CassandraRelevantProperties.COM_SUN_MANAGEMENT_JMXREMOTE_SSL;
+import static
org.apache.cassandra.config.CassandraRelevantProperties.JAVAX_RMI_SSL_CLIENT_ENABLED_CIPHER_SUITES;
+import static
org.apache.cassandra.config.CassandraRelevantProperties.JAVAX_RMI_SSL_CLIENT_ENABLED_PROTOCOLS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for JMX SSL configuration specified in the cassandra.yaml using
jmx_encryption_options with password files for
+ * keystore and truststores as applicable.
+ * @see JMXSslConfiguredWithYamlFileOptionsTest
+ */
+public class JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest
+{
+ static WithProperties properties;
+
+ @BeforeClass
+ public static void setupDatabaseDescriptor()
+ {
+ properties = new WithProperties().set(CASSANDRA_CONFIG,
"cassandra-jmx-sslconfig-with-passwordfile.yaml");
+ DatabaseDescriptor.daemonInitialization();
+ }
+
+ @AfterClass
+ public static void tearDownDatabaseDescriptor()
+ {
+ properties.close();
+ }
+
+ @Test
+ public void testYamlFileJmxEncryptionOptions() throws SSLException
+ {
+ JMXServerOptions serverOptions =
DatabaseDescriptor.getJmxServerOptions();
+ String expectedProtocols =
StringUtils.join(serverOptions.jmx_encryption_options.getAcceptedProtocols(),
",");
+ String expectedCipherSuites =
StringUtils.join(serverOptions.jmx_encryption_options.cipherSuitesArray(), ",");
+
+ InetAddress serverAddress = InetAddress.getLoopbackAddress();
+
+ try (WithProperties ignored = JMXSslPropertiesUtil.use(false))
+ {
+ Map<String, Object> env =
JMXServerUtils.configureJmxSocketFactories(serverAddress, serverOptions);
+ assertTrue("com.sun.management.jmxremote.ssl must be true",
COM_SUN_MANAGEMENT_JMXREMOTE_SSL.getBoolean());
+ assertNotNull("ServerSocketFactory must not be null",
env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE));
+ assertTrue("RMI_SERVER_SOCKET_FACTORY must be of
JMXSslRMIServerSocketFactory type",
env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE) instanceof
SslRMIServerSocketFactory);
+ assertNotNull("ClientSocketFactory must not be null",
env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE));
+ assertNotNull("com.sun.jndi.rmi.factory.socket must be set in the
env", env.get("com.sun.jndi.rmi.factory.socket"));
+ assertEquals("javax.rmi.ssl.client.enabledProtocols must match",
expectedProtocols, JAVAX_RMI_SSL_CLIENT_ENABLED_PROTOCOLS.getString());
+ assertEquals("javax.rmi.ssl.client.enabledCipherSuites must
match", expectedCipherSuites,
JAVAX_RMI_SSL_CLIENT_ENABLED_CIPHER_SUITES.getString());
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]