This is an automated email from the ASF dual-hosted git repository. samt pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
commit a397a538919206506df0e960c839e457e316d7f1 Merge: 6e8d0cde9e 217490bdd8 Author: Sam Tunnicliffe <s...@apache.org> AuthorDate: Fri Jan 17 09:11:22 2025 +0000 Merge branch 'cassandra-5.0' into trunk CHANGES.txt | 3 + src/java/org/apache/cassandra/auth/Permission.java | 7 ++ src/java/org/apache/cassandra/auth/Resources.java | 28 ++++- .../cql3/statements/GrantPermissionsStatement.java | 21 ++++ .../apache/cassandra/schema/SchemaConstants.java | 10 ++ .../org/apache/cassandra/service/ClientState.java | 60 +++++++-- .../apache/cassandra/auth/GrantAndRevokeTest.java | 138 +++++++++++++++++++-- test/unit/org/apache/cassandra/cql3/CQLTester.java | 8 ++ .../apache/cassandra/service/ClientStateTest.java | 2 + .../apache/cassandra/transport/TlsTestUtils.java | 2 +- 10 files changed, 253 insertions(+), 26 deletions(-) diff --cc CHANGES.txt index 23a694b0bd,feae546032..0b12096ef1 --- a/CHANGES.txt +++ b/CHANGES.txt @@@ -167,6 -60,6 +167,9 @@@ Merged from 4.0 * Fix rendering UNSET collection types in query tracing (CASSANDRA-19880) * Fix latency reported by ideal consistency level monitoring (CASSANDRA-19651) * Do not spam log with SSLExceptions (CASSANDRA-18839) ++Merged from 3.0 ++ * Tighten up permissions on system keyspaces (CASSANDRA-20090) ++ * Fix incorrect column identifier bytes problem when renaming a column (CASSANDRA-18956) 5.0.0 5.0-rc2 diff --cc src/java/org/apache/cassandra/schema/SchemaConstants.java index 9a5e8844b2,70fcef6410..2323893c4b --- a/src/java/org/apache/cassandra/schema/SchemaConstants.java +++ b/src/java/org/apache/cassandra/schema/SchemaConstants.java @@@ -125,6 -121,16 +125,16 @@@ public final class SchemaConstant || isReplicatedSystemKeyspace(keyspaceName); } + /** + * @return whether or not the keyspace is a non-virtual, system keyspace + */ + public static boolean isNonVirtualSystemKeyspace(String keyspaceName) + { - final String lowercaseKeyspaceName = keyspaceName.toLowerCase(); ++ final String lowercaseKeyspaceName = toLowerCaseLocalized(keyspaceName); + return LOCAL_SYSTEM_KEYSPACE_NAMES.contains(lowercaseKeyspaceName) + || REPLICATED_SYSTEM_KEYSPACE_NAMES.contains(lowercaseKeyspaceName); + } + /** * Returns the set of all system keyspaces * @return all system keyspaces diff --cc test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java index 2ac0232139,69f988653f..5ddd544615 --- a/test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java +++ b/test/unit/org/apache/cassandra/auth/GrantAndRevokeTest.java @@@ -387,95 -404,110 +403,201 @@@ public class GrantAndRevokeTest extend assertWarningsContain(res.getExecutionInfo().getWarnings(), "Role '" + user + "' was not granted MODIFY on <keyspace revoke_yeah>"); } + @Test + public void testCreateTableLikeAuthorize() throws Throwable + { + useSuperUser(); + + // two keyspaces + executeNet("CREATE KEYSPACE ks1 WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}"); + executeNet("CREATE KEYSPACE ks2 WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}"); + executeNet("CREATE TABLE ks1.sourcetb (id int PRIMARY KEY, val text)"); + executeNet("CREATE USER '" + user + "' WITH PASSWORD '" + pass + "'"); + + // same keyspace + // have no select permission on source table + ResultSet res = executeNet("REVOKE SELECT ON TABLE ks1.sourcetb FROM " + user); + assertWarningsContain(res.getExecutionInfo().getWarnings(), "Role '" + user + "' was not granted SELECT on <table ks1.sourcetb>"); + + useUser(user, pass); + // Spin assert for effective auth changes. + Util.spinAssertEquals(false, () -> { + try + { + assertUnauthorizedQuery("User user has no SELECT permission on <table ks1.sourcetb> or any of its parents", - formatQuery("SELECT * FROM ks1.sourcetb LIMIT 1")); ++ formatQuery("SELECT * FROM ks1.sourcetb LIMIT 1")); + } - catch(Throwable e) ++ catch (Throwable e) + { + return true; + } + return false; + }, 10); + + assertUnauthorizedQuery("User user has no SELECT permission on <table ks1.sourcetb> or any of its parents", + "CREATE TABLE ks1.targetTb LIKE ks1.sourcetb"); + + // have select permission on source table and do not have create permission on target keyspace + useSuperUser(); + executeNet("GRANT SELECT ON TABLE ks1.sourcetb TO " + user); + res = executeNet("REVOKE CREATE ON KEYSPACE ks1 FROM " + user); + assertWarningsContain(res.getExecutionInfo().getWarnings(), "Role '" + user + "' was not granted CREATE on <keyspace ks1>"); + + useUser(user, pass); + Util.spinAssertEquals(false, () -> { + try + { + assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ks1> or any of its parents", - formatQuery("CREATE TABLE ks1.targetTb LIKE ks1.sourcetb")); ++ formatQuery("CREATE TABLE ks1.targetTb LIKE ks1.sourcetb")); + } - catch(Throwable e) ++ catch (Throwable e) + { + return true; + } + return false; + }, 10); + + assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ks1> or any of its parents", + "CREATE TABLE ks1.targetTb LIKE ks1.sourcetb"); + + // different keyspaces + // have select permission on source table and do not have create permission on target keyspace + useSuperUser(); + executeNet("GRANT SELECT ON TABLE ks1.sourcetb TO " + user); + res = executeNet("REVOKE CREATE ON KEYSPACE ks2 FROM " + user); + assertWarningsContain(res.getExecutionInfo().getWarnings(), "Role '" + user + "' was not granted CREATE on <keyspace ks2>"); + + useUser(user, pass); + Util.spinAssertEquals(false, () -> { + try + { + assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ks2> or any of its parents", - formatQuery("CREATE TABLE ks2.targetTb LIKE ks1.sourcetb")); ++ formatQuery("CREATE TABLE ks2.targetTb LIKE ks1.sourcetb")); + } - catch(Throwable e) ++ catch (Throwable e) + { + return true; + } + return false; + }, 10); + + assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ks2> or any of its parents", + "CREATE TABLE ks2.targetTb LIKE ks1.sourcetb"); + + // source keyspace and table do not exist + assertUnauthorizedQuery("User user has no SELECT permission on <table ks1.tbnotexist> or any of its parents", + "CREATE TABLE ks2.targetTb LIKE ks1.tbnotexist"); + assertUnauthorizedQuery("User user has no SELECT permission on <table ksnotexists.sourcetb> or any of its parents", + "CREATE TABLE ks2.targetTb LIKE ksnotexists.sourcetb"); + // target keyspace does not exist + assertUnauthorizedQuery("User user has no CREATE permission on <all tables in ksnotexists> or any of its parents", + "CREATE TABLE ksnotexists.targetTb LIKE ks1.sourcetb"); ++ } ++ + @Test + public void testSpecificGrantsOnSystemKeyspaces() throws Throwable + { + // Granting specific permissions on system keyspaces should not be allowed if those permissions include any from + // the denylist Permission.INVALID_FOR_SYSTEM_KEYSPACES. By this definition, GRANT ALL on any system keyspace, + // or a table within one, should be rejected. + useSuperUser(); + executeNet("CREATE ROLE '" + user + "'"); + String responseMsg = "Granting permissions on system keyspaces is strictly limited, this operation is not permitted"; + for (String keyspace : Iterables.concat(LOCAL_SYSTEM_KEYSPACE_NAMES, REPLICATED_SYSTEM_KEYSPACE_NAMES)) + { + assertUnauthorizedQuery(responseMsg, format("GRANT ALL PERMISSIONS ON KEYSPACE %s TO %s", keyspace, user)); + DataResource keyspaceResource = DataResource.keyspace(keyspace); + for (Permission p : keyspaceResource.applicablePermissions()) + maybeRejectGrant(p, responseMsg, format("GRANT %s ON KEYSPACE %s TO %s", p.name(), keyspace, user)); + + assertUnauthorizedQuery(responseMsg, format("GRANT ALL PERMISSIONS ON ALL TABLES IN KEYSPACE %s TO %s", keyspace, user)); + for (TableMetadata table : Schema.instance.getKeyspaceMetadata(keyspace).tables) + { + DataResource tableResource = DataResource.table(keyspace, table.name); + assertUnauthorizedQuery(responseMsg, format("GRANT ALL PERMISSIONS ON %s TO %s", table, user)); + for (Permission p : tableResource.applicablePermissions()) + maybeRejectGrant(p, responseMsg, format("GRANT %s ON %s TO %s", p.name(), table, user)); + } + } + } + @Test + public void testGrantOnAllKeyspaces() throws Throwable + { + // Granting either specific or ALL permissions on ALL KEYSPACES is allowed, however these permissions are + // effective for non-system keyspaces only. If for any reason it is necessary to modify permissions on + // on a system keyspace, it must be done using keyspace specific grant statements. + useSuperUser(); + executeNet(String.format("CREATE ROLE %s WITH LOGIN = TRUE AND password='%s'", user, pass)); + executeNet(String.format("ALTER KEYSPACE %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}", SchemaConstants.TRACE_KEYSPACE_NAME)); + executeNet("CREATE KEYSPACE user_keyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}"); + executeNet("CREATE TABLE user_keyspace.t1 (k int PRIMARY KEY)"); + useUser(user, pass); + + assertUnauthorizedQuery("User user has no MODIFY permission on <table user_keyspace.t1> or any of its parents", + "INSERT INTO user_keyspace.t1 (k) VALUES (0)"); + assertUnauthorizedQuery("User user has no MODIFY permission on <table system.local> or any of its parents", + "INSERT INTO system.local(key) VALUES ('invalid')"); + + useSuperUser(); + executeNet(ProtocolVersion.CURRENT, format("GRANT MODIFY ON ALL KEYSPACES TO %s", user)); + + useUser(user, pass); + // User now has write permission on non-system keyspaces only + executeNet(ProtocolVersion.CURRENT, "INSERT INTO user_keyspace.t1 (k) VALUES (0)"); + assertUnauthorizedQuery("User user has no MODIFY permission on <table system.local> or any of its parents", + "INSERT INTO system.local(key) VALUES ('invalid')"); + + // A non-superuser only has read access to a pre-defined set of system tables and all system_schema/traces + // tables and granting ALL permissions on ALL keyspaces also does not affect this. + maybeReadSystemTables(false); + useSuperUser(); + executeNet(ProtocolVersion.CURRENT, format("GRANT ALL PERMISSIONS ON ALL KEYSPACES TO %s", user)); + maybeReadSystemTables(false); + + // A superuser can still read system tables + useSuperUser(); + maybeReadSystemTables(true); + // and also write to them, though this is still strongly discouraged + executeNet(ProtocolVersion.CURRENT, "INSERT INTO system.peers_v2(peer, peer_port, data_center) VALUES ('127.0.100.100', 7012, 'invalid_dc')"); + } + + private void maybeReadSystemTables(boolean superuser) throws Throwable + { + if (superuser) + useSuperUser(); + else + useUser(user, pass); + + Set<String> readableKeyspaces = new HashSet<>(Arrays.asList(SCHEMA_KEYSPACE_NAME, TRACE_KEYSPACE_NAME)); + Set<String> readableSystemTables = new HashSet<>(Arrays.asList(SystemKeyspace.LOCAL, + SystemKeyspace.PEERS_V2, + SystemKeyspace.LEGACY_PEERS, + SystemKeyspace.LEGACY_SIZE_ESTIMATES, + SystemKeyspace.TABLE_ESTIMATES)); + + for (String keyspace : Iterables.concat(LOCAL_SYSTEM_KEYSPACE_NAMES, REPLICATED_SYSTEM_KEYSPACE_NAMES)) + { + for (TableMetadata table : Schema.instance.getKeyspaceMetadata(keyspace).tables) + { + if (superuser || (readableKeyspaces.contains(keyspace) || (keyspace.equals(SYSTEM_KEYSPACE_NAME) && readableSystemTables.contains(table.name)))) + { + executeNet(ProtocolVersion.CURRENT, ConsistencyLevel.ONE, format("SELECT * FROM %s LIMIT 1", table)); + } + else + { + assertUnauthorizedQuery(format("User %s has no SELECT permission on %s or any of its parents", user, table.resource), + format("SELECT * FROM %s LIMIT 1", table)); + } + } + } + } + + private void maybeRejectGrant(Permission p, String errorResponse, String grant) throws Throwable + { + if (Permission.INVALID_FOR_SYSTEM_KEYSPACES.contains(p)) + assertUnauthorizedQuery(errorResponse, grant); + else + executeNet(ProtocolVersion.CURRENT, grant); } } diff --cc test/unit/org/apache/cassandra/service/ClientStateTest.java index f037eb2c35,b6df9c7cba..349b649ed1 --- a/test/unit/org/apache/cassandra/service/ClientStateTest.java +++ b/test/unit/org/apache/cassandra/service/ClientStateTest.java @@@ -50,6 -55,12 +50,8 @@@ public class ClientStateTes properties = new WithProperties().set(ORG_APACHE_CASSANDRA_DISABLE_MBEAN_REGISTRATION, true); SchemaLoader.prepareServer(); DatabaseDescriptor.setAuthFromRoot(true); - // create the system_auth keyspace so the IRoleManager can function as normal - SchemaLoader.createKeyspace(SchemaConstants.AUTH_KEYSPACE_NAME, - KeyspaceParams.simple(1), - Iterables.toArray(AuthKeyspace.metadata().tables, TableMetadata.class)); + DatabaseDescriptor.setRoleManager(new AuthTestUtils.LocalCassandraRoleManager()); + DatabaseDescriptor.getRoleManager().setup(); Roles.init(); AuthCacheService.initializeAndRegisterCaches(); } diff --cc test/unit/org/apache/cassandra/transport/TlsTestUtils.java index 24f3124f86,0000000000..f3994e7613 mode 100644,000000..100644 --- a/test/unit/org/apache/cassandra/transport/TlsTestUtils.java +++ b/test/unit/org/apache/cassandra/transport/TlsTestUtils.java @@@ -1,222 -1,0 +1,222 @@@ +/* + * 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.transport; + +import java.io.File; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.file.Path; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import javax.net.ssl.SSLException; + +import com.google.common.collect.ImmutableMap; + +import com.datastax.driver.core.PlainTextAuthProvider; +import com.datastax.driver.core.RemoteEndpointAwareJdkSSLOptions; +import com.datastax.driver.core.SSLOptions; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.policies.LoadBalancingPolicy; +import org.apache.cassandra.config.Config; +import org.apache.cassandra.config.EncryptionOptions; +import org.apache.cassandra.config.ParameterizedClass; +import org.apache.cassandra.distributed.api.ICluster; +import org.apache.cassandra.distributed.api.IInvokableInstance; +import org.apache.cassandra.distributed.shared.ClusterUtils; +import org.apache.cassandra.distributed.util.Auth; +import org.apache.cassandra.distributed.util.SingleHostLoadBalancingPolicy; +import org.apache.cassandra.security.ISslContextFactory; +import org.apache.cassandra.utils.tls.CertificateBuilder; +import org.apache.cassandra.utils.tls.CertificateBundle; + +import static org.apache.cassandra.auth.CassandraRoleManager.DEFAULT_SUPERUSER_NAME; +import static org.apache.cassandra.auth.CassandraRoleManager.DEFAULT_SUPERUSER_PASSWORD; + +public class TlsTestUtils +{ + public static String SERVER_KEYSTORE_PATH = "test/conf/cassandra_ssl_test.keystore"; + 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_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_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"; + + // To regenerate: + // 1. generate keystore + // keytool -genkeypair -keystore test/conf/cassandra_ssl_test_spiffe.keystore -validity 100000 -keyalg RSA -dname "CN=Apache Cassandra, OU=ssl_test, O=Unknown, L=Unknown, ST=Unknown, C=Unknown" -keypass cassandra -storepass cassandra -alias spiffecert -ext SAN=URI:spiffe://test.cassandra.apache.org/unitTest/mtls -storetype jks + // 2. export cert + // keytool -export -alias spiffecert -file spiffecert.cer -keystore test/conf/cassandra_ssl_test_spiffe.keystore + // 3. import cert into truststore + // keytool -import -v -trustcacerts -alias spiffecert -file spiffecert.cer -keystore test/conf/cassandra_ssl_test.truststore + public static String CLIENT_SPIFFE_KEYSTORE_PATH = "test/conf/cassandra_ssl_test_spiffe.keystore"; + public static String CLIENT_SPIFFE_KEYSTORE_PASSWORD = "cassandra"; + public static String CLIENT_SPIFFE_IDENTITY = "spiffe://test.cassandra.apache.org/unitTest/mtls"; + + public static String CLIENT_TRUSTSTORE_PATH = "test/conf/cassandra_ssl_test.truststore"; + public static String CLIENT_TRUSTSTORE_PASSWORD = "cassandra"; + + public static EncryptionOptions getClientEncryptionOptions() + { + return new EncryptionOptions(new EncryptionOptions() + .withEnabled(true) + .withRequireClientAuth(EncryptionOptions.ClientAuth.OPTIONAL) + .withOptional(true) + .withKeyStore(SERVER_KEYSTORE_PATH) + .withKeyStorePassword(SERVER_KEYSTORE_PASSWORD) + .withTrustStore(SERVER_TRUSTSTORE_PATH) + .withTrustStorePassword(SERVER_TRUSTSTORE_PASSWORD) + .withRequireEndpointVerification(false)); + } + + public static void configureWithMutualTlsWithPasswordFallbackAuthenticator(Config config) + { + // Configure an authenticator that supports multiple authentication mechanisms. + Map<String, String> parameters = Collections.singletonMap("validator_class_name", "org.apache.cassandra.auth.SpiffeCertificateValidator"); + config.authenticator = new ParameterizedClass("MutualTlsWithPasswordFallbackAuthenticator", parameters); + // Configure client encryption such that we can optionally connect with SSL. + config.client_encryption_options = TlsTestUtils.getClientEncryptionOptions(); + config.role_manager = new ParameterizedClass("CassandraRoleManager"); + config.authorizer = new ParameterizedClass("CassandraAuthorizer"); + } + + public static ISslContextFactory getClientSslContextFactory(boolean provideClientCert) + { + ImmutableMap.Builder<String, Object> params = ImmutableMap.<String, Object>builder() + .put("truststore", CLIENT_TRUSTSTORE_PATH) + .put("truststore_password", CLIENT_TRUSTSTORE_PASSWORD); + + if (provideClientCert) + { + params.put("keystore", CLIENT_SPIFFE_KEYSTORE_PATH) + .put("keystore_password", CLIENT_SPIFFE_KEYSTORE_PASSWORD); + } + + return new SimpleClientSslContextFactory(params.build()); + } + + public static SSLOptions getSSLOptions(boolean provideClientCert) throws SSLException + { + return RemoteEndpointAwareJdkSSLOptions.builder() + .withSSLContext(getClientSslContextFactory(provideClientCert) + .createJSSESslContext(EncryptionOptions.ClientAuth.OPTIONAL)) + .build(); + } + + public static SSLOptions getSSLOptions(Path keystorePath, Path truststorePath) throws RuntimeException + { + try + { + return RemoteEndpointAwareJdkSSLOptions.builder() + .withSSLContext(getClientSslContextFactory(keystorePath, truststorePath) + .createJSSESslContext(EncryptionOptions.ClientAuth.OPTIONAL)) + .build(); + } + catch (SSLException e) + { + throw new RuntimeException(e); + } + } + + private static ISslContextFactory getClientSslContextFactory(Path keystorePath, Path truststorePath) + { + ImmutableMap.Builder<String, Object> params = ImmutableMap.<String, Object>builder() + .put("truststore", truststorePath.toString()) + .put("truststore_password", CLIENT_TRUSTSTORE_PASSWORD); + + if (keystorePath != null) + { + params.put("keystore", keystorePath.toString()) + .put("keystore_password", "cassandra"); + } + + return new SimpleClientSslContextFactory(params.build()); + } + + public static void configureIdentity(ICluster<IInvokableInstance> cluster, SSLOptions sslOptions) + { + withAuthenticatedSession(cluster.get(1), DEFAULT_SUPERUSER_NAME, DEFAULT_SUPERUSER_PASSWORD, session -> { + session.execute("CREATE ROLE cassandra_ssl_test WITH LOGIN = true"); + session.execute(String.format("ADD IDENTITY '%s' TO ROLE 'cassandra_ssl_test'", CLIENT_SPIFFE_IDENTITY)); + // GRANT select to cassandra_ssl_test to be able to query the system_views.clients virtual table - session.execute("GRANT SELECT ON ALL KEYSPACES to cassandra_ssl_test"); ++ session.execute("GRANT SELECT ON system_views.clients to cassandra_ssl_test"); + }, sslOptions); + } + + public static Path generateSelfSignedCertificate(Function<CertificateBuilder, CertificateBuilder> customizeCertificate, File targetDirectory) throws Exception + { + return generateClientCertificate(customizeCertificate, targetDirectory, null); + } + + public static Path generateClientCertificate(Function<CertificateBuilder, CertificateBuilder> customizeCertificate, File targetDirectory, CertificateBundle ca) throws Exception + { + CertificateBuilder builder = new CertificateBuilder().subject("CN=Apache Cassandra, OU=ssl_test, O=Unknown, L=Unknown, ST=Unknown, C=Unknown") + .notBefore(Instant.now().minus(1, ChronoUnit.DAYS)) + .notAfter(Instant.now().plus(1, ChronoUnit.DAYS)) + .alias("spiffecert") + .addSanUriName(CLIENT_SPIFFE_IDENTITY) + .rsa2048Algorithm(); + if (customizeCertificate != null) + { + builder = customizeCertificate.apply(builder); + } + CertificateBundle ssc = ca != null + ? builder.buildIssuedBy(ca) + : builder.buildSelfSigned(); + return ssc.toTempKeyStorePath(targetDirectory.toPath(), SERVER_KEYSTORE_PASSWORD.toCharArray(), SERVER_KEYSTORE_PASSWORD.toCharArray()); + } + + public static void withAuthenticatedSession(IInvokableInstance instance, + String username, + String password, + Consumer<Session> consumer, + SSLOptions sslOptions) + { + // wait for existing roles + Auth.waitForExistingRoles(instance); + + InetSocketAddress nativeInetSocketAddress = ClusterUtils.getNativeInetSocketAddress(instance); + InetAddress address = nativeInetSocketAddress.getAddress(); + LoadBalancingPolicy lbc = new SingleHostLoadBalancingPolicy(address); + + com.datastax.driver.core.Cluster.Builder builder = com.datastax.driver.core.Cluster.builder() + .withLoadBalancingPolicy(lbc) + .withSSL(sslOptions) + .withAuthProvider(new PlainTextAuthProvider(username, password)) + .addContactPoint(address.getHostAddress()) + .withPort(nativeInetSocketAddress.getPort()); + + try (com.datastax.driver.core.Cluster c = builder.build(); Session session = c.connect()) + { + consumer.accept(session); + } + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org