This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 03ac1aa6bd60d8a6460db72e88ccf69e27758f9c
Author: Benoit Tellier <[email protected]>
AuthorDate: Tue Oct 1 16:43:40 2019 +0700

    JAMES-2904 Cassandra session user password and ssl configuration options
---
 .../backends/cassandra/init/ClusterBuilder.java    |  24 ++++-
 .../init/configuration/ClusterConfiguration.java   |  72 +++++++++++++-
 .../backends/cassandra/CassandraWaitStrategy.java  |   2 +-
 .../james/backends/cassandra/DockerCassandra.java  |  14 ++-
 .../DockerCassandraAuthenticatedSingleton.java     |  44 ++-------
 .../destination/conf/cassandra.properties          |   3 +
 .../destination/conf/cassandra.properties          |   3 +
 .../destination/conf/cassandra.properties          |   3 +
 .../destination/conf/cassandra.properties          |   3 +
 .../modules/mailbox/ResilientClusterProvider.java  |   3 +
 .../AuthenticatedCassandraJamesServerTest.java     | 109 +++++++++++++++++++++
 ....java => CassandraAuthenticationExtension.java} |  46 ++++-----
 ...va => CassandraBadAuthenticationExtension.java} |  46 ++++-----
 .../java/org/apache/james/CassandraExtension.java  |   4 +
 src/site/xdoc/server/config-cassandra.xml          |  13 +++
 15 files changed, 289 insertions(+), 100 deletions(-)

diff --git 
a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
 
b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
index bc212b0..681992a 100644
--- 
a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
+++ 
b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
@@ -55,10 +55,12 @@ public class ClusterBuilder {
     private Optional<Integer> readTimeoutMillis;
     private Optional<Integer> connectTimeoutMillis;
     private Optional<PoolingOptions> poolingOptions;
+    private Optional<Boolean> useSsl;
 
     private ClusterBuilder() {
         username = Optional.empty();
         password = Optional.empty();
+        useSsl = Optional.empty();
 
         host = Optional.empty();
         port = Optional.empty();
@@ -71,13 +73,21 @@ public class ClusterBuilder {
     }
 
     public ClusterBuilder username(String username) {
-        this.username = Optional.of(username);
+        return username(Optional.of(username));
+    }
+
+    public ClusterBuilder password(String password) {
+        return password(Optional.of(password));
+    }
+
+    public ClusterBuilder username(Optional<String> username) {
+        this.username = username;
 
         return this;
     }
 
-    public ClusterBuilder password(String password) {
-        this.password = Optional.of(password);
+    public ClusterBuilder password(Optional<String> password) {
+        this.password = password;
 
         return this;
     }
@@ -94,6 +104,12 @@ public class ClusterBuilder {
         return this;
     }
 
+    public ClusterBuilder useSsl(boolean useSsl) {
+        this.useSsl = Optional.of(useSsl);
+
+        return this;
+    }
+
     public ClusterBuilder poolingOptions(PoolingOptions poolingOptions) {
         this.poolingOptions = Optional.of(poolingOptions);
         return this;
@@ -155,6 +171,8 @@ public class ClusterBuilder {
         clusterBuilder.withSocketOptions(socketOptions);
         poolingOptions.ifPresent(clusterBuilder::withPoolingOptions);
 
+        useSsl.filter(b -> b).ifPresent(any -> clusterBuilder.withSSL());
+
         Cluster cluster = clusterBuilder.build();
         try {
             queryLogger.map(queryLoggerConfiguration ->
diff --git 
a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
 
b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
index 5d832ca..0173373 100644
--- 
a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
+++ 
b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
@@ -46,6 +46,9 @@ public class ClusterConfiguration {
         private Optional<PoolingOptions> poolingOptions;
         private Optional<Integer> readTimeoutMillis;
         private Optional<Integer> connectTimeoutMillis;
+        private Optional<Boolean> useSsl;
+        private Optional<String> username;
+        private Optional<String> password;
 
         public Builder() {
             hosts = ImmutableList.builder();
@@ -57,6 +60,9 @@ public class ClusterConfiguration {
             poolingOptions = Optional.empty();
             readTimeoutMillis = Optional.empty();
             connectTimeoutMillis = Optional.empty();
+            username = Optional.empty();
+            password = Optional.empty();
+            useSsl = Optional.empty();
         }
 
         public Builder host(Host host) {
@@ -138,6 +144,33 @@ public class ClusterConfiguration {
             return this;
         }
 
+        public Builder username(Optional<String> username) {
+            this.username = username;
+            return this;
+        }
+
+        public Builder username(String username) {
+            return username(Optional.of(username));
+        }
+
+        public Builder password(Optional<String> password) {
+            this.password = password;
+            return this;
+        }
+
+        public Builder password(String password) {
+            return password(Optional.of(password));
+        }
+
+        public Builder useSsl(boolean useSsl) {
+            this.useSsl = Optional.of(useSsl);
+            return this;
+        }
+
+        public Builder useSsl() {
+            return useSsl(true);
+        }
+
         public Builder connectTimeoutMillis(int connectTimeoutMillis) {
             return connectTimeoutMillis(Optional.of(connectTimeoutMillis));
         }
@@ -152,12 +185,18 @@ public class ClusterConfiguration {
                 
queryLoggerConfiguration.orElse(QueryLoggerConfiguration.DEFAULT),
                 poolingOptions,
                 readTimeoutMillis.orElse(DEFAULT_READ_TIMEOUT_MILLIS),
-                connectTimeoutMillis.orElse(DEFAULT_CONNECT_TIMEOUT_MILLIS));
+                connectTimeoutMillis.orElse(DEFAULT_CONNECT_TIMEOUT_MILLIS),
+                useSsl.orElse(false),
+                username,
+                password);
         }
     }
 
     private static final String CASSANDRA_NODES = "cassandra.nodes";
     public static final String CASSANDRA_KEYSPACE = "cassandra.keyspace";
+    public static final String CASSANDRA_USER = "cassandra.user";
+    public static final String CASSANDRA_PASSWORD = "cassandra.password";
+    public static final String CASSANDRA_SSL = "cassandra.ssl";
     public static final String REPLICATION_FACTOR = 
"cassandra.replication.factor";
     public static final String READ_TIMEOUT_MILLIS = 
"cassandra.readTimeoutMillis";
     public static final String CONNECT_TIMEOUT_MILLIS = 
"cassandra.connectTimeoutMillis";
@@ -170,6 +209,7 @@ public class ClusterConfiguration {
     private static final int DEFAULT_CONNECTION_MIN_DELAY = 5000;
     private static final int DEFAULT_READ_TIMEOUT_MILLIS = 5000;
     private static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 5000;
+    private static final boolean DEFAULT_SSL = false;
 
     public static Builder builder() {
         return new Builder();
@@ -186,6 +226,9 @@ public class ClusterConfiguration {
             .poolingOptions(readPoolingOptions(configuration))
             
.readTimeoutMillis(Optional.ofNullable(configuration.getInteger(READ_TIMEOUT_MILLIS,
 null)))
             
.connectTimeoutMillis(Optional.ofNullable(configuration.getInteger(CONNECT_TIMEOUT_MILLIS,
 null)))
+            .useSsl(configuration.getBoolean(CASSANDRA_SSL, false))
+            
.username(Optional.ofNullable(configuration.getString(CASSANDRA_USER, null)))
+            
.password(Optional.ofNullable(configuration.getString(CASSANDRA_PASSWORD, 
null)))
             .build();
     }
 
@@ -237,10 +280,13 @@ public class ClusterConfiguration {
     private final Optional<PoolingOptions> poolingOptions;
     private final int readTimeoutMillis;
     private final int connectTimeoutMillis;
+    private final boolean useSsl;
+    private final Optional<String> username;
+    private final Optional<String> password;
 
     public ClusterConfiguration(List<Host> hosts, String keyspace, int 
replicationFactor, int minDelay, int maxRetry,
                                 QueryLoggerConfiguration 
queryLoggerConfiguration, Optional<PoolingOptions> poolingOptions,
-                                int readTimeoutMillis, int 
connectTimeoutMillis) {
+                                int readTimeoutMillis, int 
connectTimeoutMillis, boolean useSsl, Optional<String> username, 
Optional<String> password) {
         this.hosts = hosts;
         this.keyspace = keyspace;
         this.replicationFactor = replicationFactor;
@@ -250,6 +296,9 @@ public class ClusterConfiguration {
         this.poolingOptions = poolingOptions;
         this.readTimeoutMillis = readTimeoutMillis;
         this.connectTimeoutMillis = connectTimeoutMillis;
+        this.useSsl = useSsl;
+        this.username = username;
+        this.password = password;
     }
 
     public List<Host> getHosts() {
@@ -288,6 +337,18 @@ public class ClusterConfiguration {
         return connectTimeoutMillis;
     }
 
+    public boolean isUseSsl() {
+        return useSsl;
+    }
+
+    public Optional<String> getUsername() {
+        return username;
+    }
+
+    public Optional<String> getPassword() {
+        return password;
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof ClusterConfiguration) {
@@ -301,7 +362,10 @@ public class ClusterConfiguration {
                 && Objects.equals(this.queryLoggerConfiguration, 
that.queryLoggerConfiguration)
                 && Objects.equals(this.poolingOptions, that.poolingOptions)
                 && Objects.equals(this.readTimeoutMillis, 
that.readTimeoutMillis)
-                && Objects.equals(this.connectTimeoutMillis, 
that.connectTimeoutMillis);
+                && Objects.equals(this.connectTimeoutMillis, 
that.connectTimeoutMillis)
+                && Objects.equals(this.useSsl, that.useSsl)
+                && Objects.equals(this.username, that.username)
+                && Objects.equals(this.password, that.password);
         }
         return false;
     }
@@ -309,6 +373,6 @@ public class ClusterConfiguration {
     @Override
     public final int hashCode() {
         return Objects.hash(hosts, keyspace, replicationFactor, minDelay, 
maxRetry, queryLoggerConfiguration, poolingOptions,
-            readTimeoutMillis, connectTimeoutMillis);
+            readTimeoutMillis, connectTimeoutMillis, username, useSsl, 
password);
     }
 }
diff --git 
a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
index bb47552..cbec58c 100644
--- 
a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
+++ 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraWaitStrategy.java
@@ -50,7 +50,7 @@ public class CassandraWaitStrategy implements WaitStrategy {
         Unreliables.retryUntilTrue(Ints.checkedCast(timeout.getSeconds()), 
TimeUnit.SECONDS, () -> {
                 try {
                     return cassandraContainer
-                        .execInContainer("cqlsh", "-e", "show host")
+                        .execInContainer("cqlsh", "-u", "cassandra", "-p", 
"cassandra", "-e", "show host")
                         .getStdout()
                         .contains("Connected to Test Cluster");
                 } catch (IOException | InterruptedException e) {
diff --git 
a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
index 688ed0e..58a9a08 100644
--- 
a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
+++ 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandra.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.backends.cassandra;
 
+import java.util.function.Function;
+
 import org.apache.james.util.Host;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -26,6 +28,8 @@ import org.testcontainers.DockerClientFactory;
 import org.testcontainers.containers.GenericContainer;
 import org.testcontainers.containers.output.OutputFrame;
 import org.testcontainers.images.builder.ImageFromDockerfile;
+import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
+import org.testcontainers.images.builder.dockerfile.traits.RunStatementTrait;
 
 import com.github.dockerjava.api.DockerClient;
 import com.google.common.collect.ImmutableMap;
@@ -45,17 +49,21 @@ public class DockerCassandra {
 
     @SuppressWarnings("resource")
     public DockerCassandra() {
+        this("cassandra_3_11_3", Function.identity());
+    }
+
+    public DockerCassandra(String imageName, Function<DockerfileBuilder, 
DockerfileBuilder> additionalSteps) {
         client = DockerClientFactory.instance().client();
         boolean doNotDeleteImageAfterUsage = false;
         cassandraContainer = new GenericContainer<>(
-            new ImageFromDockerfile("cassandra_3_11_3", 
doNotDeleteImageAfterUsage)
+            new ImageFromDockerfile(imageName,doNotDeleteImageAfterUsage)
                 .withDockerfileFromBuilder(builder ->
-                    builder
+                    additionalSteps.apply(builder
                         .from("cassandra:3.11.3")
                         .env("ENV CASSANDRA_CONFIG", "/etc/cassandra")
                         .run("echo \"-Xms" + CASSANDRA_MEMORY + "M\" >> " + 
JVM_OPTIONS)
                         .run("echo \"-Xmx" + CASSANDRA_MEMORY + "M\" >> " + 
JVM_OPTIONS)
-                        .run("sed", "-i", "s/auto_snapshot: 
true/auto_snapshot: false/g", "/etc/cassandra/cassandra.yaml")
+                        .run("sed", "-i", "s/auto_snapshot: 
true/auto_snapshot: false/g", "/etc/cassandra/cassandra.yaml"))
                         .build()))
             .withTmpFs(ImmutableMap.of("/var/lib/cassandra", 
"rw,noexec,nosuid,size=200m"))
             .withExposedPorts(CASSANDRA_PORT)
diff --git 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraAuthenticatedSingleton.java
similarity index 58%
copy from 
server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
copy to 
backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraAuthenticatedSingleton.java
index a2750cc..e16f639 100644
--- 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
+++ 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/DockerCassandraAuthenticatedSingleton.java
@@ -17,44 +17,14 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james;
+package org.apache.james.backends.cassandra;
 
-import org.junit.jupiter.api.extension.ExtensionContext;
+public class DockerCassandraAuthenticatedSingleton {
+    public static final DockerCassandra singleton = new 
DockerCassandra("cassandra_3_11_3_auth",
+        dockerfileBuilder -> dockerfileBuilder
+            .run("echo 'authenticator: PasswordAuthenticator' >> 
/etc/cassandra/cassandra.yaml"));
 
-import com.google.inject.Module;
-
-public class CassandraExtension implements GuiceModuleTestExtension {
-
-    private final DockerCassandraRule cassandra;
-
-    public CassandraExtension() {
-        this(new DockerCassandraRule());
-    }
-
-    public CassandraExtension(DockerCassandraRule cassandra) {
-        this.cassandra = cassandra;
-    }
-
-    @Override
-    public void beforeAll(ExtensionContext extensionContext) {
-        cassandra.start();
-    }
-
-    @Override
-    public void afterAll(ExtensionContext extensionContext) {
-        cassandra.stop();
-    }
-
-    @Override
-    public Module getModule() {
-        return cassandra.getModule();
-    }
-
-    public void pause() {
-        cassandra.pause();
-    }
-
-    public void unpause() {
-        cassandra.unpause();
+    static {
+        singleton.start();
     }
 }
diff --git 
a/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties 
b/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties
index ea199db..cebfe65 100644
--- a/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties
+++ b/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties
@@ -3,6 +3,9 @@
 
 cassandra.nodes=cassandra
 cassandra.keyspace=apache_james
+#cassandra.user=cassandra
+#cassandra.password=cassandra
+#cassandra.ssl=false
 cassandra.replication.factor=1
 cassandra.retryConnection.maxRetries=200
 cassandra.retryConnection.minDelay=5000
diff --git 
a/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
 
b/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
index 1c63f7e..842f56d 100644
--- 
a/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
+++ 
b/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
@@ -3,6 +3,9 @@
 
 cassandra.nodes=cassandra
 cassandra.keyspace=apache_james
+#cassandra.user=cassandra
+#cassandra.password=cassandra
+#cassandra.ssl=false
 cassandra.replication.factor=1
 cassandra.retryConnection.maxRetries=200
 cassandra.retryConnection.minDelay=5000
diff --git 
a/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
 
b/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
index 1c63f7e..842f56d 100644
--- 
a/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
+++ 
b/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
@@ -3,6 +3,9 @@
 
 cassandra.nodes=cassandra
 cassandra.keyspace=apache_james
+#cassandra.user=cassandra
+#cassandra.password=cassandra
+#cassandra.ssl=false
 cassandra.replication.factor=1
 cassandra.retryConnection.maxRetries=200
 cassandra.retryConnection.minDelay=5000
diff --git 
a/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties 
b/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties
index 2cf6a10..413a2ad 100644
--- a/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties
+++ b/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties
@@ -3,6 +3,9 @@
 
 cassandra.nodes=cassandra
 cassandra.keyspace=apache_james
+#cassandra.user=cassandra
+#cassandra.password=cassandra
+#cassandra.ssl=false
 cassandra.replication.factor=1
 cassandra.retryConnection.maxRetries=200
 cassandra.retryConnection.minDelay=5000
diff --git 
a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ResilientClusterProvider.java
 
b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ResilientClusterProvider.java
index e28e6a4..979aa57 100644
--- 
a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ResilientClusterProvider.java
+++ 
b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ResilientClusterProvider.java
@@ -64,6 +64,9 @@ public class ResilientClusterProvider implements 
Provider<Cluster> {
         return () -> {
             Cluster cluster = ClusterBuilder.builder()
                     .servers(configuration.getHosts())
+                    .username(configuration.getUsername())
+                    .password(configuration.getPassword())
+                    .useSsl(configuration.isUseSsl())
                     .poolingOptions(configuration.getPoolingOptions())
                     
.queryLoggerConfiguration(configuration.getQueryLoggerConfiguration())
                     .readTimeoutMillis(configuration.getReadTimeoutMillis())
diff --git 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/AuthenticatedCassandraJamesServerTest.java
 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/AuthenticatedCassandraJamesServerTest.java
new file mode 100644
index 0000000..130f4c9
--- /dev/null
+++ 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/AuthenticatedCassandraJamesServerTest.java
@@ -0,0 +1,109 @@
+/****************************************************************
+ * 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.james;
+
+import static 
org.apache.james.CassandraJamesServerMain.ALL_BUT_JMX_CASSANDRA_MODULE;
+import static 
org.apache.james.JamesServerContract.DOMAIN_LIST_CONFIGURATION_MODULE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.commons.lang3.NotImplementedException;
+import 
org.apache.james.backends.cassandra.DockerCassandraAuthenticatedSingleton;
+import 
org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.store.search.PDFTextExtractor;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.datastax.driver.core.exceptions.AuthenticationException;
+import com.google.inject.CreationException;
+
+class AuthenticatedCassandraJamesServerTest {
+    private static final int LIMIT_TO_10_MESSAGES = 10;
+
+    @Nested
+    class AuthenticationTest implements JamesServerContract {
+        @RegisterExtension
+        JamesServerExtension testExtension = new JamesServerBuilder()
+            .extension(new DockerElasticSearchExtension())
+            .extension(new CassandraAuthenticationExtension())
+            .server(configuration -> 
GuiceJamesServer.forConfiguration(configuration)
+                .combineWith(ALL_BUT_JMX_CASSANDRA_MODULE)
+                .overrideWith(binder -> 
binder.bind(TextExtractor.class).to(PDFTextExtractor.class))
+                .overrideWith(new TestJMAPServerModule(LIMIT_TO_10_MESSAGES))
+                .overrideWith(DOMAIN_LIST_CONFIGURATION_MODULE))
+            .build();
+    }
+
+    @Nested
+    class SslTest {
+        @RegisterExtension
+        JamesServerExtension testExtension = new JamesServerBuilder()
+            .extension(new DockerElasticSearchExtension())
+            .extension(new CassandraExtension())
+            .disableAutoStart()
+            .server(configuration -> 
GuiceJamesServer.forConfiguration(configuration)
+                .combineWith(ALL_BUT_JMX_CASSANDRA_MODULE)
+                .overrideWith(binder -> 
binder.bind(TextExtractor.class).to(PDFTextExtractor.class))
+                .overrideWith(new TestJMAPServerModule(LIMIT_TO_10_MESSAGES))
+                .overrideWith(DOMAIN_LIST_CONFIGURATION_MODULE))
+            .overrideServerModule(binder -> 
binder.bind(ClusterConfiguration.class)
+                .toInstance(ClusterConfiguration.builder()
+                    
.host(DockerCassandraAuthenticatedSingleton.singleton.getHost())
+                    .keyspace("testing")
+                    .replicationFactor(1)
+                    .maxRetry(1)
+                    .minDelay(100)
+                    .useSsl()
+                    .build()))
+            .build();
+
+        @Test
+        void 
startShouldFailWhenSslUsedAndNotSupportedByServer(GuiceJamesServer jamesServer) 
{
+            assertThatThrownBy(jamesServer::start)
+                .isInstanceOf(CreationException.class)
+                .hasStackTraceContaining("Caused by: 
com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried 
for query failed");
+        }
+    }
+
+    @Nested
+    class AuthenticationFailureTest {
+        @RegisterExtension
+        JamesServerExtension testExtension = new JamesServerBuilder()
+            .extension(new DockerElasticSearchExtension())
+            .extension(new CassandraBadAuthenticationExtension())
+            .disableAutoStart()
+            .server(configuration -> 
GuiceJamesServer.forConfiguration(configuration)
+                .combineWith(ALL_BUT_JMX_CASSANDRA_MODULE)
+                .overrideWith(binder -> 
binder.bind(TextExtractor.class).to(PDFTextExtractor.class))
+                .overrideWith(new TestJMAPServerModule(LIMIT_TO_10_MESSAGES))
+                .overrideWith(DOMAIN_LIST_CONFIGURATION_MODULE))
+            .build();
+
+        @Test
+        void startShouldFailOnBadPassword(GuiceJamesServer jamesServer) {
+            assertThatThrownBy(jamesServer::start)
+                .isInstanceOf(CreationException.class)
+                .hasStackTraceContaining("Caused by: 
com.datastax.driver.core.exceptions.AuthenticationException: Authentication 
error");
+        }
+    }
+}
diff --git 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraAuthenticationExtension.java
similarity index 55%
copy from 
server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
copy to 
server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraAuthenticationExtension.java
index a2750cc..7528d6c 100644
--- 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
+++ 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraAuthenticationExtension.java
@@ -19,42 +19,36 @@
 
 package org.apache.james;
 
+import 
org.apache.james.backends.cassandra.DockerCassandraAuthenticatedSingleton;
+import 
org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.server.CassandraTruncateTableTask;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
 import com.google.inject.Module;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.util.Modules;
 
-public class CassandraExtension implements GuiceModuleTestExtension {
-
-    private final DockerCassandraRule cassandra;
-
-    public CassandraExtension() {
-        this(new DockerCassandraRule());
-    }
-
-    public CassandraExtension(DockerCassandraRule cassandra) {
-        this.cassandra = cassandra;
-    }
+public class CassandraAuthenticationExtension implements 
GuiceModuleTestExtension {
 
     @Override
     public void beforeAll(ExtensionContext extensionContext) {
-        cassandra.start();
-    }
-
-    @Override
-    public void afterAll(ExtensionContext extensionContext) {
-        cassandra.stop();
+        DockerCassandraAuthenticatedSingleton.singleton.start();
     }
 
     @Override
     public Module getModule() {
-        return cassandra.getModule();
-    }
-
-    public void pause() {
-        cassandra.pause();
-    }
-
-    public void unpause() {
-        cassandra.unpause();
+        return Modules.combine((binder) -> 
binder.bind(ClusterConfiguration.class)
+                .toInstance(ClusterConfiguration.builder()
+                    
.host(DockerCassandraAuthenticatedSingleton.singleton.getHost())
+                    .keyspace("testing")
+                    .username("cassandra")
+                    .password("cassandra")
+                    .replicationFactor(1)
+                    .maxRetry(20)
+                    .minDelay(5000)
+                    .build()),
+            binder -> Multibinder.newSetBinder(binder, 
CleanupTasksPerformer.CleanupTask.class)
+                .addBinding()
+                .to(CassandraTruncateTableTask.class));
     }
 }
diff --git 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraBadAuthenticationExtension.java
similarity index 56%
copy from 
server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
copy to 
server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraBadAuthenticationExtension.java
index a2750cc..a001393 100644
--- 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
+++ 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraBadAuthenticationExtension.java
@@ -19,42 +19,36 @@
 
 package org.apache.james;
 
+import 
org.apache.james.backends.cassandra.DockerCassandraAuthenticatedSingleton;
+import 
org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.server.CassandraTruncateTableTask;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
 import com.google.inject.Module;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.util.Modules;
 
-public class CassandraExtension implements GuiceModuleTestExtension {
-
-    private final DockerCassandraRule cassandra;
-
-    public CassandraExtension() {
-        this(new DockerCassandraRule());
-    }
-
-    public CassandraExtension(DockerCassandraRule cassandra) {
-        this.cassandra = cassandra;
-    }
+public class CassandraBadAuthenticationExtension implements 
GuiceModuleTestExtension {
 
     @Override
     public void beforeAll(ExtensionContext extensionContext) {
-        cassandra.start();
-    }
-
-    @Override
-    public void afterAll(ExtensionContext extensionContext) {
-        cassandra.stop();
+        DockerCassandraAuthenticatedSingleton.singleton.start();
     }
 
     @Override
     public Module getModule() {
-        return cassandra.getModule();
-    }
-
-    public void pause() {
-        cassandra.pause();
-    }
-
-    public void unpause() {
-        cassandra.unpause();
+        return Modules.combine((binder) -> 
binder.bind(ClusterConfiguration.class)
+                .toInstance(ClusterConfiguration.builder()
+                    
.host(DockerCassandraAuthenticatedSingleton.singleton.getHost())
+                    .keyspace("testing")
+                    .username("cassandra")
+                    .password("bad")
+                    .replicationFactor(1)
+                    .maxRetry(1)
+                    .minDelay(100)
+                    .build()),
+            binder -> Multibinder.newSetBinder(binder, 
CleanupTasksPerformer.CleanupTask.class)
+                .addBinding()
+                .to(CassandraTruncateTableTask.class));
     }
 }
diff --git 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
index a2750cc..f7d1fc4 100644
--- 
a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
+++ 
b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraExtension.java
@@ -50,6 +50,10 @@ public class CassandraExtension implements 
GuiceModuleTestExtension {
         return cassandra.getModule();
     }
 
+    public DockerCassandraRule getCassandra() {
+        return cassandra;
+    }
+
     public void pause() {
         cassandra.pause();
     }
diff --git a/src/site/xdoc/server/config-cassandra.xml 
b/src/site/xdoc/server/config-cassandra.xml
index d951fe8..3511c87 100644
--- a/src/site/xdoc/server/config-cassandra.xml
+++ b/src/site/xdoc/server/config-cassandra.xml
@@ -38,6 +38,19 @@
         <dt><strong>cassandra.keyspace</strong></dt>
         <dd>Is the name of the keyspace used by James. Optional, default 
value: <b>apache_james</b></dd>
 
+        <dt><strong>cassandra.user</strong></dt>
+        <dd>Username used as a credential for contacting Cassandra cluster. 
Optional, default is absent,
+          required if <strong>cassandra.password</strong> is supplied</dd>
+
+        <dt><strong>cassandra.password</strong></dt>
+        <dd>Password used as a credential for contacting Cassandra cluster. 
Optional, default is absent,
+          required if <strong>cassandra.user</strong> is supplied</dd>
+
+        <dt><strong>cassandra.ssl</strong></dt>
+        <dd>Wether SSL should be enabled on the communications with Cassandra 
cluster. Optional, defaults to false.<br/>
+        The keystore used for trusting SLL server socket can be set via JSSE 
system properties as explained on
+        <a 
href="https://docs.datastax.com/en/developer/java-driver/3.7/manual/ssl/";>Cassandra
 driver manual</a>.</dd>
+
         <dt><strong>cassandra.replication.factor</strong></dt>
         <dd>Is the replication factor used upon keyspace creation. Modifying 
this property while the keyspace already exists
         will have no effect. Optional. Default value 1.</dd>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to