From bc84d494459f8eb9c93b289980fbfe99a5291406 Mon Sep 17 00:00:00 2001 From: BKadirkhodjaev Date: Wed, 22 May 2024 21:21:23 +0500 Subject: [PATCH] =?UTF-8?q?[EDGORDERS-83-IT].=20Add=20tls=20integration=20?= =?UTF-8?q?test,=20add=20test=20scope=20BC=20deps,=20=E2=80=A6=20(#102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [EDGORDERS-83-IT]. Add tls integration test, add test scope BC deps, keystore and trust store --- pom.xml | 8 + .../java/org/folio/edge/core/Constants.java | 24 +++ .../core/EdgeVerticleTlsIntegrationTest.java | 147 ++++++++++++++++++ src/test/resources/test.keystore 1.bcfks | Bin 0 -> 2632 bytes src/test/resources/test.truststore 1.bcfks | Bin 0 -> 1242 bytes 5 files changed, 179 insertions(+) create mode 100644 src/test/java/org/folio/edge/core/EdgeVerticleTlsIntegrationTest.java create mode 100644 src/test/resources/test.keystore 1.bcfks create mode 100644 src/test/resources/test.truststore 1.bcfks 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 0000000000000000000000000000000000000000..af4eb23f6e5f599a3ad37b3320b8f817a6ab9d32 GIT binary patch literal 2632 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