11package org .testcontainers .cassandra ;
22
33import com .datastax .oss .driver .api .core .CqlSession ;
4+ import com .datastax .oss .driver .api .core .CqlSessionBuilder ;
5+ import com .datastax .oss .driver .api .core .config .DefaultDriverOption ;
6+ import com .datastax .oss .driver .api .core .config .DriverConfigLoader ;
7+ import com .datastax .oss .driver .api .core .config .ProgrammaticDriverConfigLoaderBuilder ;
8+ import com .datastax .oss .driver .api .core .context .DriverContext ;
49import com .datastax .oss .driver .api .core .cql .ResultSet ;
510import com .datastax .oss .driver .api .core .cql .Row ;
11+ import com .datastax .oss .driver .api .core .session .ProgrammaticArguments ;
12+ import com .datastax .oss .driver .internal .core .context .DefaultDriverContext ;
13+ import com .datastax .oss .driver .internal .core .ssl .DefaultSslEngineFactory ;
614import org .junit .Test ;
715import org .testcontainers .containers .ContainerLaunchException ;
816import org .testcontainers .utility .DockerImageName ;
917
18+ import java .net .URL ;
19+
1020import static org .assertj .core .api .Assertions .assertThat ;
21+ import static org .assertj .core .api .Assertions .fail ;
1122
1223public class CassandraContainerTest {
1324
14- private static final String CASSANDRA_IMAGE = "cassandra:3.11.2 " ;
25+ private static final String CASSANDRA_IMAGE = "cassandra:3.11.15 " ;
1526
1627 private static final String TEST_CLUSTER_NAME_IN_CONF = "Test Cluster Integration Test" ;
1728
@@ -20,7 +31,7 @@ public class CassandraContainerTest {
2031 @ Test
2132 public void testSimple () {
2233 try ( // container-definition {
23- CassandraContainer cassandraContainer = new CassandraContainer ("cassandra:3.11.2" )
34+ CassandraContainer cassandraContainer = new CassandraContainer (CASSANDRA_IMAGE )
2435 // }
2536 ) {
2637 cassandraContainer .start ();
@@ -60,6 +71,46 @@ public void testConfigurationOverride() {
6071 }
6172 }
6273
74+ @ Test
75+ public void testWithSslClientConfig () {
76+ /*
77+ Commands executed to generate certificates in 'cassandra-ssl-configuration' directory:
78+ keytool -genkey -keyalg RSA -validity 36500 -alias localhost -keystore keystore.p12 -storepass cassandra \
79+ -keypass cassandra -dname "CN=localhost, OU=Testcontainers, O=Testcontainers, L=None, C=None"
80+ keytool -export -alias localhost -file cassandra.cer -keystore keystore.p12
81+ keytool -import -v -trustcacerts -alias localhost -file cassandra.cer -keystore truststore.p12
82+
83+ Commands executed to generate the client certificate and key in 'client-ssl' directory:
84+ keytool -importkeystore -srckeystore keystore.p12 -destkeystore test_node.p12 -deststoretype PKCS12 \
85+ -srcstorepass cassandra -deststorepass cassandra
86+ openssl pkcs12 -in test_node.p12 -nokeys -out cassandra.cer.pem -passin pass:cassandra
87+ openssl pkcs12 -in test_node.p12 -nodes -nocerts -out cassandra.key.pem -passin pass:cassandra
88+
89+ Reference:
90+ https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/configuration/secureSSLCertificates.html
91+ https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/configuration/secureCqlshSSL.html
92+ */
93+ try (
94+ // with-ssl-config {
95+ CassandraContainer cassandraContainer = new CassandraContainer (CASSANDRA_IMAGE )
96+ .withConfigurationOverride ("cassandra-ssl-configuration" )
97+ .withSslClientConfig ("client-ssl/cassandra.cer.pem" , "client-ssl/cassandra.key.pem" )
98+ // }
99+ ) {
100+ cassandraContainer .start ();
101+ try {
102+ ResultSet resultSet = performQueryWithSslClientConfig (cassandraContainer ,
103+ "SELECT cluster_name FROM system.local" );
104+ assertThat (resultSet .wasApplied ()).as ("Query was applied" ).isTrue ();
105+ assertThat (resultSet .one ().getString (0 ))
106+ .as ("Cassandra configuration is configured with secured connection" )
107+ .isEqualTo (TEST_CLUSTER_NAME_IN_CONF );
108+ } catch (Exception e ) {
109+ fail (e );
110+ }
111+ }
112+ }
113+
63114 @ Test (expected = ContainerLaunchException .class )
64115 public void testEmptyConfigurationOverride () {
65116 try (
@@ -153,6 +204,30 @@ private ResultSet performQueryWithAuth(CassandraContainer cassandraContainer, St
153204 return performQuery (cqlSession , cql );
154205 }
155206
207+ private ResultSet performQueryWithSslClientConfig (CassandraContainer cassandraContainer ,
208+ String cql ) {
209+ final ProgrammaticDriverConfigLoaderBuilder driverConfigLoaderBuilder =
210+ DriverConfigLoader .programmaticBuilder ();
211+ driverConfigLoaderBuilder .withBoolean (DefaultDriverOption .SSL_HOSTNAME_VALIDATION , false );
212+ final URL trustStoreUrl = this .getClass ().getClassLoader ()
213+ .getResource ("cassandra-ssl-configuration/truststore.p12" );
214+ driverConfigLoaderBuilder .withString (DefaultDriverOption .SSL_TRUSTSTORE_PATH , trustStoreUrl .getFile ());
215+ driverConfigLoaderBuilder .withString (DefaultDriverOption .SSL_TRUSTSTORE_PASSWORD , "cassandra" );
216+ final URL keyStoreUrl = this .getClass ().getClassLoader ()
217+ .getResource ("cassandra-ssl-configuration/keystore.p12" );
218+ driverConfigLoaderBuilder .withString (DefaultDriverOption .SSL_KEYSTORE_PATH , keyStoreUrl .getFile ());
219+ driverConfigLoaderBuilder .withString (DefaultDriverOption .SSL_KEYSTORE_PASSWORD , "cassandra" );
220+ final DriverContext driverContext = new DefaultDriverContext (driverConfigLoaderBuilder .build (),
221+ ProgrammaticArguments .builder ().build ());
222+
223+ final CqlSessionBuilder sessionBuilder = CqlSession .builder ();
224+ final CqlSession cqlSession = sessionBuilder .addContactPoint (cassandraContainer .getContactPoint ())
225+ .withLocalDatacenter (cassandraContainer .getLocalDatacenter ())
226+ .withSslEngineFactory (new DefaultSslEngineFactory (driverContext ))
227+ .build ();
228+ return performQuery (cqlSession , cql );
229+ }
230+
156231 private ResultSet performQuery (CqlSession session , String cql ) {
157232 final ResultSet rs = session .execute (cql );
158233 session .close ();
0 commit comments