diff --git a/src/main/java/de/ozgcloud/xta/client/config/XtaClientConfig.java b/src/main/java/de/ozgcloud/xta/client/config/XtaClientConfig.java index 4f7241ed0bcf6f84b03d1e48079fb2a4e84d2925..1693d82a00092e5dc37e4a62fec5e1ff60cb91c0 100644 --- a/src/main/java/de/ozgcloud/xta/client/config/XtaClientConfig.java +++ b/src/main/java/de/ozgcloud/xta/client/config/XtaClientConfig.java @@ -49,6 +49,10 @@ public class XtaClientConfig { @Builder.Default private final KeyStore clientCertKeystore = null; + @Valid + @Builder.Default + private final KeyStore trustStore = null; + @Builder.Default private final boolean schemaValidation = true; @Builder.Default diff --git a/src/main/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactory.java b/src/main/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactory.java index 911d35e9bfce25ddafd3876880227217bb49bb39..fee35b47d2f185f4b17fa617780ecfaa274b8891 100644 --- a/src/main/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactory.java +++ b/src/main/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactory.java @@ -45,6 +45,10 @@ public class XtaTLSClientParametersFactory { if (clientCertKeystore != null) { sslContextBuilder.loadKeyMaterial(loadStore(clientCertKeystore), clientCertKeystore.getPassword()); } + var trustStore = config.getTrustStore(); + if (trustStore != null) { + sslContextBuilder.loadTrustMaterial(loadStore(trustStore), null); + } return sslContextBuilder.build(); } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | UnrecoverableKeyException | IOException | CertificateException e) { diff --git a/src/test/java/de/ozgcloud/xta/client/XtaClientITCase.java b/src/test/java/de/ozgcloud/xta/client/XtaClientITCase.java index 0ebe3dde308d39012f560994d8819c3bdb09fc23..2169e0ba07c193b013325927d89a87d45f2548aa 100644 --- a/src/test/java/de/ozgcloud/xta/client/XtaClientITCase.java +++ b/src/test/java/de/ozgcloud/xta/client/XtaClientITCase.java @@ -3,9 +3,7 @@ package de.ozgcloud.xta.client; import static de.ozgcloud.xta.client.XtaDevServerSetupExtension.*; import static org.assertj.core.api.Assertions.*; -import org.junit.Ignore; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -13,7 +11,6 @@ import org.junit.jupiter.api.extension.RegisterExtension; import lombok.SneakyThrows; -@Ignore class XtaClientITCase { @RegisterExtension diff --git a/src/test/java/de/ozgcloud/xta/client/XtaTestServerContainer.java b/src/test/java/de/ozgcloud/xta/client/XtaTestServerContainer.java index 6629771d599f8a393ddf77ed951977a70f6e4a93..da3b366c818be7b6e7add8eeca14c574af488554 100644 --- a/src/test/java/de/ozgcloud/xta/client/XtaTestServerContainer.java +++ b/src/test/java/de/ozgcloud/xta/client/XtaTestServerContainer.java @@ -2,19 +2,15 @@ package de.ozgcloud.xta.client; import jakarta.validation.constraints.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.utility.DockerImageName; public class XtaTestServerContainer extends GenericContainer<XtaTestServerContainer> { - private static final Logger log = LoggerFactory.getLogger(XtaTestServerContainer.class); private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker.ozg-sh.de/xta-test-server"); private static final String DEFAULT_TAG = "latest"; public static final int PORT = 8443; - public XtaTestServerContainer() { this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } @@ -25,7 +21,7 @@ public class XtaTestServerContainer extends GenericContainer<XtaTestServerContai } public String getBaseUrl() { - return "https://localhost:%d/services/XTAService/".formatted(getMappedPort(PORT)); + return "https://%s:%d/services/XTAService/".formatted(getHost(), getMappedPort(PORT)); } public String getMsgBoxPortUrl() { @@ -40,10 +36,4 @@ public class XtaTestServerContainer extends GenericContainer<XtaTestServerContai return getBaseUrl() + "SendXtaPort"; } - public static void main(String[] args) { - try (XtaTestServerContainer container = new XtaTestServerContainer()) { - container.start(); - System.out.println(container.getBaseUrl()); - } - } } diff --git a/src/test/java/de/ozgcloud/xta/client/XtaTestServerSetupExtension.java b/src/test/java/de/ozgcloud/xta/client/XtaTestServerSetupExtension.java index 2ce8704ef809285362a7241a6693547b0ba1f3ca..d7f3dd2178b85745881e1fbaa050d8153f6e8fa1 100644 --- a/src/test/java/de/ozgcloud/xta/client/XtaTestServerSetupExtension.java +++ b/src/test/java/de/ozgcloud/xta/client/XtaTestServerSetupExtension.java @@ -2,7 +2,6 @@ package de.ozgcloud.xta.client; import static de.ozgcloud.xta.client.XtaDevServerSetupExtension.*; -import java.io.File; import java.util.List; import java.util.Objects; @@ -12,8 +11,6 @@ import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.testcontainers.utility.DockerImageName; -import com.google.common.io.Files; - import de.ozgcloud.xta.client.config.XtaClientConfig; import de.ozgcloud.xta.client.core.WrappedXtaService; import de.ozgcloud.xta.client.model.Identifier; @@ -36,13 +33,18 @@ public class XtaTestServerSetupExtension implements BeforeAllCallback, AfterAllC private static final DockerImageName XTA_TEST_SERVER_IMAGE = DockerImageName.parse("docker.ozg-sh.de/xta-test-server") .withTag("1.4.1-SNAPSHOT"); + private static final String JOHN_SMITH_KEYSTORE_PATH = "store/john-smith-client-cert-keystore.p12"; + private static final String JOHN_SMITH_KEYSTORE_PASSWORD = "password"; + + private static final String XTA_TEST_SERVER_TRUSTSTORE_PATH = "store/xta-test-server-truststore.jks"; + private static final String XTA_TEST_SERVER_TRUSTSTORE_PASSWORD = "password"; + private XtaClient client; private WrappedXtaService service; private XtaClientConfig config; private XtaClientFactory clientFactory; private XtaTestServerContainer xtaServerContainer; - @Override @SneakyThrows public void beforeAll(ExtensionContext context) { @@ -73,21 +75,25 @@ public class XtaTestServerSetupExtension implements BeforeAllCallback, AfterAllC @SneakyThrows XtaClient setupClient() { - var clientCertKeystorePath = getEnvVar("KOP_SH_KIEL_DEV_PATH"); - var clientCertKeystorePassword = getEnvVar("KOP_SH_KIEL_DEV_PASSWORD"); - // TODO Trust store (xta-test-server certificate not trusted...) var clientCertKeyStore = XtaClientConfig.KeyStore.builder() - .content(readBytesFromFile(clientCertKeystorePath)) + .content(readBytesFromResource(JOHN_SMITH_KEYSTORE_PATH)) .type("PKCS12") - .password(clientCertKeystorePassword.toCharArray()) + .password(JOHN_SMITH_KEYSTORE_PASSWORD.toCharArray()) + .build(); + var trustStore = XtaClientConfig.KeyStore.builder() + .content(readBytesFromResource(XTA_TEST_SERVER_TRUSTSTORE_PATH)) + .type("JKS") + .password(XTA_TEST_SERVER_TRUSTSTORE_PASSWORD.toCharArray()) .build(); + config = XtaClientConfig.builder() .clientIdentifiers(List.of(CLIENT_IDENTIFIER3, CLIENT_IDENTIFIER2, CLIENT_IDENTIFIER1)) .managementServiceUrl(xtaServerContainer.getManagementPortUrl()) .sendServiceUrl(xtaServerContainer.getSendPortUrl()) .msgBoxServiceUrl(xtaServerContainer.getMsgBoxPortUrl()) .clientCertKeystore(clientCertKeyStore) + .trustStore(trustStore) .logSoapRequests(true) .logSoapResponses(true) .build(); @@ -95,10 +101,6 @@ public class XtaTestServerSetupExtension implements BeforeAllCallback, AfterAllC return clientFactory.create(); } - private String getEnvVar(String name) { - return Objects.requireNonNull(System.getenv(name), "Environment variable " + name + " is required!"); - } - @Override @SneakyThrows public void beforeEach(ExtensionContext context) { @@ -157,8 +159,10 @@ public class XtaTestServerSetupExtension implements BeforeAllCallback, AfterAllC } @SneakyThrows - private static byte[] readBytesFromFile(String path) { - return Files.toByteArray(new File(path)); + private static byte[] readBytesFromResource(String resourcePath) { + try (var inputStream = XtaTestServerSetupExtension.class.getClassLoader().getResourceAsStream(resourcePath)) { + return Objects.requireNonNull(inputStream, "Expect class-resource at: " + resourcePath).readAllBytes(); + } } } diff --git a/src/test/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactoryTest.java b/src/test/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactoryTest.java index 3e2743219133a7492c84e41e782d2f9c3d00e4e7..294fcb065701b97d5db3e703233dfa675af0d9af 100644 --- a/src/test/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactoryTest.java +++ b/src/test/java/de/ozgcloud/xta/client/core/XtaTLSClientParametersFactoryTest.java @@ -149,6 +149,54 @@ class XtaTLSClientParametersFactoryTest { assertThat(sslContextResult).isEqualTo(sslContext); } } + + @DisplayName("with trust store") + @Nested + class TestWithTrustStore { + @BeforeEach + @SneakyThrows + void mock() { + when(config.getTrustStore()).thenReturn(configKeystore); + doReturn(keystore).when(factory).loadStore(configKeystore); + } + + @DisplayName("should call loadTrustMaterial") + @Test + @SneakyThrows + void shouldCallLoadTrustMaterial() { + factory.createXtaSslContext(); + + verify(sslContextBuilder).loadTrustMaterial(keystore, null); + } + + @DisplayName("should return SSL context") + @Test + @SneakyThrows + void shouldSetProtocol() { + var sslContextResult = factory.createXtaSslContext(); + + assertThat(sslContextResult).isEqualTo(sslContext); + } + } + + @DisplayName("without trust store") + @Nested + class TestWithoutTrustStore { + @BeforeEach + @SneakyThrows + void mock() { + when(config.getTrustStore()).thenReturn(null); + } + + @DisplayName("should return SSL context") + @Test + @SneakyThrows + void shouldSetProtocol() { + var sslContextResult = factory.createXtaSslContext(); + + assertThat(sslContextResult).isEqualTo(sslContext); + } + } } @DisplayName("create SSL context builder") diff --git a/src/test/resources/store/john-smith-client-cert-keystore.p12 b/src/test/resources/store/john-smith-client-cert-keystore.p12 new file mode 100644 index 0000000000000000000000000000000000000000..a727395694185315016bfccc2fd42e17749e4592 Binary files /dev/null and b/src/test/resources/store/john-smith-client-cert-keystore.p12 differ diff --git a/src/test/resources/store/xta-test-server-truststore.jks b/src/test/resources/store/xta-test-server-truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..0935b1e776a77b5caa7e8cfc4a6a02a9881d03b7 Binary files /dev/null and b/src/test/resources/store/xta-test-server-truststore.jks differ