Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -115,12 +107,11 @@ public abstract class AbstractIntegrationTest extends AbstractDbTest
private static final Path EMPTY_PROCESS_DIRECTORY = Paths.get("target", UUID.randomUUID().toString());
private static final List<Path> 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 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<Path> FILES_TO_DELETE = List.of(FHIR_BUNDLE_FILE, ALLOWED_BPE_CLASSES_LIST_FILE_V1,
private static final List<Path> FILES_TO_DELETE = List.of(ALLOWED_BPE_CLASSES_LIST_FILE_V1,
ALLOWED_BPE_CLASSES_LIST_FILE_V2);

protected static final FhirContext fhirContext = FhirContext.forR4();
Expand All @@ -141,10 +132,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 ...");
Expand Down Expand Up @@ -239,11 +226,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);
Expand All @@ -258,58 +240,6 @@ private static IParser newParser(Supplier<IParser> 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
{
Expand All @@ -328,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());
Expand Down Expand Up @@ -364,6 +294,14 @@ 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</tag>
</meta>
<extension url="http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint">
<valueString value="injected"/>
<valueString value="${dev.dsf.fhir.server.organization.thumbprint}"/>
</extension>
<identifier>
<system value="http://dsf.dev/sid/organization-identifier"/>
Expand Down Expand Up @@ -66,7 +66,7 @@
</payloadType>
<payloadMimeType value="application/fhir+json"/>
<payloadMimeType value="application/fhir+xml"/>
<address value="injected"/>
<address value="${dev.dsf.fhir.server.endpoint.address}"/>
</Endpoint>
</resource>
<request>
Expand All @@ -86,7 +86,7 @@
</tag>
</meta>
<extension url="http://dsf.dev/fhir/StructureDefinition/extension-certificate-thumbprint">
<valueString value="injected"/>
<valueString value="${dev.dsf.fhir.server.organization.thumbprint.external}"/>
</extension>
<identifier>
<system value="http://dsf.dev/sid/organization-identifier"/>
Expand Down Expand Up @@ -138,7 +138,7 @@
</payloadType>
<payloadMimeType value="application/fhir+json"/>
<payloadMimeType value="application/fhir+xml"/>
<address value="https://localhost:80010/fhir"/>
<address value="${dev.dsf.fhir.server.endpoint.address.external}"/>
</Endpoint>
</resource>
<request>
Expand Down
10 changes: 3 additions & 7 deletions dsf-docker-test-setup-3dic-ttp/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down
1 change: 0 additions & 1 deletion dsf-docker-test-setup/fhir/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -169,6 +175,7 @@ public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderCon
new DockerSecretsPropertySourceFactory(environment).readDockerSecretsAndAddPropertiesToEnvironment();

injectEndpointProperties(environment);
computeOrganizationThumbprintPropertyIfPossible(environment);

return new PropertySourcesPlaceholderConfigurer();
}
Expand All @@ -185,11 +192,38 @@ 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)
{
throw new RuntimeException(e);
logger.warn("Exception while injecting endpoint properties", e);
}
}

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)
{
logger.warn("Exception while computing organization thumbprint property", e);
}
}

Expand Down
Loading