diff --git a/pom.xml b/pom.xml
index 494510f..8662932 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,7 @@
UTF-8
+ 1.0.2.5
@@ -89,6 +90,13 @@
5.11.0
test
+
+
+ org.bouncycastle
+ bc-fips
+ ${bc-fips.version}
+ test
+
diff --git a/src/main/java/org/folio/edge/core/Constants.java b/src/main/java/org/folio/edge/core/Constants.java
index ca092fc..cf03dab 100644
--- a/src/main/java/org/folio/edge/core/Constants.java
+++ b/src/main/java/org/folio/edge/core/Constants.java
@@ -118,9 +118,33 @@ private Constants() {
defaultMap.put(SYS_HTTP_SERVER_SSL_ENABLED,
Boolean.parseBoolean(System.getProperty(SYS_HTTP_SERVER_SSL_ENABLED,
Boolean.toString(DEFAULT_SSL_ENABLED))));
+ defaultMap.put(SYS_HTTP_SERVER_KEYSTORE_TYPE,
+ System.getProperty(SYS_HTTP_SERVER_KEYSTORE_TYPE));
+ defaultMap.put(SYS_HTTP_SERVER_KEYSTORE_PROVIDER,
+ System.getProperty(SYS_HTTP_SERVER_KEYSTORE_PROVIDER));
+ defaultMap.put(SYS_HTTP_SERVER_KEYSTORE_PATH,
+ System.getProperty(SYS_HTTP_SERVER_KEYSTORE_PATH));
+ defaultMap.put(SYS_HTTP_SERVER_KEYSTORE_PASSWORD,
+ System.getProperty(SYS_HTTP_SERVER_KEYSTORE_PASSWORD));
+ defaultMap.put(SYS_HTTP_SERVER_KEY_ALIAS,
+ System.getProperty(SYS_HTTP_SERVER_KEY_ALIAS));
+ defaultMap.put(SYS_HTTP_SERVER_KEY_ALIAS_PASSWORD,
+ System.getProperty(SYS_HTTP_SERVER_KEY_ALIAS_PASSWORD));
defaultMap.put(SYS_WEB_CLIENT_SSL_ENABLED,
Boolean.parseBoolean(System.getProperty(SYS_WEB_CLIENT_SSL_ENABLED,
Boolean.toString(DEFAULT_SSL_ENABLED))));
+ defaultMap.put(SYS_WEB_CLIENT_TRUSTSTORE_TYPE,
+ System.getProperty(SYS_WEB_CLIENT_TRUSTSTORE_TYPE));
+ defaultMap.put(SYS_WEB_CLIENT_TRUSTSTORE_PROVIDER,
+ System.getProperty(SYS_WEB_CLIENT_TRUSTSTORE_PROVIDER));
+ defaultMap.put(SYS_WEB_CLIENT_TRUSTSTORE_PATH,
+ System.getProperty(SYS_WEB_CLIENT_TRUSTSTORE_PATH));
+ defaultMap.put(SYS_WEB_CLIENT_TRUSTSTORE_PASSWORD,
+ System.getProperty(SYS_WEB_CLIENT_TRUSTSTORE_PASSWORD));
+ defaultMap.put(SYS_WEB_CLIENT_KEY_ALIAS,
+ System.getProperty(SYS_WEB_CLIENT_KEY_ALIAS));
+ defaultMap.put(SYS_WEB_CLIENT_KEY_ALIAS_PASSWORD,
+ System.getProperty(SYS_WEB_CLIENT_KEY_ALIAS_PASSWORD));
defaultMap.put(SYS_SECURE_STORE_PROP_FILE,
System.getProperty(SYS_SECURE_STORE_PROP_FILE));
defaultMap.put(SYS_OKAPI_URL,
diff --git a/src/test/java/org/folio/edge/core/EdgeVerticleTlsIntegrationTest.java b/src/test/java/org/folio/edge/core/EdgeVerticleTlsIntegrationTest.java
new file mode 100644
index 0000000..c6cc471
--- /dev/null
+++ b/src/test/java/org/folio/edge/core/EdgeVerticleTlsIntegrationTest.java
@@ -0,0 +1,147 @@
+package org.folio.edge.core;
+
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.vertx.core.AsyncResult;
+import io.vertx.core.Vertx;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.core.http.HttpServer;
+import io.vertx.core.http.HttpServerOptions;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.unit.TestContext;
+import io.vertx.ext.unit.junit.VertxUnitRunner;
+import io.vertx.ext.web.client.WebClient;
+import io.vertx.ext.web.client.WebClientOptions;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
+import org.folio.edge.core.utils.OkapiClient;
+import org.folio.edge.core.utils.OkapiClientFactory;
+import org.folio.edge.core.utils.OkapiClientFactoryInitializer;
+import org.folio.edge.core.utils.SslConfigurationUtil;
+import org.folio.edge.core.utils.test.TestUtils;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.security.Security;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(VertxUnitRunner.class)
+public class EdgeVerticleTlsIntegrationTest {
+
+ private static final Logger logger = LogManager.getLogger(EdgeVerticleTlsIntegrationTest.class);
+ private static Vertx vertx;
+
+ private static final String KEYSTORE_TYPE = "BCFKS";
+ private static final String KEYSTORE_PATH = "test.keystore 1.bcfks";
+ private static final String TRUST_STORE_PATH = "test.truststore 1.bcfks";
+ private static final String KEYSTORE_PASSWORD = "SecretPassword";
+ private static final String RESPONSE_MESSAGE = "";
+ private static final String OKAPI_URL = "http://localhost:" + TestUtils.getPort();
+ private static final String TENANT = "diku";
+
+ @Before
+ public void setUpOnce() {
+ Security.addProvider(new BouncyCastleFipsProvider());
+ vertx = Vertx.vertx();
+ }
+
+ @After
+ public void tearDown(TestContext context) {
+ vertx.close(context.asyncAssertSuccess());
+ }
+
+ @Test
+ public void testServerClientTlsCommunication(TestContext context) throws IllegalAccessException {
+ final JsonObject config = getCommonConfig(true);
+
+ final HttpServerOptions serverOptions = new HttpServerOptions();
+ serverOptions.setPort(config.getInteger(Constants.SYS_PORT));
+
+ SslConfigurationUtil.configureSslServerOptionsIfEnabled(config, serverOptions);
+
+ final HttpServer httpServer = vertx.createHttpServer(serverOptions);
+ httpServer
+ .requestHandler(req -> req.response().putHeader(HttpHeaders.CONTENT_TYPE, Constants.TEXT_PLAIN).end(RESPONSE_MESSAGE))
+ .listen(config.getInteger(Constants.SYS_PORT), getCommonServerHandler(config));
+
+ final OkapiClientFactory okapiClientFactory = OkapiClientFactoryInitializer.createInstance(vertx, config);
+ final OkapiClient okapiClient = okapiClientFactory.getOkapiClient(TENANT);
+ final WebClientOptions webClientOptions = (WebClientOptions) FieldUtils.readDeclaredField(okapiClient.client, "options", true);
+
+ assertTrue(webClientOptions.isSsl());
+ assertNotNull(webClientOptions.getTrustOptions());
+
+ createClientRequest(context, webClientOptions, config);
+ }
+
+ @Test(expected = java.net.ConnectException.class)
+ public void testFailingServerClientTlsCommunication(TestContext context) throws IllegalAccessException {
+ final JsonObject config = getCommonConfig(false);
+
+ final HttpServerOptions serverOptions = new HttpServerOptions();
+ serverOptions.setPort(config.getInteger(Constants.SYS_PORT));
+
+ SslConfigurationUtil.configureSslServerOptionsIfEnabled(config, serverOptions);
+
+ final HttpServer httpServer = vertx.createHttpServer(serverOptions);
+ httpServer
+ .requestHandler(req -> req.response().putHeader(HttpHeaders.CONTENT_TYPE, Constants.TEXT_PLAIN).end(RESPONSE_MESSAGE))
+ .listen(config.getInteger(Constants.SYS_PORT), getCommonServerHandler(config));
+
+ final OkapiClientFactory okapiClientFactory = OkapiClientFactoryInitializer.createInstance(vertx, config);
+ final OkapiClient okapiClient = okapiClientFactory.getOkapiClient(TENANT);
+ final WebClientOptions webClientOptions = (WebClientOptions) FieldUtils.readDeclaredField(okapiClient.client, "options", true);
+
+ assertFalse(webClientOptions.isSsl());
+ assertNull(webClientOptions.getTrustOptions());
+
+ createClientRequest(context, webClientOptions, config);
+ }
+
+ private static io.vertx.core.@NotNull Handler> getCommonServerHandler(JsonObject config) {
+ return http -> logger.info("Server started on port {}", config.getInteger(Constants.SYS_PORT));
+ }
+
+ private static void createClientRequest(TestContext context, WebClientOptions webClientOptions, JsonObject config) {
+ final WebClient webClient = WebClient.create(vertx, webClientOptions);
+ webClient.get(config.getInteger(Constants.SYS_PORT), "localhost", "/")
+ .send()
+ .onComplete(context.asyncAssertSuccess(response -> {
+ String message = response.body().toString();
+ logger.info("WebClient sent message to server port {}, response message: {}", config.getInteger(Constants.SYS_PORT), message);
+ context.assertEquals(HttpResponseStatus.OK.code(), response.statusCode());
+ context.assertEquals(RESPONSE_MESSAGE, message);
+ }));
+ }
+
+ private JsonObject getCommonConfig(boolean enableWebClientSsl) {
+ int serverPort = TestUtils.getPort();
+ JsonObject config = new JsonObject().put(Constants.SYS_PORT, serverPort)
+ .put(Constants.SYS_OKAPI_URL, OKAPI_URL)
+ .put(Constants.SYS_SECURE_STORE_PROP_FILE, "src/main/resources/ephemeral.properties")
+ .put(Constants.SYS_LOG_LEVEL, "TRACE")
+ .put(Constants.SYS_REQUEST_TIMEOUT_MS, 5000)
+ .put(Constants.SYS_HTTP_SERVER_SSL_ENABLED, true)
+ .put(Constants.SYS_HTTP_SERVER_KEYSTORE_TYPE, KEYSTORE_TYPE)
+ .put(Constants.SYS_HTTP_SERVER_KEYSTORE_PATH, KEYSTORE_PATH)
+ .put(Constants.SYS_HTTP_SERVER_KEYSTORE_PASSWORD, KEYSTORE_PASSWORD);
+ if (enableWebClientSsl) {
+ return config
+ .put(Constants.SYS_WEB_CLIENT_SSL_ENABLED, true)
+ .put(Constants.SYS_WEB_CLIENT_TRUSTSTORE_TYPE, KEYSTORE_TYPE)
+ .put(Constants.SYS_WEB_CLIENT_TRUSTSTORE_PATH, TRUST_STORE_PATH)
+ .put(Constants.SYS_WEB_CLIENT_TRUSTSTORE_PASSWORD, KEYSTORE_PASSWORD);
+ } else {
+ return config
+ .put(Constants.SYS_WEB_CLIENT_SSL_ENABLED, false);
+ }
+ }
+}
diff --git a/src/test/resources/test.keystore 1.bcfks b/src/test/resources/test.keystore 1.bcfks
new file mode 100644
index 0000000..af4eb23
Binary files /dev/null and b/src/test/resources/test.keystore 1.bcfks differ
diff --git a/src/test/resources/test.truststore 1.bcfks b/src/test/resources/test.truststore 1.bcfks
new file mode 100644
index 0000000..4612e7e
Binary files /dev/null and b/src/test/resources/test.truststore 1.bcfks differ