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]
