Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/release/1.1.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
hhund committed Aug 22, 2023
2 parents 6f03aa9 + 0a9f033 commit 195d03f
Show file tree
Hide file tree
Showing 186 changed files with 4,278 additions and 2,467 deletions.
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ preferred-citation:
doi: 10.3233/SHTI210060
type: proceedings
title: "Data Sharing Framework (DSF)"
version: 1.0.0
date-released: 2023-06-28
version: 1.1.0
date-released: 2023-08-22
url: https://dsf.dev
repository-code: https://github.com/datasharingframework/dsf
repository-artifact: https://github.com/datasharingframework/dsf/releases
Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Data Sharing Framework (DSF)
![Data Sharing Framework (DSF) logo.](dsf-fhir/dsf-fhir-server/src/main/resources/static/logo.svg)

The Data Sharing Framework (DSF) implements a distributed process engine based on the BPMN 2.0 and FHIR R4 standards. The DSF is used to support biomedical research with real-world data. Every participating site runs a FHIR endpoint (dsf-fhir) accessible by other sites and a business process engine (dsf-bpe) in the local secured network. Authentication between sites is handled using X.509 client/server certificates. The process engines execute BPMN processes in order to coordinate local and remote steps necessary to enable cross-site data sharing and feasibility analyses. This includes access to local data repositories, use-and-access-committee decision support, consent filtering, and privacy preserving record-linkage and pseudonymization.
The Data Sharing Framework (DSF) implements a distributed process engine based on the BPMN 2.0 and FHIR R4 standards. The DSF is used to support biomedical research with real-world data. Every participating site runs a FHIR endpoint (dsf-fhir) accessible by other sites and a business process engine (dsf-bpe) in the local secured network. Authentication between sites is handled using X.509 client/server certificates. The process engines execute BPMN processes in order to coordinate local and remote steps necessary to enable cross-site data sharing and feasibility analyses. This includes access to local data repositories, use-and-access-committee decision support, consent filtering, and privacy preserving record-linkage and pseudonymization.

For [installation instructions](https://dsf.dev/stable/maintain/install.html), tutorials, publications, and other information about the DSF, visit [https://dsf.dev](https://dsf.dev).

## Development
Branching follows the git-flow model, for the latest development version see branch [develop](https://github.com/datasharingframework/dsf/tree/develop).

## License
All code from the Data Sharing Framework is published under the [Apache-2.0 License](LICENSE).
All code from the Data Sharing Framework is published under the [Apache-2.0 License](LICENSE).

## Public Funding
The DSF is funded by the German Federal Ministry of Education and Research (BMBF) within the [Data Sharing Framework Community](https://www.gesundheitsforschung-bmbf.de/de/dsf-medizininformatik-struktur-data-sharing-framework-community-16133.php) project of the [German Medical Informatics Initiative](https://www.medizininformatik-initiative.de/en/start), grant IDs 01ZZ2307A, 01ZZ2307B and 01ZZ2307C.

## Earlier Versions
Earlier versions of the DSF, developed as part of the HiGHmed research consortium, can be found at [highmed/highmed-dsf](https://github.com/highmed/highmed-dsf).
2 changes: 1 addition & 1 deletion dsf-bpe/dsf-bpe-process-api-v1/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-bpe-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public FhirWebserviceClient createClient(String baseUrl) throws Exception
FhirContext context = FhirContext.forR4();
ReferenceCleaner referenceCleaner = new ReferenceCleanerImpl(new ReferenceExtractorImpl());

return new FhirWebserviceClientJersey(baseUrl, trustStore, keyStore, certificatePassword, null, null, null, 0,
0, false, null, context, referenceCleaner);
return new FhirWebserviceClientJersey(baseUrl, trustStore, keyStore, certificatePassword, null, null, null,
null, 0, 0, false, "DSF Example Starter", context, referenceCleaner);
}
}
2 changes: 1 addition & 1 deletion dsf-bpe/dsf-bpe-server-jetty/conf/jetty.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ dev.dsf.server.certificate=target/localhost_certificate.pem
dev.dsf.server.certificate.key=target/localhost_private-key.pem
dev.dsf.server.certificate.key.password=password

dev.dsf.server.trust.client.certificate.cas=target/testca_certificate.pem
dev.dsf.server.auth.trust.client.certificate.cas=target/testca_certificate.pem
2 changes: 1 addition & 1 deletion dsf-bpe/dsf-bpe-server-jetty/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-bpe-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion dsf-bpe/dsf-bpe-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-bpe-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
import dev.dsf.fhir.client.WebsocketClient;
import dev.dsf.fhir.client.WebsocketClientTyrus;
import dev.dsf.fhir.service.ReferenceCleaner;
import dev.dsf.tools.build.BuildInfoReader;

public class FhirClientProviderImpl implements FhirClientProvider, InitializingBean
{
private static final Logger logger = LoggerFactory.getLogger(FhirClientProviderImpl.class);
private static final String USER_AGENT_VALUE = "DSF/";

private final Map<String, FhirWebserviceClient> webserviceClientsByUrl = new HashMap<>();
private final Map<String, WebsocketClient> websocketClientsBySubscriptionId = new HashMap<>();
Expand All @@ -47,13 +49,15 @@ public class FhirClientProviderImpl implements FhirClientProvider, InitializingB
private final char[] localWebsocketKeyStorePassword;

private final ProxyConfig proxyConfig;
private final BuildInfoReader buildInfoReader;

public FhirClientProviderImpl(FhirContext fhirContext, ReferenceCleaner referenceCleaner,
String localWebserviceBaseUrl, int localWebserviceReadTimeout, int localWebserviceConnectTimeout,
boolean localWebserviceLogRequests, KeyStore webserviceTrustStore, KeyStore webserviceKeyStore,
char[] webserviceKeyStorePassword, int remoteWebserviceReadTimeout, int remoteWebserviceConnectTimeout,
boolean remoteWebserviceLogRequests, String localWebsocketUrl, KeyStore localWebsocketTrustStore,
KeyStore localWebsocketKeyStore, char[] localWebsocketKeyStorePassword, ProxyConfig proxyConfig)
KeyStore localWebsocketKeyStore, char[] localWebsocketKeyStorePassword, ProxyConfig proxyConfig,
BuildInfoReader buildInfoReader)
{
this.fhirContext = fhirContext;
this.referenceCleaner = referenceCleaner;
Expand All @@ -77,6 +81,7 @@ public FhirClientProviderImpl(FhirContext fhirContext, ReferenceCleaner referenc
this.localWebsocketKeyStorePassword = localWebsocketKeyStorePassword;

this.proxyConfig = proxyConfig;
this.buildInfoReader = buildInfoReader;
}

@Override
Expand All @@ -101,6 +106,7 @@ public void afterPropertiesSet() throws Exception
Objects.requireNonNull(localWebsocketKeyStorePassword, "localWebsocketKeyStorePassword");

Objects.requireNonNull(proxyConfig, "proxyConfig");
Objects.requireNonNull(buildInfoReader, "buildInfoReader");
}

public String getLocalBaseUrl()
Expand All @@ -123,14 +129,14 @@ private FhirWebserviceClient getClient(String webserviceUrl)
FhirWebserviceClient client;
if (localWebserviceBaseUrl.equals(webserviceUrl))
client = new FhirWebserviceClientJersey(webserviceUrl, webserviceTrustStore, webserviceKeyStore,
webserviceKeyStorePassword, proxyUrl, proxyUsername, proxyPassword,
localWebserviceConnectTimeout, localWebserviceReadTimeout, localWebserviceLogRequests, null,
fhirContext, referenceCleaner);
webserviceKeyStorePassword, null, proxyUrl, proxyUsername, proxyPassword,
localWebserviceConnectTimeout, localWebserviceReadTimeout, localWebserviceLogRequests,
USER_AGENT_VALUE + buildInfoReader.getProjectVersion(), fhirContext, referenceCleaner);
else
client = new FhirWebserviceClientJersey(webserviceUrl, webserviceTrustStore, webserviceKeyStore,
webserviceKeyStorePassword, proxyUrl, proxyUsername, proxyPassword,
webserviceKeyStorePassword, null, proxyUrl, proxyUsername, proxyPassword,
remoteWebserviceConnectTimeout, remoteWebserviceReadTimeout, remoteWebserviceLogRequests,
null, fhirContext, referenceCleaner);
USER_AGENT_VALUE + buildInfoReader.getProjectVersion(), fhirContext, referenceCleaner);

webserviceClientsByUrl.put(webserviceUrl, client);
return client;
Expand Down Expand Up @@ -179,7 +185,8 @@ protected WebsocketClientTyrus createWebsocketClient(Runnable reconnector, Strin
localWebsocketKeyStore, localWebsocketKeyStorePassword,
proxyConfig.isEnabled(localWebsocketUrl) ? proxyConfig.getUrl() : null,
proxyConfig.isEnabled(localWebsocketUrl) ? proxyConfig.getUsername() : null,
proxyConfig.isEnabled(localWebsocketUrl) ? proxyConfig.getPassword() : null, subscriptionId);
proxyConfig.isEnabled(localWebsocketUrl) ? proxyConfig.getPassword() : null,
USER_AGENT_VALUE + buildInfoReader.getProjectVersion(), subscriptionId);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1108,27 +1108,14 @@ private boolean isValid(Measure resource, String file)
private boolean isValid(NamingSystem resource, String file)
{
boolean nameOk = resource.hasName();
boolean versionDefined = resource.hasVersion();
boolean versionOk = versionDefined && resource.getVersion().equals(getDefinitionResourceVersion());

if (!nameOk)
{
logger.warn("Ignoring FHIR resource {} from process plugin {}-{}: NamingSystem.name empty", file,
getDefinitionName(), getDefinitionVersion());
}

if (!versionDefined)
{
logger.warn("Ignoring FHIR resource {} from process plugin {}-{}: NamingSystem.version empty", file,
getDefinitionName(), getDefinitionVersion());
}
else if (!versionOk)
{
logger.warn("Ignoring FHIR resource {} from process plugin {}-{}: NamingSystem.version not equal to {}",
file, getDefinitionName(), getDefinitionVersion(), getDefinitionResourceVersion());
}

return nameOk && versionOk;
return nameOk;
}

private boolean isValid(Questionnaire resource, String file)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class FhirClientConfig implements InitializingBean
@Autowired
private FhirConfig fhirConfig;

@Autowired
private BuildInfoReaderConfig buildInfoReaderConfig;

@Override
public void afterPropertiesSet() throws Exception
{
Expand Down Expand Up @@ -105,7 +108,8 @@ public FhirClientProvider clientProvider()
keyStorePassword, propertiesConfig.getWebserviceClientRemoteReadTimeout(),
propertiesConfig.getWebserviceClientRemoteConnectTimeout(),
propertiesConfig.getWebserviceClientRemoteVerbose(), getWebsocketUrl(), webserviceTrustStore,
webserviceKeyStore, keyStorePassword, propertiesConfig.proxyConfig());
webserviceKeyStore, keyStorePassword, propertiesConfig.proxyConfig(),
buildInfoReaderConfig.buildInfoReader());
}
catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException | PKCSException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public Optional<Organization> getOrganization(Identifier organizationIdentifier)

String organizationIdSp = toSearchParameter(organizationIdentifier);

Bundle resultBundle = clientProvider.getLocalWebserviceClient().searchWithStrictHandling(Endpoint.class,
Map.of("status", Collections.singletonList("active"), "identifier",
Bundle resultBundle = clientProvider.getLocalWebserviceClient().searchWithStrictHandling(Organization.class,
Map.of("active", Collections.singletonList("true"), "identifier",
Collections.singletonList(organizationIdSp)));

if (resultBundle == null || resultBundle.getEntry() == null || resultBundle.getTotal() != 1
Expand Down
2 changes: 1 addition & 1 deletion dsf-bpe/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<modules>
Expand Down
2 changes: 1 addition & 1 deletion dsf-common/dsf-common-auth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-common-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion dsf-common/dsf-common-config/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-common-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion dsf-common/dsf-common-documentation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-common-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>
</project>
2 changes: 1 addition & 1 deletion dsf-common/dsf-common-jetty/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-common-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion dsf-common/dsf-common-status/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-common-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion dsf-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<modules>
Expand Down
2 changes: 2 additions & 0 deletions dsf-docker-test-setup/fhir/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ services:
- SEARCH
- HISTORY
- PERMANENT_DELETE
practitioner-role:
- http://dsf.dev/fhir/CodeSystem/practitioner-role|DSF_ADMIN
DEV_DSF_SERVER_AUTH_TRUST_CLIENT_CERTIFICATE_CAS: /run/secrets/app_client_trust_certificates.pem
networks:
frontend:
Expand Down
3 changes: 3 additions & 0 deletions dsf-docker/fhir_proxy/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ RUN mkdir /usr/local/apache2/ssl/ && \
ENV SSL_CERTIFICATE_CHAIN_FILE="/does/not/exist"
ENV SSL_CA_DN_REQUEST_FILE="/does/not/exist"

# setting default value - client certificate required, use 'optional' when using OIDC
ENV SSL_VERIFY_CLIENT="require"

# timeout (seconds) for reverse proxy to app server http connection, time the proxy waits for a reply
ENV PROXY_PASS_TIMEOUT_HTTP=60
# timeout (seconds) for reverse proxy to app server ws connection, time the proxy waits for a reply
Expand Down
5 changes: 3 additions & 2 deletions dsf-docker/fhir_proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ ${HTTPS\_SERVER\_NAME\_PORT} - example: localhost:8443
${APP\_SERVER\_IP} - example: 172.28.1.3
${SSL\_CERTIFICATE\_FILE} - to set apache config param `SSLCertificateFile`
${SSL\_CERTIFICATE\_KEY\_FILE} - to set apache config param `SSLCertificateKeyFile`
${SSL\_CERTIFICATE\_CHAIN\_FILE} - to set apache config param `SSLCertificateChainFile` (optional)
${SSL\_CERTIFICATE\_CHAIN\_FILE} - to set apache config param `SSLCertificateChainFile` (optional environment variable)
${SSL\_CA\_CERTIFICATE\_FILE} - to set apache config param `SSLCACertificateFile`
${SSL\_CA\_DN\_REQUEST\_FILE} - to set apache config param `SSLCADNRequestFile` (optional)
${SSL\_CA\_DN\_REQUEST\_FILE} - to set apache config param `SSLCADNRequestFile` (optional environment variable)
${SSL\_VERIFY\_CLIENT} - to set apache config param `SSLVerifyClient `, default value `require`, set to `optional` when using OIDC authentication
${PROXY\_PASS\_TIMEOUT\_HTTP} - timeout (seconds) for reverse proxy to app server http connection, time the proxy waits for a reply, default: `60` seconds
${PROXY\_PASS\_TIMEOUT\_WS} - timeout (seconds) for reverse proxy to app server ws connection, time the proxy waits for a reply, default: `60` seconds
${PROXY\_PASS\_CONNECTION\_TIMEOUT\_HTTP} - connection timeout (seconds) for reverse proxy to app server http connection, time the proxy waits for a connection to be established, default: `30` seconds
Expand Down
4 changes: 2 additions & 2 deletions dsf-docker/fhir_proxy/conf/extra/host-ssl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ SSLCACertificateFile "${SSL_CA_CERTIFICATE_FILE}"
# SSLVerifyDepth n: max n signing CAs allowed between client certificate and root certificate

SSLVerifyDepth 3
SSLVerifyClient require
SSLVerifyClient "${SSL_VERIFY_CLIENT}"

SSLOptions +ExportCertData
RequestHeader set X-ClientCert ""
Expand All @@ -49,6 +49,6 @@ Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains
ProxyPassReverse ws://${APP_SERVER_IP}:8080/fhir/ws
</Location>

CustomLog /proc/self/fd/1 "%h %t \"%r\" %>s %b %{SSL_PROTOCOL}x %{SSL_CIPHER}x"
CustomLog /proc/self/fd/1 "%h %t \"%r\" %>s %b %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{user-agent}i %{SSL_CLIENT_S_DN}x"

</VirtualHost>
2 changes: 1 addition & 1 deletion dsf-fhir/dsf-fhir-auth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-fhir-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
Expand Down
4 changes: 2 additions & 2 deletions dsf-fhir/dsf-fhir-rest-adapter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
<parent>
<groupId>dev.dsf</groupId>
<artifactId>dsf-fhir-pom</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
</parent>

<dependencies>
<dependency>
<groupId>dev.dsf</groupId>
<artifactId>dsf-common-auth</artifactId>
</dependency>

<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
Expand Down

This file was deleted.

Loading

0 comments on commit 195d03f

Please sign in to comment.