From 4054b18406d54b1f11e2df249382d719be5fe43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Wed, 22 Oct 2025 15:22:18 +0200 Subject: [PATCH 01/11] Fix typo --- .../main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java index e5872fb30..cf5854382 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java @@ -185,7 +185,7 @@ private static void injectEndpointProperties(ConfigurableEnvironment environment properties.put("dev.dsf.fhir.server.endpoint.address", baseUrl.toString()); properties.put("dev.dsf.fhir.server.endpoint.identifier.value", baseUrl.getHost()); - environment.getPropertySources().addFirst(new PropertiesPropertySource("enpoint-properties", properties)); + environment.getPropertySources().addFirst(new PropertiesPropertySource("endpoint-properties", properties)); } catch (MalformedURLException | IllegalStateException | URISyntaxException e) { From 768a7271cd8d85979bb63d6a5946471264678ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Thu, 23 Oct 2025 16:31:27 +0200 Subject: [PATCH 02/11] The organization thumbprint now gets computed from DSF_DEV_FHIR_CLIENT_CERTIFICATE if the DSF_DEV_FHIR_SERVER_ORGANIZATION_THUMBPRINT is omitted in the configuration --- .../fhir/spring/config/PropertiesConfig.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java index cf5854382..f3c4fa4bc 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java @@ -1,14 +1,20 @@ package dev.dsf.fhir.spring.config; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyStore; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.time.Duration; +import java.util.HexFormat; import java.util.List; import java.util.Properties; @@ -169,6 +175,7 @@ public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderCon new DockerSecretsPropertySourceFactory(environment).readDockerSecretsAndAddPropertiesToEnvironment(); injectEndpointProperties(environment); + computeOrganizationThumbprintPropertyIfPossible(environment); return new PropertySourcesPlaceholderConfigurer(); } @@ -193,6 +200,31 @@ private static void injectEndpointProperties(ConfigurableEnvironment environment } } + private static void computeOrganizationThumbprintPropertyIfPossible(ConfigurableEnvironment environment) + { + try + { + String organizationThumbprint = environment.getProperty("dev.dsf.fhir.server.organization.thumbprint"); + + if (organizationThumbprint == null) + { + Path clientCertPath = Paths.get(environment.getRequiredProperty("dev.dsf.fhir.client.certificate")); + X509Certificate clientCert = PemReader.readCertificate(clientCertPath); + MessageDigest md = MessageDigest.getInstance("SHA-512"); + HexFormat hexFormat = HexFormat.of(); + String thumbprint = hexFormat.formatHex(md.digest(clientCert.getEncoded())).toLowerCase(); + + Properties properties = new Properties(); + properties.put("dev.dsf.fhir.server.organization.thumbprint", thumbprint); + + environment.getPropertySources().addFirst(new PropertiesPropertySource("organization-thumbprint-properties", properties)); + } + } catch (IOException | NoSuchAlgorithmException | CertificateEncodingException e) + { + throw new RuntimeException(e); + } + } + @Override public void afterPropertiesSet() throws Exception { From 268c5b5dda3d4ba0a52fe27495101c61b55c9065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Thu, 23 Oct 2025 17:14:55 +0200 Subject: [PATCH 03/11] Format --- .../java/dev/dsf/fhir/spring/config/PropertiesConfig.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java index f3c4fa4bc..44ab979ac 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java @@ -217,9 +217,11 @@ private static void computeOrganizationThumbprintPropertyIfPossible(Configurable Properties properties = new Properties(); properties.put("dev.dsf.fhir.server.organization.thumbprint", thumbprint); - environment.getPropertySources().addFirst(new PropertiesPropertySource("organization-thumbprint-properties", properties)); + environment.getPropertySources() + .addFirst(new PropertiesPropertySource("organization-thumbprint-properties", properties)); } - } catch (IOException | NoSuchAlgorithmException | CertificateEncodingException e) + } + catch (IOException | NoSuchAlgorithmException | CertificateEncodingException e) { throw new RuntimeException(e); } From 263e8b35b214d55082f16e385b8efe72fd4a9fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Fri, 24 Oct 2025 10:59:21 +0200 Subject: [PATCH 04/11] InjectEndpointProperties and computeOrganizationThumbprintPropertyIfPossible should warn with log entry because the app will crash anyway if a required property is missing --- .../java/dev/dsf/fhir/spring/config/PropertiesConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java index 44ab979ac..e36f21c73 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/PropertiesConfig.java @@ -196,7 +196,7 @@ private static void injectEndpointProperties(ConfigurableEnvironment environment } catch (MalformedURLException | IllegalStateException | URISyntaxException e) { - throw new RuntimeException(e); + logger.warn("Exception while injecting endpoint properties", e); } } @@ -223,7 +223,7 @@ private static void computeOrganizationThumbprintPropertyIfPossible(Configurable } catch (IOException | NoSuchAlgorithmException | CertificateEncodingException e) { - throw new RuntimeException(e); + logger.warn("Exception while computing organization thumbprint property", e); } } From 5fb037739d14822109a42ded5c337af90ac85d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Mon, 27 Oct 2025 12:32:38 +0100 Subject: [PATCH 05/11] Refactored AbstractIntegrationTest to use property replacement instead of reading, writing and deleting a test-bundle --- .../integration/AbstractIntegrationTest.java | 72 +++---------------- .../resources/integration/test-bundle.xml | 8 +-- .../integration/AbstractIntegrationTest.java | 67 +++-------------- .../resources/integration/test-bundle.xml | 8 +-- 4 files changed, 27 insertions(+), 128 deletions(-) diff --git a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java index 0d1e1766c..7095a7a48 100644 --- a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java +++ b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java @@ -115,12 +115,12 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest private static final Path EMPTY_PROCESS_DIRECTORY = Paths.get("target", UUID.randomUUID().toString()); private static final List DIRECTORIES_TO_DELETE = List.of(EMPTY_PROCESS_DIRECTORY); - private static final Path FHIR_BUNDLE_FILE = Paths.get("target", UUID.randomUUID().toString() + ".xml"); + private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration","test-bundle.xml"); private static final Path ALLOWED_BPE_CLASSES_LIST_FILE_V1 = Paths.get("target", UUID.randomUUID().toString() + ".list"); private static final Path ALLOWED_BPE_CLASSES_LIST_FILE_V2 = Paths.get("target", UUID.randomUUID().toString() + ".list"); - private static final List FILES_TO_DELETE = List.of(FHIR_BUNDLE_FILE, ALLOWED_BPE_CLASSES_LIST_FILE_V1, + private static final List FILES_TO_DELETE = List.of(ALLOWED_BPE_CLASSES_LIST_FILE_V1, ALLOWED_BPE_CLASSES_LIST_FILE_V2); protected static final FhirContext fhirContext = FhirContext.forR4(); @@ -141,10 +141,6 @@ public static void beforeClass() throws Exception ServerSocketChannel fhirStatusConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); ServerSocketChannel fhirApiConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); - logger.info("Creating FHIR Bundle ..."); - createTestBundle(certificates.getClientCertificate(), certificates.getExternalClientCertificate(), - fhirApiConnectorChannel.socket().getLocalPort()); - String fhirBaseUrl = "https://localhost:" + fhirApiConnectorChannel.socket().getLocalPort() + FHIR_CONTEXT_PATH; logger.info("Creating webservice client ..."); @@ -239,11 +235,6 @@ private static WebsocketClient createWebsocketClient(int fhirApiPort, KeyStore t keyStorePassword, null, null, null, "Integration Test Client", subscriptionIdPart); } - protected static IParser newXmlParser() - { - return newParser(fhirContext::newXmlParser); - } - protected static IParser newJsonParser() { return newParser(fhirContext::newJsonParser); @@ -258,58 +249,6 @@ private static IParser newParser(Supplier supplier) return p; } - private static void createTestBundle(CertificateAndPrivateKey clientCertificate, - CertificateAndPrivateKey externalClientCertificate, int fhirApiPort) - { - Path testBundleTemplateFile = Paths.get("src/test/resources/integration/test-bundle.xml"); - - Bundle testBundle = readBundle(testBundleTemplateFile, newXmlParser()); - - Organization organization = (Organization) testBundle.getEntry().get(0).getResource(); - Extension thumbprintExtension = organization - .getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint"); - thumbprintExtension.setValue(new StringType(clientCertificate.certificateSha512ThumbprintHex())); - - Endpoint endpoint = (Endpoint) testBundle.getEntry().get(1).getResource(); - endpoint.setAddress("https://localhost:" + fhirApiPort + "/fhir"); - - Organization externalOrganization = (Organization) testBundle.getEntry().get(2).getResource(); - Extension externalThumbprintExtension = externalOrganization - .getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint"); - externalThumbprintExtension - .setValue(new StringType(externalClientCertificate.certificateSha512ThumbprintHex())); - - writeBundle(FHIR_BUNDLE_FILE, testBundle); - } - - private static Bundle readBundle(Path bundleTemplateFile, IParser parser) - { - try (InputStream in = Files.newInputStream(bundleTemplateFile)) - { - Bundle bundle = parser.parseResource(Bundle.class, in); - return referenceCleaner.cleanReferenceResourcesIfBundle(bundle); - } - catch (IOException e) - { - logger.error("Error while reading bundle from {}", bundleTemplateFile.toString(), e); - throw new RuntimeException(e); - } - } - - private static void writeBundle(Path bundleFile, Bundle bundle) - { - try (OutputStream out = Files.newOutputStream(bundleFile); - OutputStreamWriter writer = new OutputStreamWriter(out)) - { - newXmlParser().encodeResourceToWriter(bundle, writer); - } - catch (IOException e) - { - logger.error("Error while writing bundle to {}", bundleFile.toString(), e); - throw new RuntimeException(e); - } - } - private static JettyServer startFhirServer(ServerSocketChannel statusConnectorChannel, ServerSocketChannel apiConnectorChannel, String baseUrl) throws Exception { @@ -364,6 +303,13 @@ private static JettyServer startFhirServer(ServerSocketChannel statusConnectorCh """, certificates.getDicUserClientCertificate().certificateSha512ThumbprintHex(), certificates.getUacUserClientCertificate().certificateSha512ThumbprintHex())); + initParameters.put("dev.dsf.fhir.server.organization.thumbprint", + certificates.getClientCertificate().certificateSha512ThumbprintHex()); + initParameters.put("dev.dsf.fhir.server.endpoint.address", "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + "/fhir"); + initParameters.put("dev.dsf.fhir.server.organization.thumbprint.external", + certificates.getExternalClientCertificate().certificateSha512ThumbprintHex()); + initParameters.put("dev.dsf.fhir.server.endpoint.address.external", "https://localhost:80010/fhir"); + KeyStore clientCertificateTrustStore = KeyStoreCreator .jksForTrustedCertificates(certificates.getCaCertificate()); KeyStore fhirServerCertificateKeyStore = certificates.getFhirServerCertificate().keyStore(); diff --git a/dsf-bpe/dsf-bpe-server/src/test/resources/integration/test-bundle.xml b/dsf-bpe/dsf-bpe-server/src/test/resources/integration/test-bundle.xml index 729a45976..138cf961c 100644 --- a/dsf-bpe/dsf-bpe-server/src/test/resources/integration/test-bundle.xml +++ b/dsf-bpe/dsf-bpe-server/src/test/resources/integration/test-bundle.xml @@ -14,7 +14,7 @@ - + @@ -66,7 +66,7 @@ -
+
@@ -86,7 +86,7 @@ - + @@ -138,7 +138,7 @@ -
+
diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java index 84f3236fe..ffd39d71f 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java @@ -100,8 +100,8 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest protected static final String CONTEXT_PATH = "/fhir"; - private static final Path FHIR_BUNDLE_FILE = Paths.get("target", UUID.randomUUID().toString() + ".xml"); - private static final List FILES_TO_DELETE = List.of(FHIR_BUNDLE_FILE); + private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration", + "test-bundle.xml"); protected static final FhirContext fhirContext = FhirContext.forR4(); protected static final ReadAccessHelper readAccessHelper = new ReadAccessHelperImpl(); @@ -124,9 +124,6 @@ public static void beforeClass() throws Exception liquibaseRule.getDatabaseName()); defaultDataSource.unwrap(BasicDataSource.class).start(); - logger.info("Creating Bundle ..."); - createTestBundle(certificates.getClientCertificate(), certificates.getExternalClientCertificate()); - ServerSocketChannel statusConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); ServerSocketChannel apiConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); @@ -247,6 +244,14 @@ private static JettyServer startFhirServer(ServerSocketChannel statusConnectorCh certificates.getMinimalClientCertificate().certificateSha512ThumbprintHex())); initParameters.put("dev.dsf.fhir.debug.log.message.dbStatement", "true"); + initParameters.put("dev.dsf.fhir.server.organization.thumbprint", + certificates.getClientCertificate().certificateSha512ThumbprintHex()); + initParameters.put("dev.dsf.fhir.server.endpoint.address", + "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + "/fhir"); + initParameters.put("dev.dsf.fhir.server.organization.thumbprint.external", + certificates.getExternalClientCertificate().certificateSha512ThumbprintHex()); + initParameters.put("dev.dsf.fhir.server.endpoint.address.external", "https://localhost:80010/fhir"); + KeyStore clientCertificateTrustStore = KeyStoreCreator .jksForTrustedCertificates(certificates.getCaCertificate()); KeyStore serverCertificateKeyStore = certificates.getServerCertificate().keyStore(); @@ -298,20 +303,6 @@ protected static Bundle readBundle(Path bundleTemplateFile, IParser parser) } } - private static void writeBundle(Path bundleFile, Bundle bundle) - { - try (OutputStream out = Files.newOutputStream(bundleFile); - OutputStreamWriter writer = new OutputStreamWriter(out)) - { - newXmlParser().encodeResourceToWriter(bundle, writer); - } - catch (IOException e) - { - logger.error("Error while writing bundle to {}", bundleFile.toString(), e); - throw new RuntimeException(e); - } - } - protected static IParser newXmlParser() { return newParser(fhirContext::newXmlParser); @@ -331,29 +322,6 @@ private static IParser newParser(Supplier supplier) return p; } - private static void createTestBundle(CertificateAndPrivateKey clientCertificate, - CertificateAndPrivateKey externalClientCertificate) - { - Path testBundleTemplateFile = Paths.get("src/test/resources/integration/test-bundle.xml"); - - Bundle testBundle = readBundle(testBundleTemplateFile, newXmlParser()); - - Organization organization = (Organization) testBundle.getEntry().get(0).getResource(); - Extension thumbprintExtension = organization - .getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint"); - - thumbprintExtension.setValue(new StringType(clientCertificate.certificateSha512ThumbprintHex())); - - Organization externalOrganization = (Organization) testBundle.getEntry().get(2).getResource(); - Extension externalThumbprintExtension = externalOrganization - .getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint"); - - externalThumbprintExtension - .setValue(new StringType(externalClientCertificate.certificateSha512ThumbprintHex())); - - writeBundle(FHIR_BUNDLE_FILE, testBundle); - } - @AfterClass public static void afterClass() throws Exception { @@ -371,21 +339,6 @@ public static void afterClass() throws Exception } defaultDataSource.unwrap(BasicDataSource.class).close(); - - logger.info("Deleting files {} ...", FILES_TO_DELETE); - FILES_TO_DELETE.forEach(AbstractIntegrationTest::deleteFile); - } - - private static void deleteFile(Path file) - { - try - { - Files.delete(file); - } - catch (IOException e) - { - logger.error("Error while deleting test file {}, error: {}", file.toString(), e.toString()); - } } protected AnnotationConfigWebApplicationContext getSpringWebApplicationContext() diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml index c1e319802..4a345ec99 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/integration/test-bundle.xml @@ -14,7 +14,7 @@ - + @@ -66,7 +66,7 @@ -
+
@@ -86,7 +86,7 @@ - + @@ -138,7 +138,7 @@ -
+
From acf472f03901249f143a5b487f676b96cd12769d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Tue, 28 Oct 2025 18:09:10 +0100 Subject: [PATCH 06/11] Added integration test --- ...OrganizationThumbprintIntegrationTest.java | 279 ++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java new file mode 100644 index 000000000..f9cc6db2a --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java @@ -0,0 +1,279 @@ +package dev.dsf.fhir.integration; + +import static org.junit.Assert.assertEquals; + +import java.nio.channels.ServerSocketChannel; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.sql.DataSource; + +import org.apache.commons.dbcp2.BasicDataSource; +import org.eclipse.jetty.ee10.servlet.SessionHandler; +import org.eclipse.jetty.ee10.webapp.WebAppContext; +import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer; +import org.eclipse.jetty.security.SecurityHandler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer; +import org.hl7.fhir.r4.model.Organization; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.SpringServletContainerInitializer; +import org.testcontainers.utility.DockerImageName; + +import ca.uhn.fhir.context.FhirContext; + +import de.hsheilbronn.mi.utils.crypto.keystore.KeyStoreCreator; +import de.hsheilbronn.mi.utils.test.PostgreSqlContainerLiquibaseTemplateClassRule; +import de.hsheilbronn.mi.utils.test.PostgresTemplateRule; + +import dev.dsf.common.auth.ClientCertificateAuthenticator; +import dev.dsf.common.auth.DelegatingAuthenticator; +import dev.dsf.common.auth.DsfLoginService; +import dev.dsf.common.auth.DsfSecurityHandler; +import dev.dsf.common.auth.StatusPortAuthenticator; +import dev.dsf.common.jetty.JettyServer; +import dev.dsf.fhir.authorization.read.ReadAccessHelper; +import dev.dsf.fhir.authorization.read.ReadAccessHelperImpl; +import dev.dsf.fhir.client.FhirWebserviceClient; +import dev.dsf.fhir.client.FhirWebserviceClientJersey; +import dev.dsf.fhir.dao.AbstractDbTest; +import dev.dsf.fhir.service.ReferenceCleaner; +import dev.dsf.fhir.service.ReferenceCleanerImpl; +import dev.dsf.fhir.service.ReferenceExtractorImpl; +import jakarta.servlet.ServletContainerInitializer; + +public class OrganizationThumbprintIntegrationTest extends AbstractDbTest +{ + @ClassRule + public static final X509Certificates certificates = new X509Certificates(); + + protected static DataSource defaultDataSource; + + @ClassRule + public static final PostgreSqlContainerLiquibaseTemplateClassRule liquibaseRule = new PostgreSqlContainerLiquibaseTemplateClassRule( + DockerImageName.parse("postgres:15"), ROOT_USER, "fhir", "fhir_template", CHANGE_LOG_FILE, + CHANGE_LOG_PARAMETERS, false); + + @Rule + public final PostgresTemplateRule templateRule = new PostgresTemplateRule(liquibaseRule); + + @Rule + public final TestNameLoggerRule testNameLoggerRule = new TestNameLoggerRule(); + + private static final Logger logger = LoggerFactory.getLogger(AbstractIntegrationTest.class); + + protected static final String CONTEXT_PATH = "/fhir"; + + private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration", + "test-bundle.xml"); + + protected static final FhirContext fhirContext = FhirContext.forR4(); + protected static final ReadAccessHelper readAccessHelper = new ReadAccessHelperImpl(); + + private static final ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl()); + + private static String baseUrl; + private static JettyServer fhirServer; + private static FhirWebserviceClient webserviceClient; + private static final ServerSocketChannel apiConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); + private static final ServerSocketChannel statusConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); + + @BeforeClass + public static void beforeClass() throws Exception + { + defaultDataSource = createDefaultDataSource(liquibaseRule.getHost(), liquibaseRule.getMappedPort(5432), + liquibaseRule.getDatabaseName()); + defaultDataSource.unwrap(BasicDataSource.class).start(); + + baseUrl = "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + CONTEXT_PATH; + + logger.info("Creating webservice client ..."); + webserviceClient = createWebserviceClient(apiConnectorChannel.socket().getLocalPort(), + certificates.getClientCertificate().trustStore(), certificates.getClientCertificate().keyStore(), + certificates.getClientCertificate().keyStorePassword()); + + logger.info("Creating template database ..."); + liquibaseRule.createTemplateDatabase(); + } + + private static FhirWebserviceClient createWebserviceClient(int apiPort, KeyStore trustStore, KeyStore keyStore, + char[] keyStorePassword) + { + return new FhirWebserviceClientJersey("https://localhost:" + apiPort + CONTEXT_PATH, trustStore, keyStore, + keyStorePassword, null, null, null, null, Duration.ZERO, Duration.ZERO, false, + "DSF Integration Test Client", fhirContext, + referenceCleaner); + } + + private static Map getDefaultInitParameters(ServerSocketChannel statusConnectorChannel, + ServerSocketChannel apiConnectorChannel) + { + Map initParameters = new HashMap<>(); + initParameters.put("dev.dsf.server.status.port", + Integer.toString(statusConnectorChannel.socket().getLocalPort())); + + initParameters.put("dev.dsf.fhir.db.url", + "jdbc:postgresql://" + liquibaseRule.getHost() + ":" + liquibaseRule.getMappedPort(5432) + "/" + liquibaseRule.getDatabaseName()); + initParameters.put("dev.dsf.fhir.db.user.group", DATABASE_USERS_GROUP); + initParameters.put("dev.dsf.fhir.db.user.username", DATABASE_USER); + initParameters.put("dev.dsf.fhir.db.user.password", DATABASE_USER_PASSWORD); + initParameters.put("dev.dsf.fhir.db.user.permanent.delete.group", DATABASE_DELETE_USERS_GROUP); + initParameters.put("dev.dsf.fhir.db.user.permanent.delete.username", DATABASE_DELETE_USER); + initParameters.put("dev.dsf.fhir.db.user.permanent.delete.password", DATABASE_DELETE_USER_PASSWORD); + + initParameters.put("dev.dsf.fhir.server.base.url", baseUrl); + initParameters.put("dev.dsf.fhir.server.organization.identifier.value", "Test_Organization"); + initParameters.put("dev.dsf.fhir.server.init.bundle", FHIR_BUNDLE_FILE.toString()); + + initParameters.put("dev.dsf.fhir.client.trust.server.certificate.cas", + certificates.getCaCertificateFile().toString()); + initParameters.put("dev.dsf.server.auth.trust.client.certificate.cas", + certificates.getCaCertificateFile().toString()); + initParameters.put("dev.dsf.fhir.client.certificate", certificates.getClientCertificateFile().toString()); + initParameters.put("dev.dsf.fhir.client.certificate.private.key", + certificates.getClientCertificatePrivateKeyFile().toString()); + initParameters.put("dev.dsf.fhir.client.certificate.private.key.password", + String.valueOf(X509Certificates.PASSWORD)); + + initParameters.put("dev.dsf.fhir.server.roleConfig", String.format(""" + - practitioner-test-user: + thumbprint: %s + dsf-role: + - CREATE + - READ + - UPDATE + - DELETE + - SEARCH + - HISTORY + practitioner-role: + - http://dsf.dev/fhir/CodeSystem/practitioner-role|DIC_USER + - admin-user: + thumbprint: %s + dsf-role: [CREATE, READ, UPDATE, DELETE, SEARCH, HISTORY] + practitioner-role: + - http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN + - minimal-test-user: + thumbprint: %s + dsf-role: + - CREATE: [Task] + - READ: &tqqr [Task, Questionnaire, QuestionnaireResponse] + - UPDATE: [QuestionnaireResponse] + - SEARCH: *tqqr + - HISTORY: *tqqr + practitioner-role: + - http://dsf.dev/fhir/CodeSystem/practitioner-role|DIC_USER + """, certificates.getPractitionerClientCertificate().certificateSha512ThumbprintHex(), + certificates.getAdminClientCertificate().certificateSha512ThumbprintHex(), + certificates.getMinimalClientCertificate().certificateSha512ThumbprintHex())); + initParameters.put("dev.dsf.fhir.debug.log.message.dbStatement", "true"); + + initParameters.put("dev.dsf.fhir.server.endpoint.address", + "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + "/fhir"); + + initParameters.put("dev.dsf.fhir.server.endpoint.address.external", "https://localhost:80010/fhir"); + initParameters.put("dev.dsf.fhir.server.organization.thumbprint.external", + certificates.getExternalClientCertificate().certificateSha512ThumbprintHex()); + return initParameters; + } + + private static Map getInitParametersWithThumbprint(ServerSocketChannel statusConnectorChannel, + ServerSocketChannel apiConnectorChannel) + { + Map initParameters = getDefaultInitParameters(statusConnectorChannel, apiConnectorChannel); + initParameters.put("dev.dsf.fhir.server.organization.thumbprint", + certificates.getClientCertificate().certificateSha512ThumbprintHex()); + return initParameters; + } + + private static JettyServer createFhirServer(Map initParameters) throws Exception + { + + KeyStore clientCertificateTrustStore = KeyStoreCreator + .jksForTrustedCertificates(certificates.getCaCertificate()); + KeyStore serverCertificateKeyStore = certificates.getServerCertificate().keyStore(); + + Function apiConnector = JettyServer.httpsConnector( + apiConnectorChannel, + clientCertificateTrustStore, serverCertificateKeyStore, + certificates.getServerCertificate().keyStorePassword(), false); + Function statusConnector = JettyServer.statusConnector( + statusConnectorChannel); + List> servletContainerInitializers = List.of( + JakartaWebSocketServletContainerInitializer.class, JerseyServletContainerInitializer.class, + SpringServletContainerInitializer.class); + + BiConsumer> securityHandlerConfigurer = (webAppContext, statusPortSupplier) -> + { + SessionHandler sessionHandler = webAppContext.getSessionHandler(); + DsfLoginService dsfLoginService = new DsfLoginService(webAppContext); + + StatusPortAuthenticator statusPortAuthenticator = new StatusPortAuthenticator(statusPortSupplier); + ClientCertificateAuthenticator clientCertificateAuthenticator = new ClientCertificateAuthenticator( + clientCertificateTrustStore); + DelegatingAuthenticator delegatingAuthenticator = new DelegatingAuthenticator(sessionHandler, + statusPortAuthenticator, clientCertificateAuthenticator, null, null, null, null); + + SecurityHandler securityHandler = new DsfSecurityHandler(dsfLoginService, delegatingAuthenticator, null); + securityHandler.setSessionRenewedOnAuthentication(true); + + webAppContext.setSecurityHandler(securityHandler); + }; + + return new JettyServer(apiConnector, statusConnector, "dsf-fhir-server", CONTEXT_PATH, + servletContainerInitializers, initParameters, securityHandlerConfigurer); + } + + @Test + public void testFhirServerStartupWithoutThumbprint() throws Exception + { + fhirServer = createFhirServer(getDefaultInitParameters(statusConnectorChannel, apiConnectorChannel)); + fhirServer.start(); + Organization organization = (Organization) webserviceClient.search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0).getResource(); + String thumbprint = organization.getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint").getValue().primitiveValue(); + assertEquals(certificates.getClientCertificate().certificateSha512ThumbprintHex(), thumbprint); + } + + @Test + public void testFhirServerStartupWithThumbprint() throws Exception + { + fhirServer = createFhirServer(getInitParametersWithThumbprint(statusConnectorChannel, apiConnectorChannel)); + fhirServer.start(); + Organization organization = (Organization) webserviceClient.search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0).getResource(); + String thumbprint = organization.getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint").getValue().primitiveValue(); + assertEquals(certificates.getClientCertificate().certificateSha512ThumbprintHex(), thumbprint); + } + + @After + public void cleanUp() throws Exception + { + try + { + if (fhirServer != null) + { + logger.info("Stopping FHIR Server ..."); + fhirServer.stop(); + } + } + catch (Exception e) + { + logger.error("Error while stopping FHIR Server", e); + } + + defaultDataSource.unwrap(BasicDataSource.class).close(); + } +} From 915bf0b3bee265a7c08087017f46c9ef3c8aacca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Tue, 28 Oct 2025 18:19:02 +0100 Subject: [PATCH 07/11] Format --- .../integration/AbstractIntegrationTest.java | 6 ++- ...OrganizationThumbprintIntegrationTest.java | 38 ++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java index 7095a7a48..b3de18841 100644 --- a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java +++ b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java @@ -115,7 +115,8 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest private static final Path EMPTY_PROCESS_DIRECTORY = Paths.get("target", UUID.randomUUID().toString()); private static final List DIRECTORIES_TO_DELETE = List.of(EMPTY_PROCESS_DIRECTORY); - private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration","test-bundle.xml"); + private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration", + "test-bundle.xml"); private static final Path ALLOWED_BPE_CLASSES_LIST_FILE_V1 = Paths.get("target", UUID.randomUUID().toString() + ".list"); private static final Path ALLOWED_BPE_CLASSES_LIST_FILE_V2 = Paths.get("target", @@ -305,7 +306,8 @@ private static JettyServer startFhirServer(ServerSocketChannel statusConnectorCh initParameters.put("dev.dsf.fhir.server.organization.thumbprint", certificates.getClientCertificate().certificateSha512ThumbprintHex()); - initParameters.put("dev.dsf.fhir.server.endpoint.address", "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + "/fhir"); + initParameters.put("dev.dsf.fhir.server.endpoint.address", + "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + "/fhir"); initParameters.put("dev.dsf.fhir.server.organization.thumbprint.external", certificates.getExternalClientCertificate().certificateSha512ThumbprintHex()); initParameters.put("dev.dsf.fhir.server.endpoint.address.external", "https://localhost:80010/fhir"); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java index f9cc6db2a..74607a83f 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java @@ -36,11 +36,9 @@ import org.testcontainers.utility.DockerImageName; import ca.uhn.fhir.context.FhirContext; - import de.hsheilbronn.mi.utils.crypto.keystore.KeyStoreCreator; import de.hsheilbronn.mi.utils.test.PostgreSqlContainerLiquibaseTemplateClassRule; import de.hsheilbronn.mi.utils.test.PostgresTemplateRule; - import dev.dsf.common.auth.ClientCertificateAuthenticator; import dev.dsf.common.auth.DelegatingAuthenticator; import dev.dsf.common.auth.DsfLoginService; @@ -116,8 +114,7 @@ private static FhirWebserviceClient createWebserviceClient(int apiPort, KeyStore { return new FhirWebserviceClientJersey("https://localhost:" + apiPort + CONTEXT_PATH, trustStore, keyStore, keyStorePassword, null, null, null, null, Duration.ZERO, Duration.ZERO, false, - "DSF Integration Test Client", fhirContext, - referenceCleaner); + "DSF Integration Test Client", fhirContext, referenceCleaner); } private static Map getDefaultInitParameters(ServerSocketChannel statusConnectorChannel, @@ -127,8 +124,8 @@ private static Map getDefaultInitParameters(ServerSocketChannel initParameters.put("dev.dsf.server.status.port", Integer.toString(statusConnectorChannel.socket().getLocalPort())); - initParameters.put("dev.dsf.fhir.db.url", - "jdbc:postgresql://" + liquibaseRule.getHost() + ":" + liquibaseRule.getMappedPort(5432) + "/" + liquibaseRule.getDatabaseName()); + initParameters.put("dev.dsf.fhir.db.url", "jdbc:postgresql://" + liquibaseRule.getHost() + ":" + + liquibaseRule.getMappedPort(5432) + "/" + liquibaseRule.getDatabaseName()); initParameters.put("dev.dsf.fhir.db.user.group", DATABASE_USERS_GROUP); initParameters.put("dev.dsf.fhir.db.user.username", DATABASE_USER); initParameters.put("dev.dsf.fhir.db.user.password", DATABASE_USER_PASSWORD); @@ -150,7 +147,8 @@ private static Map getDefaultInitParameters(ServerSocketChannel initParameters.put("dev.dsf.fhir.client.certificate.private.key.password", String.valueOf(X509Certificates.PASSWORD)); - initParameters.put("dev.dsf.fhir.server.roleConfig", String.format(""" + initParameters.put("dev.dsf.fhir.server.roleConfig", + String.format(""" - practitioner-test-user: thumbprint: %s dsf-role: @@ -178,8 +176,8 @@ private static Map getDefaultInitParameters(ServerSocketChannel practitioner-role: - http://dsf.dev/fhir/CodeSystem/practitioner-role|DIC_USER """, certificates.getPractitionerClientCertificate().certificateSha512ThumbprintHex(), - certificates.getAdminClientCertificate().certificateSha512ThumbprintHex(), - certificates.getMinimalClientCertificate().certificateSha512ThumbprintHex())); + certificates.getAdminClientCertificate().certificateSha512ThumbprintHex(), + certificates.getMinimalClientCertificate().certificateSha512ThumbprintHex())); initParameters.put("dev.dsf.fhir.debug.log.message.dbStatement", "true"); initParameters.put("dev.dsf.fhir.server.endpoint.address", @@ -207,12 +205,10 @@ private static JettyServer createFhirServer(Map initParameters) .jksForTrustedCertificates(certificates.getCaCertificate()); KeyStore serverCertificateKeyStore = certificates.getServerCertificate().keyStore(); - Function apiConnector = JettyServer.httpsConnector( - apiConnectorChannel, + Function apiConnector = JettyServer.httpsConnector(apiConnectorChannel, clientCertificateTrustStore, serverCertificateKeyStore, certificates.getServerCertificate().keyStorePassword(), false); - Function statusConnector = JettyServer.statusConnector( - statusConnectorChannel); + Function statusConnector = JettyServer.statusConnector(statusConnectorChannel); List> servletContainerInitializers = List.of( JakartaWebSocketServletContainerInitializer.class, JerseyServletContainerInitializer.class, SpringServletContainerInitializer.class); @@ -243,8 +239,12 @@ public void testFhirServerStartupWithoutThumbprint() throws Exception { fhirServer = createFhirServer(getDefaultInitParameters(statusConnectorChannel, apiConnectorChannel)); fhirServer.start(); - Organization organization = (Organization) webserviceClient.search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0).getResource(); - String thumbprint = organization.getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint").getValue().primitiveValue(); + Organization organization = (Organization) webserviceClient + .search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0) + .getResource(); + String thumbprint = organization + .getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint") + .getValue().primitiveValue(); assertEquals(certificates.getClientCertificate().certificateSha512ThumbprintHex(), thumbprint); } @@ -253,8 +253,12 @@ public void testFhirServerStartupWithThumbprint() throws Exception { fhirServer = createFhirServer(getInitParametersWithThumbprint(statusConnectorChannel, apiConnectorChannel)); fhirServer.start(); - Organization organization = (Organization) webserviceClient.search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0).getResource(); - String thumbprint = organization.getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint").getValue().primitiveValue(); + Organization organization = (Organization) webserviceClient + .search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0) + .getResource(); + String thumbprint = organization + .getExtensionByUrl("http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint") + .getValue().primitiveValue(); assertEquals(certificates.getClientCertificate().certificateSha512ThumbprintHex(), thumbprint); } From 553643596d7fcf04b364c5361dcc7c1611e2cb52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Thu, 30 Oct 2025 10:38:55 +0100 Subject: [PATCH 08/11] Fixed ClosedChannelException by creating new channels before each test run --- ...OrganizationThumbprintIntegrationTest.java | 51 +++++++++++++++++-- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java index 74607a83f..e7a1a19b0 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java @@ -26,6 +26,7 @@ import org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer; import org.hl7.fhir.r4.model.Organization; import org.junit.After; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; @@ -88,8 +89,8 @@ public class OrganizationThumbprintIntegrationTest extends AbstractDbTest private static String baseUrl; private static JettyServer fhirServer; private static FhirWebserviceClient webserviceClient; - private static final ServerSocketChannel apiConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); - private static final ServerSocketChannel statusConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); + private ServerSocketChannel apiConnectorChannel; + private ServerSocketChannel statusConnectorChannel; @BeforeClass public static void beforeClass() throws Exception @@ -97,6 +98,13 @@ public static void beforeClass() throws Exception defaultDataSource = createDefaultDataSource(liquibaseRule.getHost(), liquibaseRule.getMappedPort(5432), liquibaseRule.getDatabaseName()); defaultDataSource.unwrap(BasicDataSource.class).start(); + } + + @Before + public void before() + { + apiConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); + statusConnectorChannel = JettyServer.serverSocketChannel("127.0.0.1"); baseUrl = "https://localhost:" + apiConnectorChannel.socket().getLocalPort() + CONTEXT_PATH; @@ -198,7 +206,8 @@ private static Map getInitParametersWithThumbprint(ServerSocketC return initParameters; } - private static JettyServer createFhirServer(Map initParameters) throws Exception + private static JettyServer createFhirServer(Map initParameters, + ServerSocketChannel apiConnectorChannel, ServerSocketChannel statusConnectorChannel) throws Exception { KeyStore clientCertificateTrustStore = KeyStoreCreator @@ -237,7 +246,8 @@ private static JettyServer createFhirServer(Map initParameters) @Test public void testFhirServerStartupWithoutThumbprint() throws Exception { - fhirServer = createFhirServer(getDefaultInitParameters(statusConnectorChannel, apiConnectorChannel)); + fhirServer = createFhirServer(getDefaultInitParameters(statusConnectorChannel, apiConnectorChannel), + apiConnectorChannel, statusConnectorChannel); fhirServer.start(); Organization organization = (Organization) webserviceClient .search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0) @@ -251,7 +261,8 @@ public void testFhirServerStartupWithoutThumbprint() throws Exception @Test public void testFhirServerStartupWithThumbprint() throws Exception { - fhirServer = createFhirServer(getInitParametersWithThumbprint(statusConnectorChannel, apiConnectorChannel)); + fhirServer = createFhirServer(getInitParametersWithThumbprint(statusConnectorChannel, apiConnectorChannel), + apiConnectorChannel, statusConnectorChannel); fhirServer.start(); Organization organization = (Organization) webserviceClient .search(Organization.class, Map.of("identifier", List.of("Test_Organization"))).getEntry().get(0) @@ -278,6 +289,36 @@ public void cleanUp() throws Exception logger.error("Error while stopping FHIR Server", e); } + try + { + if (apiConnectorChannel != null) + { + logger.info("Closing API Connector Channel..."); + apiConnectorChannel.close(); + } + } + catch (Exception e) + { + logger.error("Error while closing API Connector Channel", e); + } + + try + { + if (statusConnectorChannel != null) + { + logger.info("Closing Status Connector Channel..."); + statusConnectorChannel.close(); + } + } + catch (Exception e) + { + logger.error("Error while closing Status Connector Channel", e); + } + + if (webserviceClient != null) + { + webserviceClient = null; + } defaultDataSource.unwrap(BasicDataSource.class).close(); } } From 54a8e7874184369bade1d8cd13e991d0321d69ba Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Fri, 31 Oct 2025 19:02:58 +0100 Subject: [PATCH 09/11] removed unused imports --- .../dev/dsf/bpe/integration/AbstractIntegrationTest.java | 8 -------- .../dev/dsf/fhir/integration/AbstractIntegrationTest.java | 7 ------- 2 files changed, 15 deletions(-) diff --git a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java index b3de18841..cddb07491 100644 --- a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java +++ b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java @@ -5,9 +5,6 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.net.URI; import java.nio.channels.ServerSocketChannel; import java.nio.charset.StandardCharsets; @@ -42,10 +39,6 @@ import org.eclipse.jetty.server.ServerConnector; import org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Endpoint; -import org.hl7.fhir.r4.model.Extension; -import org.hl7.fhir.r4.model.Organization; -import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Subscription; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -64,7 +57,6 @@ import de.hsheilbronn.mi.utils.test.PostgreSqlContainerLiquibaseTemplateClassRule; import de.hsheilbronn.mi.utils.test.PostgresTemplateRule; import dev.dsf.bpe.dao.AbstractDbTest; -import dev.dsf.bpe.integration.X509Certificates.CertificateAndPrivateKey; import dev.dsf.common.auth.ClientCertificateAuthenticator; import dev.dsf.common.auth.DelegatingAuthenticator; import dev.dsf.common.auth.DsfLoginService; diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java index ffd39d71f..26dae89f5 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java @@ -7,8 +7,6 @@ import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.net.URI; import java.nio.channels.ServerSocketChannel; import java.nio.file.Files; @@ -19,7 +17,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; @@ -35,9 +32,6 @@ import org.eclipse.jetty.server.ServerConnector; import org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Extension; -import org.hl7.fhir.r4.model.Organization; -import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Subscription; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -70,7 +64,6 @@ import dev.dsf.fhir.client.WebsocketClient; import dev.dsf.fhir.client.WebsocketClientTyrus; import dev.dsf.fhir.dao.AbstractDbTest; -import dev.dsf.fhir.integration.X509Certificates.CertificateAndPrivateKey; import dev.dsf.fhir.service.ReferenceCleaner; import dev.dsf.fhir.service.ReferenceCleanerImpl; import dev.dsf.fhir.service.ReferenceExtractorImpl; From e6e735752b11ce2d9f20c5cf93a98925a6ce4073 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Fri, 31 Oct 2025 19:16:11 +0100 Subject: [PATCH 10/11] inlined bundle path --- .../dev/dsf/bpe/integration/AbstractIntegrationTest.java | 4 +--- .../dev/dsf/fhir/integration/AbstractIntegrationTest.java | 6 +----- .../integration/OrganizationThumbprintIntegrationTest.java | 7 +------ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java index cddb07491..4676c760b 100644 --- a/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java +++ b/dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/AbstractIntegrationTest.java @@ -107,8 +107,6 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest private static final Path EMPTY_PROCESS_DIRECTORY = Paths.get("target", UUID.randomUUID().toString()); private static final List DIRECTORIES_TO_DELETE = List.of(EMPTY_PROCESS_DIRECTORY); - private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration", - "test-bundle.xml"); private static final Path ALLOWED_BPE_CLASSES_LIST_FILE_V1 = Paths.get("target", UUID.randomUUID().toString() + ".list"); private static final Path ALLOWED_BPE_CLASSES_LIST_FILE_V2 = Paths.get("target", @@ -260,7 +258,7 @@ private static JettyServer startFhirServer(ServerSocketChannel statusConnectorCh initParameters.put("dev.dsf.fhir.server.base.url", baseUrl); initParameters.put("dev.dsf.fhir.server.organization.identifier.value", "Test_Organization"); - initParameters.put("dev.dsf.fhir.server.init.bundle", FHIR_BUNDLE_FILE.toString()); + initParameters.put("dev.dsf.fhir.server.init.bundle", "src/test/resources/integration/test-bundle.xml"); initParameters.put("dev.dsf.fhir.client.trust.server.certificate.cas", certificates.getCaCertificateFile().toString()); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java index 26dae89f5..a45751def 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/AbstractIntegrationTest.java @@ -11,7 +11,6 @@ import java.nio.channels.ServerSocketChannel; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.security.KeyStore; import java.time.Duration; import java.util.HashMap; @@ -93,9 +92,6 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest protected static final String CONTEXT_PATH = "/fhir"; - private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration", - "test-bundle.xml"); - protected static final FhirContext fhirContext = FhirContext.forR4(); protected static final ReadAccessHelper readAccessHelper = new ReadAccessHelperImpl(); protected static final ProcessAuthorizationHelper processAuthorizationHelper = new ProcessAuthorizationHelperImpl(); @@ -192,7 +188,7 @@ private static JettyServer startFhirServer(ServerSocketChannel statusConnectorCh initParameters.put("dev.dsf.fhir.server.base.url", baseUrl); initParameters.put("dev.dsf.fhir.server.organization.identifier.value", "Test_Organization"); - initParameters.put("dev.dsf.fhir.server.init.bundle", FHIR_BUNDLE_FILE.toString()); + initParameters.put("dev.dsf.fhir.server.init.bundle", "src/test/resources/integration/test-bundle.xml"); initParameters.put("dev.dsf.fhir.client.trust.server.certificate.cas", certificates.getCaCertificateFile().toString()); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java index e7a1a19b0..a077c33a9 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/OrganizationThumbprintIntegrationTest.java @@ -3,8 +3,6 @@ import static org.junit.Assert.assertEquals; import java.nio.channels.ServerSocketChannel; -import java.nio.file.Path; -import java.nio.file.Paths; import java.security.KeyStore; import java.time.Duration; import java.util.HashMap; @@ -78,9 +76,6 @@ public class OrganizationThumbprintIntegrationTest extends AbstractDbTest protected static final String CONTEXT_PATH = "/fhir"; - private static final Path FHIR_BUNDLE_FILE = Paths.get("src", "test", "resources", "integration", - "test-bundle.xml"); - protected static final FhirContext fhirContext = FhirContext.forR4(); protected static final ReadAccessHelper readAccessHelper = new ReadAccessHelperImpl(); @@ -143,7 +138,7 @@ private static Map getDefaultInitParameters(ServerSocketChannel initParameters.put("dev.dsf.fhir.server.base.url", baseUrl); initParameters.put("dev.dsf.fhir.server.organization.identifier.value", "Test_Organization"); - initParameters.put("dev.dsf.fhir.server.init.bundle", FHIR_BUNDLE_FILE.toString()); + initParameters.put("dev.dsf.fhir.server.init.bundle", "src/test/resources/integration/test-bundle.xml"); initParameters.put("dev.dsf.fhir.client.trust.server.certificate.cas", certificates.getCaCertificateFile().toString()); From f35b434d9c37f3aab7cdedc8a713787a7097049c Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Fri, 31 Oct 2025 20:41:57 +0100 Subject: [PATCH 11/11] removed thumbprint configs from test setups, renamed .env entries Run "mvn dsf:generate-dev-setup-cert-files" to update generated .env files. --- dsf-docker-test-setup-3dic-ttp/docker-compose.yml | 10 +++------- dsf-docker-test-setup/fhir/docker-compose.yml | 1 - .../templates/dsf-docker-test-setup-3dic-ttp.env | 7 +++---- .../resources/templates/dsf-docker-test-setup-fhir.env | 1 - 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml index 78f22570f..fbc74c84e 100644 --- a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml +++ b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml @@ -165,7 +165,6 @@ services: DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: dic1_fhir_server_permanent_delete_user DEV_DSF_FHIR_SERVER_BASE_URL: https://dic1/fhir DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC_1 - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT: ${DIC1_BUNDLE_USER_THUMBPRINT} DEV_DSF_FHIR_SERVER_ROLECONFIG: | - webbrowser_test_user: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} @@ -252,7 +251,6 @@ services: DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: dic2_fhir_server_permanent_delete_user DEV_DSF_FHIR_SERVER_BASE_URL: https://dic2/fhir DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC_2 - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT: ${DIC2_BUNDLE_USER_THUMBPRINT} DEV_DSF_FHIR_SERVER_ROLECONFIG: | - webbrowser_test_user: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} @@ -334,7 +332,6 @@ services: DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: dic3_fhir_server_permanent_delete_user DEV_DSF_FHIR_SERVER_BASE_URL: https://dic3/fhir DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_DIC_3 - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT: ${DIC3_BUNDLE_USER_THUMBPRINT} DEV_DSF_FHIR_SERVER_ROLECONFIG: | - webbrowser_test_user: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} @@ -418,10 +415,9 @@ services: DEV_DSF_FHIR_DB_USER_PERMANENT_DELETE_USERNAME: ttp_fhir_server_permanent_delete_user DEV_DSF_FHIR_SERVER_BASE_URL: https://ttp/fhir DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_TTP - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT: ${TTP_BUNDLE_USER_THUMBPRINT} - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT_DIC1: ${DIC1_BUNDLE_USER_THUMBPRINT} - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT_DIC2: ${DIC2_BUNDLE_USER_THUMBPRINT} - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT_DIC3: ${DIC3_BUNDLE_USER_THUMBPRINT} + DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT_DIC1: ${DIC1_THUMBPRINT} + DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT_DIC2: ${DIC2_THUMBPRINT} + DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT_DIC3: ${DIC3_THUMBPRINT} DEV_DSF_FHIR_SERVER_ROLECONFIG: | - webbrowser_test_user: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} diff --git a/dsf-docker-test-setup/fhir/docker-compose.yml b/dsf-docker-test-setup/fhir/docker-compose.yml index 0fc5f7176..40dd026b9 100755 --- a/dsf-docker-test-setup/fhir/docker-compose.yml +++ b/dsf-docker-test-setup/fhir/docker-compose.yml @@ -68,7 +68,6 @@ services: DEV_DSF_FHIR_SERVER_UI_THEME: dev DEV_DSF_FHIR_SERVER_BASE_URL: https://fhir/fhir DEV_DSF_FHIR_SERVER_ORGANIZATION_IDENTIFIER_VALUE: Test_Organization - DEV_DSF_FHIR_SERVER_ORGANIZATION_THUMBPRINT: ${BUNDLE_USER_THUMBPRINT} DEV_DSF_FHIR_SERVER_ROLECONFIG: | - webbrowser_test_user: thumbprint: ${WEBBROWSER_TEST_USER_THUMBPRINT} diff --git a/src/main/resources/templates/dsf-docker-test-setup-3dic-ttp.env b/src/main/resources/templates/dsf-docker-test-setup-3dic-ttp.env index 3fc1812bd..1babebec3 100644 --- a/src/main/resources/templates/dsf-docker-test-setup-3dic-ttp.env +++ b/src/main/resources/templates/dsf-docker-test-setup-3dic-ttp.env @@ -1,5 +1,4 @@ WEBBROWSER_TEST_USER_THUMBPRINT=${Webbrowser Test User.thumbprint} -DIC1_BUNDLE_USER_THUMBPRINT=${dic1.thumbprint} -DIC2_BUNDLE_USER_THUMBPRINT=${dic2.thumbprint} -DIC3_BUNDLE_USER_THUMBPRINT=${dic3.thumbprint} -TTP_BUNDLE_USER_THUMBPRINT=${ttp.thumbprint} \ No newline at end of file +DIC1_THUMBPRINT=${dic1.thumbprint} +DIC2_THUMBPRINT=${dic2.thumbprint} +DIC3_THUMBPRINT=${dic3.thumbprint} \ No newline at end of file diff --git a/src/main/resources/templates/dsf-docker-test-setup-fhir.env b/src/main/resources/templates/dsf-docker-test-setup-fhir.env index bee4009f2..d00663b5f 100644 --- a/src/main/resources/templates/dsf-docker-test-setup-fhir.env +++ b/src/main/resources/templates/dsf-docker-test-setup-fhir.env @@ -1,2 +1 @@ -BUNDLE_USER_THUMBPRINT=${bpe.thumbprint} WEBBROWSER_TEST_USER_THUMBPRINT=${Webbrowser Test User.thumbprint} \ No newline at end of file