diff --git a/pom.xml b/pom.xml
index 6c3a783..d086735 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
de.medizininformatik-initiative
mii-process-data-transfer
- 1.0.1.1-SNAPSHOT
+ 1.0.2.0-SNAPSHOT
UTF-8
@@ -45,7 +45,7 @@
de.medizininformatik-initiative
mii-processes-common
- 1.0.1.0
+ 1.0.2.0-SNAPSHOT
diff --git a/src/main/java/de/medizininformatik_initiative/process/data_transfer/DataTransferProcessPluginDefinition.java b/src/main/java/de/medizininformatik_initiative/process/data_transfer/DataTransferProcessPluginDefinition.java
index 5d84198..f2e1af9 100644
--- a/src/main/java/de/medizininformatik_initiative/process/data_transfer/DataTransferProcessPluginDefinition.java
+++ b/src/main/java/de/medizininformatik_initiative/process/data_transfer/DataTransferProcessPluginDefinition.java
@@ -11,7 +11,7 @@
public class DataTransferProcessPluginDefinition implements ProcessPluginDefinition
{
- public static final String VERSION = "1.0.1.1";
+ public static final String VERSION = "1.0.2.0";
public static final LocalDate RELEASE_DATE = LocalDate.of(2024, 6, 11);
@Override
diff --git a/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DicFhirClientConfig.java b/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DicFhirClientConfig.java
index d254212..6dcdc3f 100644
--- a/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DicFhirClientConfig.java
+++ b/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DicFhirClientConfig.java
@@ -11,15 +11,22 @@
import ca.uhn.fhir.context.FhirContext;
import de.medizininformatik_initiative.processes.common.fhir.client.FhirClientFactory;
import de.medizininformatik_initiative.processes.common.fhir.client.logging.DataLogger;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.OAuth2TokenClient;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.OAuth2TokenProvider;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.TokenClient;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.TokenProvider;
+import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.documentation.ProcessDocumentation;
@Configuration
public class DicFhirClientConfig
{
- // TODO: use default proxy config from DSF
@Autowired
private FhirContext fhirContext;
+ @Autowired
+ private ProcessPluginApi api;
+
@ProcessDocumentation(required = true, processNames = {
"medizininformatik-initiativede_dataSend" }, description = "The base address of the DIC FHIR server to read/store FHIR resources", example = "http://foo.bar/fhir")
@Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.base.url:#{null}}")
@@ -81,20 +88,65 @@ public class DicFhirClientConfig
private boolean fhirStoreHapiClientVerbose;
@ProcessDocumentation(processNames = {
- "medizininformatik-initiativede_dataSend" }, description = "Proxy location, set if the server containing the FHIR data can only be reached through a proxy", example = "http://proxy.foo:8080")
+ "medizininformatik-initiativede_dataSend" }, description = "Proxy location, set if the server containing the FHIR data can only be reached through a proxy, uses value from DEV_DSF_PROXY_URL if not set", example = "http://proxy.foo:8080")
@Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.proxy.url:#{null}}")
private String fhirStoreProxyUrl;
@ProcessDocumentation(processNames = {
- "medizininformatik-initiativede_dataSend" }, description = "Proxy username, set if the server containing the FHIR data can only be reached through a proxy which requests authentication")
+ "medizininformatik-initiativede_dataSend" }, description = "Proxy username, set if the server containing the FHIR data can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_USERNAME if not set")
@Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.proxy.username:#{null}}")
private String fhirStoreProxyUsername;
@ProcessDocumentation(processNames = {
- "medizininformatik-initiativede_dataSend" }, description = "Proxy password, set if the server containing the FHIR data can only be reached through a proxy which requests authentication", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
+ "medizininformatik-initiativede_dataSend" }, description = "Proxy password, set if the server containing the FHIR data can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_PASSWORD if not set", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
@Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.proxy.password:#{null}}")
private String fhirStoreProxyPassword;
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "The url of the oidc provider to request access tokens (token endpoint)", example = "http://foo.baz/realms/fhir-realm/protocol/openid-connect/token")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.issuer.url:#{null}}")
+ private String fhirStoreOAuth2IssuerUrl;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "Identifier of the client (username) used for authentication when accessing the oidc provider token endpoint")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.client.id:#{null}}")
+ private String fhirStoreOAuth2ClientId;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "Secret of the client (password) used for authentication when accessing the oidc provider token endpoint", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.client.password:#{null}}")
+ private String fhirStoreOAuth2ClientSecret;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "The timeout in milliseconds until a connection is established between the client and the oidc provider", recommendation = "Change default value only if timeout exceptions occur")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.timeout.connect:20000}")
+ private int fhirStoreOAuth2ConnectTimeout;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "Maximum period of inactivity in milliseconds between two consecutive data packets of the client and the oidc provider", recommendation = "Change default value only if timeout exceptions occur")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.timeout.socket:60000}")
+ private int fhirStoreOAuth2SocketTimeout;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "PEM encoded file with one or more trusted root certificate to validate the oidc provider server certificate when connecting via https", recommendation = "Use docker secret file to configure", example = "/run/secrets/hospital_ca.pem")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.trust.certificates:#{null}}")
+ private String fhirStoreOAuth2TrustStore;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "Proxy location, set if the oidc provider can only be reached through a proxy, uses value from DEV_DSF_PROXY_URL if not set", example = "http://proxy.foo:8080")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.proxy.url:#{null}}")
+ private String fhirStoreOAuth2ProxyUrl;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "Proxy username, set if the oidc provider can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_USERNAME if not set")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.proxy.username:#{null}}")
+ private String fhirStoreOAuth2ProxyUsername;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataSend" }, description = "Proxy password, set if the oidc provider can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_PASSWORD if not set", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
+ @Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.server.oauth2.proxy.password:#{null}}")
+ private String fhirStoreOAuth2ProxyPassword;
+
@ProcessDocumentation(processNames = {
"medizininformatik-initiativede_dataSend" }, description = "To enable debug logging of FHIR resources set to `true`")
@Value("${de.medizininformatik.initiative.data.transfer.dic.fhir.dataLoggingEnabled:false}")
@@ -109,10 +161,46 @@ public FhirClientFactory fhirClientFactory()
Path certificatePath = checkExists(fhirStoreCertificate);
Path privateKeyPath = checkExists(fhirStorePrivateKey);
+ String proxyUrl = fhirStoreProxyUrl, proxyUsername = fhirStoreProxyUsername,
+ proxyPassword = fhirStoreProxyPassword;
+ if (proxyUrl == null && api.getProxyConfig().isEnabled()
+ && !api.getProxyConfig().isNoProxyUrl(fhirStoreBaseUrl))
+ {
+ proxyUrl = api.getProxyConfig().getUrl();
+ proxyUsername = api.getProxyConfig().getUsername();
+ proxyPassword = api.getProxyConfig().getPassword() == null ? null
+ : new String(api.getProxyConfig().getPassword());
+ }
+
return new FhirClientFactory(trustStorePath, certificatePath, privateKeyPath, fhirStorePrivateKeyPassword,
fhirStoreConnectTimeout, fhirStoreSocketTimeout, fhirStoreConnectionRequestTimeout, fhirStoreBaseUrl,
- fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, fhirStoreProxyUrl, fhirStoreProxyUsername,
- fhirStoreProxyPassword, fhirStoreHapiClientVerbose, fhirContext, localIdentifierValue, dataLogger());
+ fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, tokenProvider(), proxyUrl, proxyUsername,
+ proxyPassword, fhirStoreHapiClientVerbose, fhirContext, localIdentifierValue, dataLogger());
+ }
+
+ public TokenProvider tokenProvider()
+ {
+ return new OAuth2TokenProvider(tokenClient());
+ }
+
+ public TokenClient tokenClient()
+ {
+ Path trustStoreOAuth2Path = checkExists(fhirStoreOAuth2TrustStore);
+
+ String proxyUrl = fhirStoreOAuth2ProxyUrl, proxyUsername = fhirStoreOAuth2ProxyUsername,
+ proxyPassword = fhirStoreOAuth2ProxyPassword;
+ if (proxyUrl == null && api.getProxyConfig().isEnabled()
+ && !api.getProxyConfig().isNoProxyUrl(fhirStoreOAuth2IssuerUrl))
+ {
+ proxyUrl = api.getProxyConfig().getUrl();
+ proxyUsername = api.getProxyConfig().getUsername();
+ proxyPassword = api.getProxyConfig().getPassword() == null ? null
+ : new String(api.getProxyConfig().getPassword());
+ }
+
+ return new OAuth2TokenClient(fhirStoreOAuth2IssuerUrl, fhirStoreOAuth2ClientId, fhirStoreOAuth2ClientSecret,
+ fhirStoreOAuth2ConnectTimeout, fhirStoreOAuth2SocketTimeout, trustStoreOAuth2Path, proxyUrl,
+ proxyUsername, proxyPassword);
}
public DataLogger dataLogger()
diff --git a/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DmsFhirClientConfig.java b/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DmsFhirClientConfig.java
index 6026945..a356a47 100644
--- a/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DmsFhirClientConfig.java
+++ b/src/main/java/de/medizininformatik_initiative/process/data_transfer/spring/config/DmsFhirClientConfig.java
@@ -11,15 +11,22 @@
import ca.uhn.fhir.context.FhirContext;
import de.medizininformatik_initiative.processes.common.fhir.client.FhirClientFactory;
import de.medizininformatik_initiative.processes.common.fhir.client.logging.DataLogger;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.OAuth2TokenClient;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.OAuth2TokenProvider;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.TokenClient;
+import de.medizininformatik_initiative.processes.common.fhir.client.token.TokenProvider;
+import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.documentation.ProcessDocumentation;
@Configuration
public class DmsFhirClientConfig
{
- // TODO: use default proxy config from DSF
@Autowired
private FhirContext fhirContext;
+ @Autowired
+ private ProcessPluginApi api;
+
@ProcessDocumentation(required = true, processNames = {
"medizininformatik-initiativede_dataReceive" }, description = "The base address of the DMS FHIR server to read/store FHIR resources", example = "http://foo.bar/fhir")
@Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.base.url:#{null}}")
@@ -81,20 +88,65 @@ public class DmsFhirClientConfig
private boolean fhirStoreHapiClientVerbose;
@ProcessDocumentation(processNames = {
- "medizininformatik-initiativede_dataReceive" }, description = "Proxy location, set if the server containing the FHIR data can only be reached through a proxy", example = "http://proxy.foo:8080")
+ "medizininformatik-initiativede_dataReceive" }, description = "Proxy location, set if the server containing the FHIR data can only be reached through a proxy, uses value from DEV_DSF_PROXY_URL if not set", example = "http://proxy.foo:8080")
@Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.proxy.url:#{null}}")
private String fhirStoreProxyUrl;
@ProcessDocumentation(processNames = {
- "medizininformatik-initiativede_dataReceive" }, description = "Proxy username, set if the server containing the FHIR data can only be reached through a proxy which requests authentication")
+ "medizininformatik-initiativede_dataReceive" }, description = "Proxy username, set if the server containing the FHIR data can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_USERNAME if not set")
@Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.proxy.username:#{null}}")
private String fhirStoreProxyUsername;
@ProcessDocumentation(processNames = {
- "medizininformatik-initiativede_dataReceive" }, description = "Proxy password, set if the server containing the FHIR data can only be reached through a proxy which requests authentication", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
+ "medizininformatik-initiativede_dataReceive" }, description = "Proxy password, set if the server containing the FHIR data can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_PASSWORD if not set", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
@Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.proxy.password:#{null}}")
private String fhirStoreProxyPassword;
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "The url of the oidc provider to request access tokens (token endpoint)", example = "http://foo.baz/realms/fhir-realm/protocol/openid-connect/token")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.issuer.url:#{null}}")
+ private String fhirStoreOAuth2IssuerUrl;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Identifier of the client (username) used for authentication when accessing the oidc provider token endpoint")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.client.id:#{null}}")
+ private String fhirStoreOAuth2ClientId;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Secret of the client (password) used for authentication when accessing the oidc provider token endpoint", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.client.password:#{null}}")
+ private String fhirStoreOAuth2ClientSecret;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "The timeout in milliseconds until a connection is established between the client and the oidc provider", recommendation = "Change default value only if timeout exceptions occur")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.timeout.connect:20000}")
+ private int fhirStoreOAuth2ConnectTimeout;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Maximum period of inactivity in milliseconds between two consecutive data packets of the client and the oidc provider", recommendation = "Change default value only if timeout exceptions occur")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.timeout.socket:60000}")
+ private int fhirStoreOAuth2SocketTimeout;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "PEM encoded file with one or more trusted root certificate to validate the oidc provider server certificate when connecting via https", recommendation = "Use docker secret file to configure", example = "/run/secrets/hospital_ca.pem")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.trust.certificates:#{null}}")
+ private String fhirStoreOAuth2TrustStore;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Proxy location, set if the oidc provider can only be reached through a proxy, uses value from DEV_DSF_PROXY_URL if not set", example = "http://proxy.foo:8080")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.proxy.url:#{null}}")
+ private String fhirStoreOAuth2ProxyUrl;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Proxy username, set if the oidc provider can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_USERNAME if not set")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.proxy.username:#{null}}")
+ private String fhirStoreOAuth2ProxyUsername;
+
+ @ProcessDocumentation(processNames = {
+ "medizininformatik-initiativede_dataReceive" }, description = "Proxy password, set if the oidc provider can only be reached through a proxy which requests authentication, uses value from DEV_DSF_PROXY_PASSWORD if not set", recommendation = "Use docker secret file to configure by using *${env_variable}_FILE*")
+ @Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.server.oauth2.proxy.password:#{null}}")
+ private String fhirStoreOAuth2ProxyPassword;
+
@ProcessDocumentation(processNames = {
"medizininformatik-initiativede_dataReceive" }, description = "To enable debug logging of FHIR resources set to `true`")
@Value("${de.medizininformatik.initiative.data.transfer.dms.fhir.dataLoggingEnabled:false}")
@@ -109,10 +161,46 @@ public FhirClientFactory fhirClientFactory()
Path certificatePath = checkExists(fhirStoreCertificate);
Path privateKeyPath = checkExists(fhirStorePrivateKey);
+ String proxyUrl = fhirStoreProxyUrl, proxyUsername = fhirStoreProxyUsername,
+ proxyPassword = fhirStoreProxyPassword;
+ if (proxyUrl == null && api.getProxyConfig().isEnabled()
+ && !api.getProxyConfig().isNoProxyUrl(fhirStoreBaseUrl))
+ {
+ proxyUrl = api.getProxyConfig().getUrl();
+ proxyUsername = api.getProxyConfig().getUsername();
+ proxyPassword = api.getProxyConfig().getPassword() == null ? null
+ : new String(api.getProxyConfig().getPassword());
+ }
+
return new FhirClientFactory(trustStorePath, certificatePath, privateKeyPath, fhirStorePrivateKeyPassword,
fhirStoreConnectTimeout, fhirStoreSocketTimeout, fhirStoreConnectionRequestTimeout, fhirStoreBaseUrl,
- fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, fhirStoreProxyUrl, fhirStoreProxyUsername,
- fhirStoreProxyPassword, fhirStoreHapiClientVerbose, fhirContext, localIdentifierValue, dataLogger());
+ fhirStoreUsername, fhirStorePassword, fhirStoreBearerToken, tokenProvider(), proxyUrl, proxyUsername,
+ proxyPassword, fhirStoreHapiClientVerbose, fhirContext, localIdentifierValue, dataLogger());
+ }
+
+ public TokenProvider tokenProvider()
+ {
+ return new OAuth2TokenProvider(tokenClient());
+ }
+
+ public TokenClient tokenClient()
+ {
+ Path trustStoreOAuth2Path = checkExists(fhirStoreOAuth2TrustStore);
+
+ String proxyUrl = fhirStoreOAuth2ProxyUrl, proxyUsername = fhirStoreOAuth2ProxyUsername,
+ proxyPassword = fhirStoreOAuth2ProxyPassword;
+ if (proxyUrl == null && api.getProxyConfig().isEnabled()
+ && !api.getProxyConfig().isNoProxyUrl(fhirStoreOAuth2IssuerUrl))
+ {
+ proxyUrl = api.getProxyConfig().getUrl();
+ proxyUsername = api.getProxyConfig().getUsername();
+ proxyPassword = api.getProxyConfig().getPassword() == null ? null
+ : new String(api.getProxyConfig().getPassword());
+ }
+
+ return new OAuth2TokenClient(fhirStoreOAuth2IssuerUrl, fhirStoreOAuth2ClientId, fhirStoreOAuth2ClientSecret,
+ fhirStoreOAuth2ConnectTimeout, fhirStoreOAuth2SocketTimeout, trustStoreOAuth2Path, proxyUrl,
+ proxyUsername, proxyPassword);
}
public DataLogger dataLogger()