Add support for SSL and bindable address to sidecar
Patch by Dinesh Joshi; reviewed by Vinay Chella and Chris Lohfink for CASSANDRA-15030
diff --git a/build.gradle b/build.gradle
index 5d4c771..a479649 100644
--- a/build.gradle
+++ b/build.gradle
@@ -49,7 +49,7 @@
}
test {
resources {
- srcDirs = [main.resources]
+ srcDirs = [main.resources, "src/test/resources"]
}
}
}
@@ -129,6 +129,8 @@
test {
useJUnitPlatform()
+ systemProperty "javax.net.ssl.trustStore", "$projectDir/src/test/resources/certs/ca.p12"
+ systemProperty "javax.net.ssl.trustStorePassword", "password"
}
// copyDist gets called on every build
diff --git a/conf/sidecar.yaml b/conf/sidecar.yaml
index 8ffbcc6..f7e1ce3 100644
--- a/conf/sidecar.yaml
+++ b/conf/sidecar.yaml
@@ -7,7 +7,20 @@
- port: 9042
sidecar:
+ - host: 0.0.0.0
- port: 9043
+#
+# Enable SSL configuration (Disabled by default)
+#
+# - ssl:
+# - enabled: true
+# - keystore:
+# - path: "path/to/keystore.p12"
+# - password: password
+# - truststore:
+# - path: "path/to/truststore.p12"
+# - password: password
+
healthcheck:
- - poll_freq_millis: 30000
\ No newline at end of file
+ - poll_freq_millis: 30000
diff --git a/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java b/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
index 6ab682b..aaa39f3 100644
--- a/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
+++ b/src/main/java/org/apache/cassandra/sidecar/CassandraSidecarDaemon.java
@@ -20,13 +20,15 @@
import com.google.inject.Guice;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
import io.vertx.core.http.HttpServer;
import org.apache.cassandra.sidecar.routes.HealthService;
+import org.apache.cassandra.sidecar.utils.SslUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
+@Singleton
public class CassandraSidecarDaemon
{
private static final Logger logger = LoggerFactory.getLogger(CassandraSidecarDaemon.class);
@@ -45,9 +47,10 @@
public void start()
{
banner();
+ validate();
logger.info("Starting Cassandra Sidecar on port {}", config.getPort());
healthService.start();
- server.listen();
+ server.listen(config.getPort(), config.getHost());
}
public void stop()
@@ -69,6 +72,25 @@
" ");
}
+ private void validate()
+ {
+ if (config.isSslEnabled())
+ {
+ try
+ {
+ SslUtils.validateSslOpts(config.getKeyStorePath(), config.getKeystorePassword());
+
+ if (config.getTrustStorePath() != null && config.getTruststorePassword() != null)
+ SslUtils.validateSslOpts(config.getTrustStorePath(), config.getTruststorePassword());
+ } catch (Exception e)
+ {
+ throw new RuntimeException("Invalid keystore parameters for SSL", e);
+ }
+ }
+
+ }
+
+
public static void main(String[] args)
{
CassandraSidecarDaemon app = Guice.createInjector(new MainModule())
diff --git a/src/main/java/org/apache/cassandra/sidecar/Configuration.java b/src/main/java/org/apache/cassandra/sidecar/Configuration.java
index 8086164..ed20ea0 100644
--- a/src/main/java/org/apache/cassandra/sidecar/Configuration.java
+++ b/src/main/java/org/apache/cassandra/sidecar/Configuration.java
@@ -32,9 +32,21 @@
/* Sidecar's HTTP REST API port */
private final Integer port;
+ /* Sidecar's listen address */
+ private String host;
+
/* Healthcheck frequency in miilis */
private final Integer healthCheckFrequencyMillis;
+ /* SSL related settings */
+ private final String keyStorePath;
+ private final String keyStorePassword;
+
+ private final String trustStorePath;
+ private final String trustStorePassword;
+
+ private final boolean isSslEnabled;
+
/**
* Constructor
*
@@ -42,14 +54,24 @@
* @param cassandraPort
* @param port
* @param healthCheckFrequencyMillis
+ * @param trustStorePath
+ * @param trustStorePassword
*/
- public Configuration(String cassandraHost, Integer cassandraPort, Integer port,
- Integer healthCheckFrequencyMillis)
+ public Configuration(String cassandraHost, Integer cassandraPort, String host, Integer port,
+ Integer healthCheckFrequencyMillis, String keyStorePath, String keyStorePassword,
+ String trustStorePath, String trustStorePassword, boolean isSslEnabled)
{
this.cassandraHost = cassandraHost;
this.cassandraPort = cassandraPort;
+ this.host = host;
this.port = port;
this.healthCheckFrequencyMillis = healthCheckFrequencyMillis;
+
+ this.keyStorePath = keyStorePath;
+ this.keyStorePassword = keyStorePassword;
+ this.trustStorePath = trustStorePath;
+ this.trustStorePassword = trustStorePassword;
+ this.isSslEnabled = isSslEnabled;
}
/**
@@ -73,6 +95,16 @@
}
/**
+ * Sidecar's listen address
+ *
+ * @return
+ */
+ public String getHost()
+ {
+ return host;
+ }
+
+ /**
* Get the Sidecar's REST HTTP API port
*
* @return
@@ -91,4 +123,137 @@
{
return healthCheckFrequencyMillis;
}
+
+ /**
+ * Get the SSL status
+ *
+ * @return
+ */
+ public boolean isSslEnabled()
+ {
+ return isSslEnabled;
+ }
+
+ /**
+ * Get the Keystore Path
+ *
+ * @return
+ */
+ public String getKeyStorePath()
+ {
+ return keyStorePath;
+ }
+
+ /**
+ * Get the Keystore password
+ *
+ * @return
+ */
+ public String getKeystorePassword()
+ {
+ return keyStorePassword;
+ }
+
+ /**
+ * Get the Truststore Path
+ *
+ * @return
+ */
+ public String getTrustStorePath()
+ {
+ return trustStorePath;
+ }
+
+ /**
+ * Get the Truststore password
+ *
+ * @return
+ */
+ public String getTruststorePassword()
+ {
+ return trustStorePassword;
+ }
+
+ /**
+ * Configuration Builder
+ */
+ public static class Builder
+ {
+ private String cassandraHost;
+ private Integer cassandraPort;
+ private String host;
+ private Integer port;
+ private Integer healthCheckFrequencyMillis;
+ private String keyStorePath;
+ private String keyStorePassword;
+ private String trustStorePath;
+ private String trustStorePassword;
+ private boolean isSslEnabled;
+
+ public Builder setCassandraHost(String host)
+ {
+ this.cassandraHost = host;
+ return this;
+ }
+
+ public Builder setCassandraPort(Integer port)
+ {
+ this.cassandraPort = port;
+ return this;
+ }
+
+ public Builder setHost(String host)
+ {
+ this.host = host;
+ return this;
+ }
+
+ public Builder setPort(Integer port)
+ {
+ this.port = port;
+ return this;
+ }
+
+ public Builder setHealthCheckFrequency(Integer freqMillis)
+ {
+ this.healthCheckFrequencyMillis = freqMillis;
+ return this;
+ }
+
+ public Builder setKeyStorePath(String path)
+ {
+ this.keyStorePath = path;
+ return this;
+ }
+
+ public Builder setKeyStorePassword(String password)
+ {
+ this.keyStorePassword = password;
+ return this;
+ }
+
+ public Builder setTrustStorePath(String path)
+ {
+ this.trustStorePath = path;
+ return this;
+ }
+
+ public Builder setTrustStorePassword(String password)
+ {
+ this.trustStorePassword = password;
+ return this;
+ }
+
+ public Builder setSslEnabled(boolean enabled)
+ {
+ this.isSslEnabled = enabled;
+ return this;
+ }
+
+ public Configuration build()
+ {
+ return new Configuration(cassandraHost, cassandraPort, host, port, healthCheckFrequencyMillis,
+ keyStorePath, keyStorePassword, trustStorePath, trustStorePassword, isSslEnabled);
+ }
+ }
}
diff --git a/src/main/java/org/apache/cassandra/sidecar/MainModule.java b/src/main/java/org/apache/cassandra/sidecar/MainModule.java
index 59113f2..b161bac 100644
--- a/src/main/java/org/apache/cassandra/sidecar/MainModule.java
+++ b/src/main/java/org/apache/cassandra/sidecar/MainModule.java
@@ -25,6 +25,7 @@
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.net.JksOptions;
import io.vertx.ext.dropwizard.DropwizardMetricsOptions;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.LoggerHandler;
@@ -39,12 +40,6 @@
public class MainModule extends AbstractModule
{
- @Override
- protected void configure()
- {
- bind(CassandraSidecarDaemon.class).in(Singleton.class);
- }
-
@Provides
@Singleton
public Vertx getVertx()
@@ -67,11 +62,26 @@
@Provides
@Singleton
- public HttpServer vertxServer(Vertx vertx, Configuration config, Router router)
+ public HttpServer vertxServer(Vertx vertx, Router router, Configuration conf)
{
- HttpServer server = vertx.createHttpServer(new HttpServerOptions()
- .setPort(config.getPort())
- .setLogActivity(true));
+ HttpServerOptions options = new HttpServerOptions().setLogActivity(true);
+
+ if (conf.isSslEnabled())
+ {
+ options.setKeyStoreOptions(new JksOptions()
+ .setPath(conf.getKeyStorePath())
+ .setPassword(conf.getKeystorePassword()))
+ .setSsl(conf.isSslEnabled());
+
+ if (conf.getTrustStorePath() != null && conf.getTruststorePassword() != null)
+ {
+ options.setTrustStoreOptions(new JksOptions()
+ .setPath(conf.getTrustStorePath())
+ .setPassword(conf.getTruststorePassword()));
+ }
+ }
+
+ HttpServer server = vertx.createHttpServer(options);
server.requestHandler(router);
return server;
}
@@ -102,10 +112,17 @@
File propFile = new File("sidecar.yaml");
YAMLConfiguration yamlConf = confs.fileBased(YAMLConfiguration.class, propFile);
- return new Configuration(
- yamlConf.get(String.class, "cassandra.host"),
- yamlConf.get(Integer.class, "cassandra.port"),
- yamlConf.get(Integer.class, "sidecar.port"),
- yamlConf.get(Integer.class, "healthcheck.poll_freq_millis"));
+ return new Configuration.Builder()
+ .setCassandraHost(yamlConf.get(String.class, "cassandra.host"))
+ .setCassandraPort(yamlConf.get(Integer.class, "cassandra.port"))
+ .setHost(yamlConf.get(String.class, "sidecar.host"))
+ .setPort(yamlConf.get(Integer.class, "sidecar.port"))
+ .setHealthCheckFrequency(yamlConf.get(Integer.class, "healthcheck.poll_freq_millis"))
+ .setKeyStorePath(yamlConf.get(String.class, "sidecar.ssl.keystore.path", null))
+ .setKeyStorePassword(yamlConf.get(String.class, "sidecar.ssl.keystore.password", null))
+ .setTrustStorePath(yamlConf.get(String.class, "sidecar.ssl.truststore.path", null))
+ .setTrustStorePassword(yamlConf.get(String.class, "sidecar.ssl.truststore.password", null))
+ .setSslEnabled(yamlConf.get(Boolean.class, "sidecar.ssl.enabled", false))
+ .build();
}
}
diff --git a/src/main/java/org/apache/cassandra/sidecar/utils/SslUtils.java b/src/main/java/org/apache/cassandra/sidecar/utils/SslUtils.java
new file mode 100644
index 0000000..8855f45
--- /dev/null
+++ b/src/main/java/org/apache/cassandra/sidecar/utils/SslUtils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.sidecar.utils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+/**
+ * Utility class for SSL related operations
+ */
+public class SslUtils
+{
+ /**
+ * Given the parameters, validate the keystore can be loaded and is usable
+ *
+ * @param keyStorePath
+ * @param keystorePassword
+ * @throws KeyStoreException
+ * @throws NoSuchAlgorithmException
+ * @throws IOException
+ * @throws CertificateException
+ */
+ public static void validateSslOpts(String keyStorePath, String keystorePassword) throws KeyStoreException,
+ NoSuchAlgorithmException,
+ IOException, CertificateException
+ {
+ final KeyStore ks;
+
+ if (keyStorePath.endsWith("p12"))
+ ks = KeyStore.getInstance("PKCS12");
+ else if (keyStorePath.endsWith("jks"))
+ ks = KeyStore.getInstance("JKS");
+ else
+ throw new IllegalArgumentException("Unrecognized keystore format extension: "
+ + keyStorePath.substring(keyStorePath.length() - 3));
+
+ ks.load(new FileInputStream(keyStorePath), keystorePassword.toCharArray());
+ }
+}
diff --git a/src/test/java/org/apache/cassandra/sidecar/AbstractHealthServiceTest.java b/src/test/java/org/apache/cassandra/sidecar/AbstractHealthServiceTest.java
new file mode 100644
index 0000000..90f077f
--- /dev/null
+++ b/src/test/java/org/apache/cassandra/sidecar/AbstractHealthServiceTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.sidecar;
+
+import org.junit.Assert;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpServer;
+import io.vertx.ext.web.client.WebClient;
+import io.vertx.ext.web.codec.BodyCodec;
+import io.vertx.junit5.VertxTestContext;
+import org.apache.cassandra.sidecar.mocks.MockHealthCheck;
+import org.apache.cassandra.sidecar.routes.HealthService;
+
+abstract public class AbstractHealthServiceTest
+{
+ private MockHealthCheck check;
+ private HealthService service;
+ private Vertx vertx;
+ private Configuration config;
+
+ public abstract AbstractModule getTestModule();
+ public abstract boolean isSslEnabled();
+
+ @BeforeEach
+ void setUp()
+ {
+ Injector injector = Guice.createInjector(getTestModule());
+ HttpServer server = injector.getInstance(HttpServer.class);
+
+ check = injector.getInstance(MockHealthCheck.class);
+ service = injector.getInstance(HealthService.class);
+ vertx = injector.getInstance(Vertx.class);
+ config = injector.getInstance(Configuration.class);
+
+ server.listen(config.getPort());
+ }
+
+ @AfterEach
+ void tearDown()
+ {
+ vertx.close();
+ }
+
+ @DisplayName("Should return HTTP 200 OK when check=True")
+ @Test
+ public void testHealthCheckReturns200OK(VertxTestContext testContext)
+ {
+ check.setStatus(true);
+ service.refreshNow();
+
+ WebClient client = WebClient.create(vertx);
+
+ client.get(config.getPort(), "localhost", "/api/v1/__health")
+ .as(BodyCodec.string())
+ .ssl(isSslEnabled())
+ .send(testContext.succeeding(response -> testContext.verify(() -> {
+ Assert.assertEquals(200, response.statusCode());
+ testContext.completeNow();
+ })));
+ }
+
+ @DisplayName("Should return HTTP 503 Failure when check=False")
+ @Test
+ public void testHealthCheckReturns503Failure(VertxTestContext testContext)
+ {
+ check.setStatus(false);
+ service.refreshNow();
+
+ WebClient client = WebClient.create(vertx);
+
+ client.get(config.getPort(), "localhost", "/api/v1/__health")
+ .as(BodyCodec.string())
+ .ssl(isSslEnabled())
+ .send(testContext.succeeding(response -> testContext.verify(() -> {
+ Assert.assertEquals(503, response.statusCode());
+ testContext.completeNow();
+ })));
+ }
+}
diff --git a/src/test/java/org/apache/cassandra/sidecar/HealthServiceSslTest.java b/src/test/java/org/apache/cassandra/sidecar/HealthServiceSslTest.java
new file mode 100644
index 0000000..d89d861
--- /dev/null
+++ b/src/test/java/org/apache/cassandra/sidecar/HealthServiceSslTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.sidecar;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import com.google.inject.AbstractModule;
+import io.vertx.core.Vertx;
+import io.vertx.junit5.VertxExtension;
+
+@DisplayName("Health Service SSL Test")
+@ExtendWith(VertxExtension.class)
+public class HealthServiceSslTest extends AbstractHealthServiceTest
+{
+
+ public AbstractModule getTestModule()
+ {
+ return new TestSslModule(Vertx.vertx());
+ }
+
+ public boolean isSslEnabled()
+ {
+ return true;
+ }
+}
diff --git a/src/test/java/org/apache/cassandra/sidecar/HealthServiceTest.java b/src/test/java/org/apache/cassandra/sidecar/HealthServiceTest.java
index 9a39c44..67a6220 100644
--- a/src/test/java/org/apache/cassandra/sidecar/HealthServiceTest.java
+++ b/src/test/java/org/apache/cassandra/sidecar/HealthServiceTest.java
@@ -18,88 +18,25 @@
package org.apache.cassandra.sidecar;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import io.vertx.core.Vertx;
-import io.vertx.core.http.HttpServer;
-import io.vertx.ext.web.Router;
-import io.vertx.ext.web.client.WebClient;
-import io.vertx.ext.web.codec.BodyCodec;
-import io.vertx.junit5.VertxExtension;
-import io.vertx.junit5.VertxTestContext;
-import org.apache.cassandra.sidecar.mocks.MockHealthCheck;
-import org.apache.cassandra.sidecar.routes.HealthService;
-
-import org.junit.Assert;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import com.google.inject.AbstractModule;
+import io.vertx.core.Vertx;
+import io.vertx.junit5.VertxExtension;
+
@DisplayName("Health Service Test")
@ExtendWith(VertxExtension.class)
-public class HealthServiceTest
+public class HealthServiceTest extends AbstractHealthServiceTest
{
- private MockHealthCheck check;
- private HealthService service;
- private Vertx vertx;
- private Configuration config;
- @BeforeEach
- void setUp()
+ public AbstractModule getTestModule()
{
- Injector injector = Guice.createInjector(new TestModule(Vertx.vertx()));
- HttpServer server = injector.getInstance(HttpServer.class);
- Router router = injector.getInstance(Router.class);
-
- check = injector.getInstance(MockHealthCheck.class);
- service = injector.getInstance(HealthService.class);
- vertx = injector.getInstance(Vertx.class);
- config = injector.getInstance(Configuration.class);
-
- server.listen(config.getPort());
+ return new TestModule(Vertx.vertx());
}
- @AfterEach
- void tearDown()
+ public boolean isSslEnabled()
{
- vertx.close();
- }
-
- @DisplayName("Should return HTTP 200 OK when check=True")
- @Test
- public void testHealthCheckReturns200OK(VertxTestContext testContext)
- {
- check.setStatus(true);
- service.refreshNow();
-
- WebClient client = WebClient.create(vertx);
-
- client.get(config.getPort(), "localhost", "/api/v1/__health")
- .as(BodyCodec.string())
- .send(testContext.succeeding(response -> testContext.verify(() -> {
- System.out.println(response.statusCode());
- Assert.assertEquals(200, response.statusCode());
- testContext.completeNow();
- })));
- }
-
- @DisplayName("Should return HTTP 503 Failure when check=False")
- @Test
- public void testHealthCheckReturns503Failure(VertxTestContext testContext)
- {
- check.setStatus(false);
- service.refreshNow();
-
- WebClient client = WebClient.create(vertx);
-
- client.get(config.getPort(), "localhost", "/api/v1/__health")
- .as(BodyCodec.string())
- .send(testContext.succeeding(response -> testContext.verify(() -> {
- System.out.println(response.statusCode());
- Assert.assertEquals(503, response.statusCode());
- testContext.completeNow();
- })));
+ return false;
}
}
diff --git a/src/test/java/org/apache/cassandra/sidecar/TestModule.java b/src/test/java/org/apache/cassandra/sidecar/TestModule.java
index 01061ba..0bb17ad 100644
--- a/src/test/java/org/apache/cassandra/sidecar/TestModule.java
+++ b/src/test/java/org/apache/cassandra/sidecar/TestModule.java
@@ -24,6 +24,7 @@
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.net.JksOptions;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.LoggerHandler;
import org.apache.cassandra.sidecar.mocks.MockHealthCheck;
@@ -38,12 +39,6 @@
this.vertx = vertx;
}
- @Override
- protected void configure()
- {
- bind(CassandraSidecarDaemon.class).in(Singleton.class);
- }
-
@Provides
@Singleton
public Vertx getVertx()
@@ -67,11 +62,14 @@
@Provides
@Singleton
- public HttpServer vertxServer(Vertx vertx, Configuration config, Router router)
+ public HttpServer vertxServer(Vertx vertx, Router router, Configuration conf)
{
- HttpServer server = vertx.createHttpServer(new HttpServerOptions()
- .setPort(config.getPort())
- .setLogActivity(true));
+ HttpServerOptions options = new HttpServerOptions().setLogActivity(true);
+ options.setKeyStoreOptions(new JksOptions()
+ .setPath(conf.getKeyStorePath())
+ .setPassword(conf.getKeystorePassword()))
+ .setSsl(conf.isSslEnabled());
+ HttpServer server = vertx.createHttpServer(options);
server.requestHandler(router);
return server;
}
@@ -90,10 +88,18 @@
@Singleton
public Configuration configuration()
{
- return new Configuration(
- "INVALID_FOR_TEST",
- 0,
- 6475,
- 1000);
+ return abstractConfig();
+ }
+
+ protected Configuration abstractConfig()
+ {
+ return new Configuration.Builder()
+ .setCassandraHost("INVALID_FOR_TEST")
+ .setCassandraPort(0)
+ .setHost("127.0.0.1")
+ .setPort(6475)
+ .setHealthCheckFrequency(1000)
+ .setSslEnabled(false)
+ .build();
}
}
diff --git a/src/test/java/org/apache/cassandra/sidecar/TestSslModule.java b/src/test/java/org/apache/cassandra/sidecar/TestSslModule.java
new file mode 100644
index 0000000..078327f
--- /dev/null
+++ b/src/test/java/org/apache/cassandra/sidecar/TestSslModule.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sidecar;
+
+import io.vertx.core.Vertx;
+
+public class TestSslModule extends TestModule
+{
+ public TestSslModule(Vertx vertx)
+ {
+ super(vertx);
+ }
+
+ @Override
+ public Configuration abstractConfig()
+ {
+ final String keyStorePath = TestSslModule.class.getClassLoader().getResource("certs/test.p12").getPath();
+ final String keyStorePassword = "password";
+
+ final String trustStorePath = TestSslModule.class.getClassLoader().getResource("certs/ca.p12").getPath();
+ final String trustStorePassword = "password";
+
+ return new Configuration.Builder()
+ .setCassandraHost("INVALID_FOR_TEST")
+ .setCassandraPort(0)
+ .setHost("127.0.0.1")
+ .setPort(6475)
+ .setHealthCheckFrequency(1000)
+ .setKeyStorePath(keyStorePath)
+ .setKeyStorePassword(keyStorePassword)
+ .setTrustStorePath(trustStorePath)
+ .setTrustStorePassword(trustStorePassword)
+ .setSslEnabled(true)
+ .build();
+ }
+}
diff --git a/src/test/resources/certs/ca.p12 b/src/test/resources/certs/ca.p12
new file mode 100644
index 0000000..39a1899
--- /dev/null
+++ b/src/test/resources/certs/ca.p12
Binary files differ
diff --git a/src/test/resources/certs/test.p12 b/src/test/resources/certs/test.p12
new file mode 100644
index 0000000..3436057
--- /dev/null
+++ b/src/test/resources/certs/test.p12
Binary files differ