From e0aae547f41a76634bfd262ebc5ea5dfcc475053 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 17:36:11 +0100 Subject: [PATCH 01/25] removed not needed code --- .../data_transfer/client/fhir/KdsFhirClientImpl.java | 4 ---- .../data_transfer/client/fhir/KdsFhirClientStub.java | 4 ---- .../data_transfer/bpe/start/DataSendExampleStarter.java | 2 -- 3 files changed, 10 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java index 3a64d47..0dd29a4 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientImpl.java @@ -6,15 +6,11 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.DocumentReference; import org.hl7.fhir.r4.model.IdType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClient; public class KdsFhirClientImpl implements KdsFhirClient { - private static final Logger logger = LoggerFactory.getLogger(KdsFhirClientImpl.class); - private KdsClient kdsClient; public KdsFhirClientImpl(KdsClient kdsClient) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java index 1f09efb..da77ddf 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/fhir/KdsFhirClientStub.java @@ -14,15 +14,11 @@ import org.hl7.fhir.r4.model.DocumentReference; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.ResourceType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClient; public final class KdsFhirClientStub implements KdsFhirClient { - private static final Logger logger = LoggerFactory.getLogger(KdsFhirClientStub.class); - private final KdsClient kdsClient; public KdsFhirClientStub(KdsClient kdsClient) diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java index 5b0ed75..63c2701 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java +++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java @@ -24,8 +24,6 @@ import org.hl7.fhir.r4.model.Task.TaskIntent; import org.hl7.fhir.r4.model.Task.TaskStatus; -import ca.uhn.fhir.context.FhirContext; - public class DataSendExampleStarter { public static void main(String[] args) throws Exception From 1678104d4d1ac0f5ab399d5e5bd8ed037b33d32b Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 18:43:49 +0100 Subject: [PATCH 02/25] download first attachment only, URL validation stub, improved logging --- .../data_transfer/service/ReadData.java | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java index 204eba8..2832816 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java @@ -119,28 +119,50 @@ private DocumentReference readDocumentReference(String projectIdentifier, String if (documentReferences.size() > 1) logger.warn( - "Found > 1 DocumentReferences ({}) for project-identifier='{}' referenced in task with id='{}', using only the first", - documentReferences.size(), projectIdentifier, taskId); + "Found {} DocumentReferences for project-identifier='{}' referenced in task with id='{}', using first ({})", + documentReferences.size(), projectIdentifier, taskId, + documentReferences.get(0).getIdElement().getValue()); return documentReferences.get(0); } private Binary readBinary(DocumentReference documentReference, String taskId) { - List binaries = Stream.of(documentReference).filter(DocumentReference::hasContent) - .flatMap(dr -> dr.getContent().stream()).map(c -> c.getAttachment().getUrl()).map(this::readBinary) - .collect(toList()); + List urls = Stream.of(documentReference).filter(DocumentReference::hasContent) + .flatMap(dr -> dr.getContent().stream()).map(c -> c.getAttachment().getUrl()).collect(toList()); - if (binaries.size() < 1) - throw new IllegalArgumentException("Could not find any Binary from DocumentReference with id='" + if (urls.size() < 1) + throw new IllegalArgumentException("Could not find any attachment URLs in DocumentReference with id='" + documentReference.getId() + "' belonging to task with id='" + taskId + "'"); - if (binaries.size() > 1) + if (urls.size() > 1) logger.warn( - "Found > 1 Binaries ({}) from DocumentReference with id='{}' belonging to task with id='{}', using only the first", - binaries.size(), documentReference.getId(), taskId); + "Found {} attachment URLs in DocumentReference with id='{}' belonging to task with id='{}', using first ({})", + urls.size(), documentReference.getId(), taskId, urls.get(0)); - return binaries.get(0); + if (!validBinaryUrl(urls.get(0))) + { + logger.warn( + "Attachment URL {} in DocumentReference with id='{}' belonging to task with id='{}', not a valid Binary reference," + + " should be a relative Binary reference or an absloute Binary reference to KDS FHIR server at {}", + urls.get(0), documentReference.getId(), taskId, kdsClientFactory.getKdsClient().getFhirBaseUrl()); + throw new IllegalArgumentException( + "Attachment URL " + urls.get(0) + " in DocumentReference with id='" + documentReference.getId() + + "' belonging to task with id='" + taskId + "' not a valid Binary reference"); + } + + return readBinary(urls.get(0)); + } + + private boolean validBinaryUrl(String url) + { + /* + * TODO implement URL validation. + * + * URL must be either relative Binary reference or, relative Binary reference with Base URL equal to KDS client + * base URL. + */ + return true; } private Binary readBinary(String url) From 9e3dd657bb317102919a954de7df0685b6a5e264 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 18:44:28 +0100 Subject: [PATCH 03/25] hex encoding from commons-codec, improved logging --- .../data_transfer/service/EncryptData.java | 42 +++++-------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java index ea8bc60..b5aa6c6 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.Objects; +import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; @@ -117,8 +118,8 @@ private DocumentReference getDocumentReference(Bundle bundle) "Could not find any DocumentReference in PublicKey Bundle with id='" + bundle.getId() + "'"); if (documentReferences.size() > 1) - logger.warn("Found > 1 DocumentReferences ({}) in PublicKey Bundle with id='{}'", documentReferences.size(), - bundle.getId()); + logger.warn("Found {} DocumentReferences in PublicKey Bundle with id='{}', using first", + documentReferences.size(), bundle.getId()); return documentReferences.get(0); } @@ -133,7 +134,8 @@ private Binary getBinary(Bundle bundle) "Could not find any Binary in PublicKey Bundle with id='" + bundle.getId() + "'"); if (binaries.size() > 1) - logger.warn("Found > 1 Binaries ({}) in PublicKey Bundle with id='{}'", binaries.size(), bundle.getId()); + logger.warn("Found {} Binaries in PublicKey Bundle with id='{}', using first", binaries.size(), + bundle.getId()); return binaries.get(0); } @@ -146,9 +148,9 @@ private PublicKey getPublicKey(Binary binary, String publicKeyBundleId) } catch (Exception exception) { - logger.info("Could not generate PublicKey from Binary in PublicKey Bundle with id='{}'", publicKeyBundleId); + logger.info("Could not read PublicKey from Binary in PublicKey Bundle with id='{}'", publicKeyBundleId); throw new RuntimeException( - "Could not generate PublicKey from Binary in PublicKey Bundle with id='" + publicKeyBundleId + "'", + "Could not read PublicKey from Binary in PublicKey Bundle with id='" + publicKeyBundleId + "'", exception); } } @@ -161,47 +163,25 @@ private void checkHash(DocumentReference documentReference, PublicKey publicKey, .map(Attachment::getHash).count(); if (numberOfHashes < 1) - { throw new RuntimeException( "Could not find any sha256-hash in DocumentReference from Bundle with id='" + bundleId + "'"); - } if (numberOfHashes > 1) - { - logger.warn("DocumentReference contains > 1 sha256-hashes ({}), using the first from Bundle with id='{}'", + logger.warn("DocumentReference contains {} sha256-hashes, using the first from Bundle with id='{}'", numberOfHashes, bundleId); - } byte[] documentReferenceHash = documentReference.getContentFirstRep().getAttachment().getHash(); byte[] publicKeyHash = DigestUtils.sha256(publicKey.getEncoded()); logger.debug("DocumentReference PublicKey sha256-hash='{}' from Bundle with id='{}'", - byteToHex(documentReferenceHash), bundleId); - logger.debug("PublicKey actual sha256-hash='{}' from Bundle with id='{}'", byteToHex(publicKeyHash), bundleId); + Hex.encodeHexString(documentReferenceHash), bundleId); + logger.debug("PublicKey actual sha256-hash='{}' from Bundle with id='{}'", Hex.encodeHexString(publicKeyHash), + bundleId); if (!Arrays.equals(documentReferenceHash, publicKeyHash)) - { throw new RuntimeException( "Sha256-hash in DocumentReference does not match computed sha256-hash of Binary in Bundle with id='" + bundleId + "'"); - } - } - - private String byteToHex(byte[] toConvert) - { - StringBuilder hexString = new StringBuilder(2 * toConvert.length); - - for (byte b : toConvert) - { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) - { - hexString.append('0'); - } - hexString.append(hex); - } - - return hexString.toString(); } private byte[] encrypt(PublicKey publicKey, Bundle bundle) From a06abc6b34dbbbebf7f44717d6dc7a5d5ec984e6 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 19:04:08 +0100 Subject: [PATCH 04/25] validation & bundle creation in separate service task, validation ToDos --- .../data_transfer/service/CreateBundle.java | 94 +++++++++++++++++++ .../service/ValidateDataCos.java | 7 ++ .../service/ValidateDataDic.java | 71 +++----------- .../src/main/resources/bpe/send.bpmn | 56 ++++++----- 4 files changed, 149 insertions(+), 79 deletions(-) create mode 100644 mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java new file mode 100644 index 0000000..5c5de68 --- /dev/null +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java @@ -0,0 +1,94 @@ +package de.medizininformatik_initiative.processes.projectathon.data_transfer.service; + +import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY; +import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET; +import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE; +import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER; +import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER; +import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER; +import static org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTION; +import static org.hl7.fhir.r4.model.DocumentReference.ReferredDocumentStatus.FINAL; +import static org.hl7.fhir.r4.model.Enumerations.DocumentReferenceStatus.CURRENT; + +import java.util.Objects; +import java.util.UUID; + +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; +import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper; +import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; +import org.highmed.dsf.fhir.organization.OrganizationProvider; +import org.highmed.dsf.fhir.task.TaskHelper; +import org.highmed.dsf.fhir.variables.FhirResourceValues; +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.DocumentReference; +import org.hl7.fhir.r4.model.ResourceType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; + +import ca.uhn.fhir.context.FhirContext; + +public class CreateBundle extends AbstractServiceDelegate implements InitializingBean +{ + private static final Logger logger = LoggerFactory.getLogger(CreateBundle.class); + + private final OrganizationProvider organizationProvider; + + public CreateBundle(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, + ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider) + { + super(clientProvider, taskHelper, readAccessHelper); + + this.organizationProvider = organizationProvider; + } + + @Override + public void afterPropertiesSet() throws Exception + { + super.afterPropertiesSet(); + + Objects.requireNonNull(organizationProvider, "organizationProvider"); + } + + @Override + protected void doExecute(DelegateExecution execution) + { + String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER); + DocumentReference documentReference = (DocumentReference) execution + .getVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE); + Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY); + + Bundle bundle = createTransactionBundle(projectIdentifier, documentReference, binary); + logger.debug("Created Bundle: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(bundle)); + + execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundle)); + } + + private Bundle createTransactionBundle(String projectIdentifier, DocumentReference documentReference, Binary binary) + { + Binary binaryToTransmit = new Binary().setContentType(binary.getContentType()); + binaryToTransmit.setContent(binary.getContent()); + binaryToTransmit.setId(UUID.randomUUID().toString()); + + DocumentReference documentReferenceToTransmit = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL); + documentReferenceToTransmit.getMasterIdentifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER) + .setValue(projectIdentifier); + documentReferenceToTransmit.addAuthor().setType(ResourceType.Organization.name()).getIdentifier() + .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER) + .setValue(organizationProvider.getLocalIdentifierValue()); + documentReferenceToTransmit.setDate(documentReference.getDate()); + documentReferenceToTransmit.addContent().getAttachment().setContentType(binary.getContentType()) + .setUrl("urn:uuid:" + binaryToTransmit.getId()); + + Bundle bundle = new Bundle().setType(TRANSACTION); + bundle.addEntry().setResource(documentReferenceToTransmit) + .setFullUrl("urn:uuid:" + documentReferenceToTransmit.getId()).getRequest() + .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.DocumentReference.name()); + bundle.addEntry().setResource(binaryToTransmit).setFullUrl("urn:uuid:" + binaryToTransmit.getId()).getRequest() + .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Binary.name()); + + return bundle; + } +} diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java index 1f3309a..468275b 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java @@ -79,5 +79,12 @@ protected void doExecute(DelegateExecution execution) { throw new RuntimeException("Bundle contains < 1 or > 1 of Binaries (" + countB + ")"); } + + /* + * TODO validate binary declared mime-type = text/csv, if possible validate actual mime-type of data for example + * using Apache Tika -> https://tika.apache.org/1.21/detection.html + * + * ...possible transfer of malicious binary data + */ } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java index 9cb0e3b..cd99f4b 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java @@ -1,17 +1,6 @@ package de.medizininformatik_initiative.processes.projectathon.data_transfer.service; -import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY; -import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DATA_SET; -import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE; -import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER; -import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.NAMINGSYSTEM_MII_PROJECT_IDENTIFIER; -import static org.highmed.dsf.bpe.ConstantsBase.NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER; -import static org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTION; -import static org.hl7.fhir.r4.model.DocumentReference.ReferredDocumentStatus.FINAL; -import static org.hl7.fhir.r4.model.Enumerations.DocumentReferenceStatus.CURRENT; - import java.util.Objects; -import java.util.UUID; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; @@ -19,21 +8,10 @@ import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; -import org.highmed.dsf.fhir.variables.FhirResourceValues; -import org.hl7.fhir.r4.model.Binary; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.DocumentReference; -import org.hl7.fhir.r4.model.ResourceType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -import ca.uhn.fhir.context.FhirContext; - public class ValidateDataDic extends AbstractServiceDelegate implements InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(ValidateDataDic.class); - private final OrganizationProvider organizationProvider; public ValidateDataDic(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, @@ -55,40 +33,19 @@ public void afterPropertiesSet() throws Exception @Override protected void doExecute(DelegateExecution execution) { - String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER); - DocumentReference documentReference = (DocumentReference) execution - .getVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE); - Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY); - - Bundle bundle = createTransactionBundle(projectIdentifier, documentReference, binary); - logger.debug("Created Bundle: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(bundle)); - - execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundle)); - } - - private Bundle createTransactionBundle(String projectIdentifier, DocumentReference documentReference, Binary binary) - { - Binary binaryToTransmit = new Binary().setContentType(binary.getContentType()); - binaryToTransmit.setContent(binary.getContent()); - binaryToTransmit.setId(UUID.randomUUID().toString()); - - DocumentReference documentReferenceToTransmit = new DocumentReference().setStatus(CURRENT).setDocStatus(FINAL); - documentReferenceToTransmit.getMasterIdentifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER) - .setValue(projectIdentifier); - documentReferenceToTransmit.addAuthor().setType(ResourceType.Organization.name()).getIdentifier() - .setSystem(NAMINGSYSTEM_HIGHMED_ORGANIZATION_IDENTIFIER) - .setValue(organizationProvider.getLocalIdentifierValue()); - documentReferenceToTransmit.setDate(documentReference.getDate()); - documentReferenceToTransmit.addContent().getAttachment().setContentType(binary.getContentType()) - .setUrl("urn:uuid:" + binaryToTransmit.getId()); - - Bundle bundle = new Bundle().setType(TRANSACTION); - bundle.addEntry().setResource(documentReferenceToTransmit) - .setFullUrl("urn:uuid:" + documentReferenceToTransmit.getId()).getRequest() - .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.DocumentReference.name()); - bundle.addEntry().setResource(binaryToTransmit).setFullUrl("urn:uuid:" + binaryToTransmit.getId()).getRequest() - .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Binary.name()); - - return bundle; + // String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER); + // DocumentReference documentReference = (DocumentReference) execution + // .getVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE); + // Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY); + // + // binary.getContentType(); + // binary.getData(); + + /* + * TODO validate declared mime-type = text/csv, if possible validate actual mime-type of data for example using + * Apache Tika -> https://tika.apache.org/1.21/detection.html + * + * ...possible transfer of malicious binary data + */ } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn index 7e0618c..7484c77 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/send.bpmn @@ -1,5 +1,5 @@ - + Flow_0kkjyst @@ -10,14 +10,14 @@ Flow_0yamo5r - + Flow_0yamo5r Flow_0zrvqk8 - Flow_0zrvqk8 + Flow_05qlnk4 Flow_15vmy2h @@ -62,34 +62,39 @@ Flow_1pzxejf Flow_0phc02z + + + Flow_0zrvqk8 + Flow_05qlnk4 + - - + + - - + + - - + + - - + + - - + + @@ -99,6 +104,10 @@ + + + + @@ -112,31 +121,34 @@ - + - + - + - + - + - + - + - + - + + + + From c6aaf9a6962f44706481251fc3b60a2e3672a480 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 19:37:17 +0100 Subject: [PATCH 05/25] recommendations (TODOs) for improving the annotation and doc generator --- .../documentation/generator/Documentation.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java index 268f8ad..e48419e 100644 --- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java +++ b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java @@ -7,12 +7,26 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) +/* + * TODO add default values to properties where possible or a typical default value exists (required = false, + * recommendation = null) + */ public @interface Documentation { + /* + * TODO remove, should be generated using @Value annotation, if needed add a boolean property to configure that a + * ..._PASSWORD_FILE env Variable is not supported (boolean filePropertySupported() default true;) + */ String environmentVariables(); boolean required(); + /* + * TODO change to String Array, default null -> all processes (Generator could use + * ProcessPluginDefinition#getBpmnFiles to parse BPMN file and find process names) + * + * Generator should validate process names against configured processes + */ String processNames(); String description(); From 7597c2d7e566be401c0ccb986936fc98d4f25dd9 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 19:57:29 +0100 Subject: [PATCH 06/25] recommendation to use meaningful AAD --- .../data_transfer/crypto/RsaAesGcmUtil.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java index db7beb1..b4c0aa4 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java @@ -24,11 +24,25 @@ public class RsaAesGcmUtil private static final String RSA_CIPHER = "RSA/ECB/PKCS1Padding"; private static final int RSA_KEY_LENGTH = 4096; private static final int ENCRYPTED_AES_KEY_LENGTH = 512; + /* + * TODO remove AAD constant. Since the sending Organization is known to the COS, we can use meaningful Additional + * Authentication Data (AAD). I would suggest using the DSF organization identifier of the sending organization + * instead of this static value. On the decryption end, the identifier could be extracted from the Task that started + * the receive process: Task.requester + * + * Additionally the receiving organizations identifier could be added as AAD. In general AAD does not improve + * security, but in our case it might guard against configuration errors, since the sending and receiving + * organizations would be pinned to the encrypted binary. It might be important to remind people that the data + * transfer is not secure because we are encrypting the Bundle before transferring it. The data transfer itself is + * secure by using TLS, but we want the data to stay secure in case a DICs DSF FHIR server gets hacked, before the + * Bundle is deleted. + */ /** * AAD: some random bytes */ private static final byte[] AAD = "JLCbSbIk5VAvBtKs4ypnDw3AJRfSBWXFHUxl78WBJw".getBytes(StandardCharsets.UTF_8); + // TODO add sending org identifier parameter and use as AAD public static byte[] encrypt(PublicKey publicKey, byte[] data) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, ShortBufferException @@ -48,6 +62,7 @@ public static byte[] encrypt(PublicKey publicKey, byte[] data) return output; } + // TODO add sending org identifier parameter and use as AAD public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted) throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException From a89b775d4b3e90435b0fd10914c1ba5322f57764 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 20:24:07 +0100 Subject: [PATCH 07/25] recommendation to use valueIdentifier instead of valueReference --- .../resources/fhir/Task/TaskStartDataSend_Demo.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml index a5c2365..1c69a9a 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml @@ -53,6 +53,19 @@ + From 181348be4409f9fc48eff1e0aca44bfebb19d429 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Sun, 20 Feb 2022 20:35:09 +0100 Subject: [PATCH 08/25] Recommendation to add the project identifier in the start receive Task and additional validation recommendations. --- .../data_transfer/message/StartReceiveProcess.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java index 84e40a4..8c211cb 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java @@ -26,6 +26,14 @@ public StartReceiveProcess(FhirWebserviceClientProvider clientProvider, TaskHelp super(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext); } + /* + * TODO we should send the http://medizininformatik-initiative.de/sid/project-identifier as an input parameter (Task + * profile would require modification). On the receiving end, the identifier should be validated against current + * active projects. Maybe check if an active ResearchStudy resource with the same project identifier exists. The + * ResearchStudy could also reference sending organizations, to not except data from every one. The ResearchStudy + * active and sending organization expected status should be checked as part of a validate Task before downloading + * the Binary step. + */ @Override protected Stream getAdditionalInputParameters(DelegateExecution execution) { From 21cd00e8a1c0e0b995c1eed9c9d1d6e8bd569275 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 09:45:14 +0100 Subject: [PATCH 09/25] use meaningful aad --- .../data_transfer/crypto/RsaAesGcmUtil.java | 38 +++++++------------ .../data_transfer/service/DecryptData.java | 28 ++++++++++++-- .../data_transfer/service/EncryptData.java | 17 +++++++-- .../spring/config/TransferDataConfig.java | 9 +++-- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java index b4c0aa4..b6d0aa0 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/RsaAesGcmUtil.java @@ -24,33 +24,17 @@ public class RsaAesGcmUtil private static final String RSA_CIPHER = "RSA/ECB/PKCS1Padding"; private static final int RSA_KEY_LENGTH = 4096; private static final int ENCRYPTED_AES_KEY_LENGTH = 512; - /* - * TODO remove AAD constant. Since the sending Organization is known to the COS, we can use meaningful Additional - * Authentication Data (AAD). I would suggest using the DSF organization identifier of the sending organization - * instead of this static value. On the decryption end, the identifier could be extracted from the Task that started - * the receive process: Task.requester - * - * Additionally the receiving organizations identifier could be added as AAD. In general AAD does not improve - * security, but in our case it might guard against configuration errors, since the sending and receiving - * organizations would be pinned to the encrypted binary. It might be important to remind people that the data - * transfer is not secure because we are encrypting the Bundle before transferring it. The data transfer itself is - * secure by using TLS, but we want the data to stay secure in case a DICs DSF FHIR server gets hacked, before the - * Bundle is deleted. - */ - /** - * AAD: some random bytes - */ - private static final byte[] AAD = "JLCbSbIk5VAvBtKs4ypnDw3AJRfSBWXFHUxl78WBJw".getBytes(StandardCharsets.UTF_8); - - // TODO add sending org identifier parameter and use as AAD - public static byte[] encrypt(PublicKey publicKey, byte[] data) + + public static byte[] encrypt(PublicKey publicKey, byte[] data, String sendingOrganizationIdentifier, + String receivingOrganizationIdentifier) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, ShortBufferException { SecretKey aesKey = AesGcmUtil.generateAES256Key(); + byte[] aad = getAad(sendingOrganizationIdentifier, receivingOrganizationIdentifier); byte[] encryptedAesKey = encryptRsa(aesKey, publicKey); - byte[] encryptedData = AesGcmUtil.encrypt(data, AAD, aesKey); + byte[] encryptedData = AesGcmUtil.encrypt(data, aad, aesKey); if (encryptedAesKey.length != ENCRYPTED_AES_KEY_LENGTH) throw new IllegalStateException("Encrypted AES key length = " + ENCRYPTED_AES_KEY_LENGTH + " expected"); @@ -62,8 +46,8 @@ public static byte[] encrypt(PublicKey publicKey, byte[] data) return output; } - // TODO add sending org identifier parameter and use as AAD - public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted) + public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted, String sendingOrganizationIdentifier, + String receivingOrganizationIdentifier) throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { @@ -72,9 +56,10 @@ public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted) System.arraycopy(encrypted, 0, encryptedAesKey, 0, ENCRYPTED_AES_KEY_LENGTH); System.arraycopy(encrypted, ENCRYPTED_AES_KEY_LENGTH, encryptedData, 0, encrypted.length - ENCRYPTED_AES_KEY_LENGTH); + byte[] aad = getAad(sendingOrganizationIdentifier, receivingOrganizationIdentifier); SecretKey key = decryptRsa(encryptedAesKey, privateKey); - return AesGcmUtil.decrypt(encryptedData, AAD, key); + return AesGcmUtil.decrypt(encryptedData, aad, key); } public static KeyPair generateRsa4096KeyPair() throws NoSuchAlgorithmException @@ -104,4 +89,9 @@ private static SecretKey decryptRsa(byte[] encryptedKey, PrivateKey privateKey) return new SecretKeySpec(decrypted, "AES"); } + + private static byte[] getAad(String sendingOrganizationIdentifier, String receivingOrganizationIdentifier) + { + return (sendingOrganizationIdentifier + "|" + receivingOrganizationIdentifier).getBytes(StandardCharsets.UTF_8); + } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java index 605819a..2032329 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java @@ -11,9 +11,11 @@ import org.highmed.dsf.bpe.delegate.AbstractServiceDelegate; import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; +import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.FhirResourceValues; import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -26,13 +28,15 @@ public class DecryptData extends AbstractServiceDelegate implements Initializing { private static final Logger logger = LoggerFactory.getLogger(DecryptData.class); + private final OrganizationProvider organizationProvider; private final KeyProvider keyProvider; public DecryptData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, - ReadAccessHelper readAccessHelper, KeyProvider keyProvider) + ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, KeyProvider keyProvider) { super(clientProvider, taskHelper, readAccessHelper); + this.organizationProvider = organizationProvider; this.keyProvider = keyProvider; } @@ -41,6 +45,7 @@ public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + Objects.requireNonNull(organizationProvider, "organizationProvider"); Objects.requireNonNull(keyProvider, "keyProvider"); } @@ -48,19 +53,34 @@ public void afterPropertiesSet() throws Exception protected void doExecute(DelegateExecution execution) { byte[] bundleEncrypted = (byte[]) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED); + String localOrganizationIdentifier = organizationProvider.getLocalIdentifierValue(); + String sendingOrganizationIdentifier = getSendingOrganizationIdentifier(); - Bundle bundleDecrypted = decryptBundle(keyProvider.getPrivateKey(), bundleEncrypted); + Bundle bundleDecrypted = decryptBundle(keyProvider.getPrivateKey(), bundleEncrypted, + sendingOrganizationIdentifier, localOrganizationIdentifier); logger.debug("Decrypted Bundle: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(bundleDecrypted)); execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundleDecrypted)); } - private Bundle decryptBundle(PrivateKey privateKey, byte[] bundleEncrypted) + private String getSendingOrganizationIdentifier() + { + Reference requester = getLeadingTaskFromExecutionVariables().getRequester(); + + if (requester.hasIdentifier() && requester.getIdentifier().hasValue()) + return requester.getIdentifier().getValue(); + else + throw new IllegalArgumentException("Task is missing requester identifier"); + } + + private Bundle decryptBundle(PrivateKey privateKey, byte[] bundleEncrypted, String sendingOrganizationIdentifier, + String receivingOrganizationIdentifier) { try { - byte[] bundleDecrypted = RsaAesGcmUtil.decrypt(privateKey, bundleEncrypted); + byte[] bundleDecrypted = RsaAesGcmUtil.decrypt(privateKey, bundleEncrypted, sendingOrganizationIdentifier, + receivingOrganizationIdentifier); String bundleString = new String(bundleDecrypted, StandardCharsets.UTF_8); return (Bundle) FhirContext.forR4().newXmlParser().parseResource(bundleString); } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java index b5aa6c6..877fafb 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java @@ -26,6 +26,7 @@ import org.highmed.dsf.fhir.authorization.read.ReadAccessHelper; import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.EndpointProvider; +import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.hl7.fhir.r4.model.Attachment; import org.hl7.fhir.r4.model.Binary; @@ -43,13 +44,16 @@ public class EncryptData extends AbstractServiceDelegate implements Initializing { private static final Logger logger = LoggerFactory.getLogger(EncryptData.class); + private final OrganizationProvider organizationProvider; private final EndpointProvider endpointProvider; public EncryptData(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, - ReadAccessHelper readAccessHelper, EndpointProvider endpointProvider) + ReadAccessHelper readAccessHelper, OrganizationProvider organizationProvider, + EndpointProvider endpointProvider) { super(clientProvider, taskHelper, readAccessHelper); + this.organizationProvider = organizationProvider; this.endpointProvider = endpointProvider; } @@ -58,6 +62,7 @@ public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + Objects.requireNonNull(organizationProvider, "organizationProvider"); Objects.requireNonNull(endpointProvider, "endpointProvider"); } @@ -66,10 +71,12 @@ protected void doExecute(DelegateExecution execution) { String coordinatingSiteIdentifier = (String) execution .getVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER); + String localOrganizationIdentifier = organizationProvider.getLocalIdentifierValue(); + Bundle toEncrypt = (Bundle) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET); PublicKey publicKey = readPublicKey(coordinatingSiteIdentifier); - byte[] encrypted = encrypt(publicKey, toEncrypt); + byte[] encrypted = encrypt(publicKey, toEncrypt, localOrganizationIdentifier, coordinatingSiteIdentifier); execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_ENCRYPTED, encrypted); } @@ -184,14 +191,16 @@ private void checkHash(DocumentReference documentReference, PublicKey publicKey, + bundleId + "'"); } - private byte[] encrypt(PublicKey publicKey, Bundle bundle) + private byte[] encrypt(PublicKey publicKey, Bundle bundle, String sendingOrganizationIdentifier, + String receivingOrganizationIdentifier) { try { byte[] toEncrypt = FhirContext.forR4().newXmlParser().encodeResourceToString(bundle) .getBytes(StandardCharsets.UTF_8); - return RsaAesGcmUtil.encrypt(publicKey, toEncrypt); + return RsaAesGcmUtil.encrypt(publicKey, toEncrypt, sendingOrganizationIdentifier, + receivingOrganizationIdentifier); } catch (Exception exception) { diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java index 6eb62bf..dea95bf 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java @@ -164,7 +164,7 @@ private Path checkExists(String file) } } - // miiProjectathonDataSend + // projectathonDataSend @Bean public ReadData readData() @@ -181,7 +181,8 @@ public ValidateDataDic validateDataDic() @Bean public EncryptData encryptData() { - return new EncryptData(fhirClientProvider, taskHelper, readAccessHelper, endpointProvider); + return new EncryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider, + endpointProvider); } @Bean @@ -203,7 +204,7 @@ public DeleteData deleteData() return new DeleteData(fhirClientProvider, taskHelper, readAccessHelper); } - // miiProjectathonDataReceive + // projectathonDataReceive @Bean public DownloadData downloadData() @@ -221,7 +222,7 @@ public KeyProvider keyProvider() @Bean public DecryptData decryptData() { - return new DecryptData(fhirClientProvider, taskHelper, readAccessHelper, keyProvider()); + return new DecryptData(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider, keyProvider()); } @Bean From 5a0d3aae42b6d8f9aef25f419fa647dbc0566135 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 10:04:23 +0100 Subject: [PATCH 10/25] add missing CreateBundle bean --- .../data_transfer/spring/config/TransferDataConfig.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java index dea95bf..874d94e 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java @@ -21,6 +21,7 @@ import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.KeyProvider; import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.KeyProviderImpl; import de.medizininformatik_initiative.processes.projectathon.data_transfer.message.StartReceiveProcess; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.CreateBundle; import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.DecryptData; import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.DeleteData; import de.medizininformatik_initiative.processes.projectathon.data_transfer.service.DownloadData; @@ -178,6 +179,12 @@ public ValidateDataDic validateDataDic() return new ValidateDataDic(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider); } + @Bean + public CreateBundle createBundle() + { + return new CreateBundle(fhirClientProvider, taskHelper, readAccessHelper, organizationProvider); + } + @Bean public EncryptData encryptData() { From 2bfc0f6e988b881a109928bca3e9b3cbc9ba7a4f Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 10:20:32 +0100 Subject: [PATCH 11/25] add url validation of binary resource --- .../data_transfer/service/ReadData.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java index 2832816..f0064bb 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java @@ -24,7 +24,9 @@ import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.DocumentReference; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResourceType; import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -144,7 +146,7 @@ private Binary readBinary(DocumentReference documentReference, String taskId) { logger.warn( "Attachment URL {} in DocumentReference with id='{}' belonging to task with id='{}', not a valid Binary reference," - + " should be a relative Binary reference or an absloute Binary reference to KDS FHIR server at {}", + + " should be a relative Binary reference or an absolute Binary reference to KDS FHIR server at {}", urls.get(0), documentReference.getId(), taskId, kdsClientFactory.getKdsClient().getFhirBaseUrl()); throw new IllegalArgumentException( "Attachment URL " + urls.get(0) + " in DocumentReference with id='" + documentReference.getId() @@ -156,13 +158,14 @@ private Binary readBinary(DocumentReference documentReference, String taskId) private boolean validBinaryUrl(String url) { - /* - * TODO implement URL validation. - * - * URL must be either relative Binary reference or, relative Binary reference with Base URL equal to KDS client - * base URL. - */ - return true; + IdType idType = new IdType(url); + String fhirBaseUrl = kdsClientFactory.getKdsClient().getFhirBaseUrl(); + + // expecting no Base URL or, Base URL equal to KDS client Base URL + boolean hasValidBaseUrl = !idType.hasBaseUrl() || fhirBaseUrl.equals(idType.getBaseUrl()); + boolean isBinaryReference = ResourceType.Binary.name().equals(idType.getResourceType()); + + return hasValidBaseUrl && isBinaryReference; } private Binary readBinary(String url) From b321f3943462bbc91d18ee842813f53530cbcd6d Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 10:59:22 +0100 Subject: [PATCH 12/25] use value[x].identifier instead of value[x].reference.identifier for project-identifier --- .../data_transfer/service/ReadData.java | 15 ++++++++------- .../mii-projectathon-task-start-data-send.xml | 16 ++++++++-------- .../bpe/start/DataSendExampleStarter.java | 4 +--- .../fhir/profile/TaskProfileTest.java | 4 +--- .../fhir/Task/TaskStartDataSend_Demo.xml | 18 +----------------- .../fhir/Task/TaskStartDataSend_NT-proBNP.xml | 7 ++----- .../fhir/Task/TaskStartDataSend_WE-STORM.xml | 7 ++----- 7 files changed, 23 insertions(+), 48 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java index f0064bb..f189148 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java @@ -25,7 +25,7 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.DocumentReference; import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.ResourceType; import org.hl7.fhir.r4.model.Task; import org.slf4j.Logger; @@ -81,12 +81,13 @@ protected void doExecute(DelegateExecution execution) private String getProjectIdentifier(Task task) { - List identifiers = getTaskHelper() - .getInputParameterReferenceValues(task, CODESYSTEM_MII_DATA_TRANSFER, - CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER) - .filter(Reference::hasIdentifier) - .filter(i -> NAMINGSYSTEM_MII_PROJECT_IDENTIFIER.equals(i.getIdentifier().getSystem())) - .map(i -> i.getIdentifier().getValue()).collect(toList()); + List identifiers = task.getInput().stream() + .filter(i -> i.getType().getCoding().stream() + .anyMatch(c -> CODESYSTEM_MII_DATA_TRANSFER.equals(c.getSystem()) + && CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER.equals(c.getCode()))) + .filter(i -> i.getValue() instanceof Identifier).map(i -> (Identifier) i.getValue()) + .filter(i -> NAMINGSYSTEM_MII_PROJECT_IDENTIFIER.equals(i.getSystem())).map(Identifier::getValue) + .collect(toList()); if (identifiers.size() < 1) throw new IllegalArgumentException("No project identifier present in task with id='" + task.getId() + "'"); diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml index b995cb1..4ce0a82 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml @@ -120,17 +120,17 @@ - - + - - - + + + + - - - + + + \ No newline at end of file diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java index 63c2701..3b4e7f8 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java +++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/bpe/start/DataSendExampleStarter.java @@ -58,9 +58,7 @@ private static Task createTask() .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER); task.addInput() - .setValue(new Reference().setIdentifier( - new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT")) - .setType(ResourceType.DocumentReference.name())) + .setValue(new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT")) .getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER) .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER); diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java index 595a631..5f9f263 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java +++ b/mii-dsf-process-projectathon-data-transfer/src/test/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/fhir/profile/TaskProfileTest.java @@ -113,9 +113,7 @@ private Task createValidTaskStartDataSend() .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_COORDINATING_SITE_IDENTIFIER); task.addInput() - .setValue(new Reference().setIdentifier( - new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT")) - .setType(ResourceType.DocumentReference.name())) + .setValue(new Identifier().setSystem(NAMINGSYSTEM_MII_PROJECT_IDENTIFIER).setValue("Test_PROJECT")) .getType().addCoding().setSystem(CODESYSTEM_MII_DATA_TRANSFER) .setCode(CODESYSTEM_MII_DATA_TRANSFER_VALUE_PROJECT_IDENTIFIER); diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml index 1c69a9a..420649b 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml @@ -53,25 +53,9 @@ - - - - - - + \ No newline at end of file diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml index 7c489c2..3c1d4ee 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_NT-proBNP.xml @@ -53,12 +53,9 @@ - - - + - - + \ No newline at end of file diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml index 4b633cd..6b86da1 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_WE-STORM.xml @@ -53,12 +53,9 @@ - - - + - - + \ No newline at end of file From efbfa22c740636f7c17739b25895f57090c3bfd5 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 13:57:59 +0100 Subject: [PATCH 13/25] validate mime-type of binary data --- .../pom.xml | 32 ++++++++-- .../data_transfer/service/ReadData.java | 6 +- .../service/ValidateDataCos.java | 16 ++--- .../service/ValidateDataDic.java | 29 +++++----- .../data_transfer/util/MimeTypeHelper.java | 58 +++++++++++++++++++ pom.xml | 20 ++++--- 6 files changed, 126 insertions(+), 35 deletions(-) create mode 100644 mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml index caabcb6..1acc081 100644 --- a/mii-dsf-process-projectathon-data-transfer/pom.xml +++ b/mii-dsf-process-projectathon-data-transfer/pom.xml @@ -1,6 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 mii-process-projectathon-data-transfer @@ -26,6 +26,11 @@ hapi-fhir-client provided + + org.apache.tika + tika-core + provided + de.medizininformatik-initiative @@ -67,8 +72,11 @@ -classpath - de.medizininformatik_initiative.processes.documentation.generator.DocumentationGenerator - de.medizininformatik_initiative.processes.projectathon.data_transfer.spring.config + + de.medizininformatik_initiative.processes.documentation.generator.DocumentationGenerator + + de.medizininformatik_initiative.processes.projectathon.data_transfer.spring.config + true compile @@ -97,7 +105,7 @@ - copy-hapi-fhir-client/dic + copy-dependencies/dic package copy @@ -109,6 +117,11 @@ hapi-fhir-client ${hapi.version} + + org.apache.tika + tika-core + ${apache.tika.version} + ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin @@ -131,7 +144,7 @@ - copy-hapi-fhir-client/cos + copy-dependencies/cos package copy @@ -143,6 +156,11 @@ hapi-fhir-client ${hapi.version} + + org.apache.tika + tika-core + ${apache.tika.version} + ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin @@ -165,6 +183,7 @@ ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin hapi-fhir-client-${hapi.version}.jar + tika-core-${apache.tika.version}.jar false @@ -179,6 +198,7 @@ ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin hapi-fhir-client-${hapi.version}.jar + tika-core-${apache.tika.version}.jar false diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java index f189148..baef93a 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java @@ -21,6 +21,7 @@ import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.highmed.dsf.fhir.variables.FhirResourceValues; +import org.hl7.fhir.r4.model.Attachment; import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.DocumentReference; @@ -132,7 +133,10 @@ private DocumentReference readDocumentReference(String projectIdentifier, String private Binary readBinary(DocumentReference documentReference, String taskId) { List urls = Stream.of(documentReference).filter(DocumentReference::hasContent) - .flatMap(dr -> dr.getContent().stream()).map(c -> c.getAttachment().getUrl()).collect(toList()); + .flatMap(dr -> dr.getContent().stream()) + .filter(DocumentReference.DocumentReferenceContentComponent::hasAttachment) + .map(DocumentReference.DocumentReferenceContentComponent::getAttachment).filter(Attachment::hasUrl) + .map(Attachment::getUrl).collect(toList()); if (urls.size() < 1) throw new IllegalArgumentException("Could not find any attachment URLs in DocumentReference with id='" diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java index 468275b..91edf38 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataCos.java @@ -20,6 +20,8 @@ import org.hl7.fhir.r4.model.Reference; import org.springframework.beans.factory.InitializingBean; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper; + public class ValidateDataCos extends AbstractServiceDelegate implements InitializingBean { public ValidateDataCos(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, @@ -74,17 +76,17 @@ protected void doExecute(DelegateExecution execution) throw new RuntimeException("DocumentReference contains < 1 or > 1 of projectIdentifiers (" + countMi + ")"); } - long countB = entries.stream().filter(e -> e.getResource() instanceof Binary).count(); + List binaries = entries.stream().map(Bundle.BundleEntryComponent::getResource) + .filter(r -> r instanceof Binary).map(r -> (Binary) r).collect(toList()); + + long countB = binaries.size(); if (countB != 1) { throw new RuntimeException("Bundle contains < 1 or > 1 of Binaries (" + countB + ")"); } - /* - * TODO validate binary declared mime-type = text/csv, if possible validate actual mime-type of data for example - * using Apache Tika -> https://tika.apache.org/1.21/detection.html - * - * ...possible transfer of malicious binary data - */ + byte[] dataB = binaries.get(0).getData(); + String mimeTypeB = binaries.get(0).getContentType(); + MimeTypeHelper.validate(dataB, mimeTypeB); } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java index cd99f4b..22f5a2c 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java @@ -1,5 +1,7 @@ package de.medizininformatik_initiative.processes.projectathon.data_transfer.service; +import static de.medizininformatik_initiative.processes.projectathon.data_transfer.ConstantsDataTransfer.BPMN_EXECUTION_VARIABLE_BINARY; + import java.util.Objects; import org.camunda.bpm.engine.delegate.DelegateExecution; @@ -8,10 +10,17 @@ import org.highmed.dsf.fhir.client.FhirWebserviceClientProvider; import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; +import org.hl7.fhir.r4.model.Binary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper; + public class ValidateDataDic extends AbstractServiceDelegate implements InitializingBean { + private static final Logger logger = LoggerFactory.getLogger(ValidateDataDic.class); + private final OrganizationProvider organizationProvider; public ValidateDataDic(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, @@ -33,19 +42,11 @@ public void afterPropertiesSet() throws Exception @Override protected void doExecute(DelegateExecution execution) { - // String projectIdentifier = (String) execution.getVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER); - // DocumentReference documentReference = (DocumentReference) execution - // .getVariable(BPMN_EXECUTION_VARIABLE_DOCUMENT_REFERENCE); - // Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY); - // - // binary.getContentType(); - // binary.getData(); - - /* - * TODO validate declared mime-type = text/csv, if possible validate actual mime-type of data for example using - * Apache Tika -> https://tika.apache.org/1.21/detection.html - * - * ...possible transfer of malicious binary data - */ + Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY); + + String mimeTypeBinary = binary.getContentType(); + byte[] dataBinary = binary.getData(); + + MimeTypeHelper.validate(dataBinary, mimeTypeBinary); } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java new file mode 100644 index 0000000..ed05573 --- /dev/null +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java @@ -0,0 +1,58 @@ +package de.medizininformatik_initiative.processes.projectathon.data_transfer.util; + +import org.apache.tika.config.TikaConfig; +import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.mime.MediaType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MimeTypeHelper +{ + private static final Logger logger = LoggerFactory.getLogger(MimeTypeHelper.class); + + /** + * Detects the mime-type of the provided data and validates if the detected mime-type equals the declared mime-type. + * Logs a warning if the full mime-types do not match, throws a {@link RuntimeException} if the base mime-types do + * not match. + * + * @param data + * of which the mime-type should be detected + * @param declared + * the declared mime-type of the data + * @throws RuntimeException + * if the detected and the declared base mime-type do not match + */ + public static void validate(byte[] data, String declared) + { + MediaType declaredMimeType = MediaType.parse(declared); + MediaType detectedMimeType = MediaType.EMPTY; + + try + { + TikaConfig tika = new TikaConfig(); + TikaInputStream input = TikaInputStream.get(data); + Metadata metadata = new Metadata(); + + // gives only a hint to the possible mime-type + // this needed because text/csv cannot be detected without any hint and would resolve to text/plain + metadata.add(Metadata.CONTENT_TYPE, declaredMimeType.toString()); + + detectedMimeType = tika.getDetector().detect(input, metadata); + } + catch (Exception exception) + { + throw new RuntimeException("Could not detect mime-type of binary", exception); + } + + if (!declaredMimeType.equals(detectedMimeType)) + logger.warn("Declared mime-type='{}' does not match detected mime-type='{}'", declaredMimeType.toString(), + detectedMimeType.toString()); + + if (!declaredMimeType.getType().equals(detectedMimeType.getType())) + { + throw new RuntimeException("Declared base mime-type of '" + declaredMimeType.toString() + + "' does not match detected base mime-type of '" + detectedMimeType.toString() + "'"); + } + } +} diff --git a/pom.xml b/pom.xml index 544a723..ff97086 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ ${project.basedir} 5.1.0 0.5.4 + 2.3.0 mii-dsf-processes @@ -104,12 +105,6 @@ ${hapi.version} - - org.reflections - reflections - 0.10.2 - - de.hs-heilbronn.mi @@ -129,6 +124,17 @@ 1.8.0-beta4 + + + org.apache.tika + tika-core + ${apache.tika.version} + + + org.reflections + reflections + 0.10.2 + com.fasterxml.jackson.core jackson-annotations @@ -185,7 +191,7 @@ - org.apache.maven.plugins From a2511326bc4b569fbad040cb09a4d5a7bdea19f1 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 14:07:52 +0100 Subject: [PATCH 14/25] renaming of task --- .../src/main/resources/bpe/receive.bpmn | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn index 9d6edbd..a89793b 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/bpe/receive.bpmn @@ -18,8 +18,8 @@ Flow_1w6vljw - - + + Flow_0j6v09z Flow_1w6vljw @@ -28,7 +28,7 @@ Flow_1c3t0x1 Flow_0j6v09z - + @@ -71,7 +71,7 @@ - + From 586ea027b1abc46778d038941a899a283bf99e2c Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 2 Mar 2022 21:32:07 +0100 Subject: [PATCH 15/25] fix typo --- .../projectathon/data_transfer/util/MimeTypeHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java index ed05573..123a5d2 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java @@ -35,7 +35,7 @@ public static void validate(byte[] data, String declared) Metadata metadata = new Metadata(); // gives only a hint to the possible mime-type - // this needed because text/csv cannot be detected without any hint and would resolve to text/plain + // this is needed because text/csv cannot be detected without any hint and would resolve to text/plain metadata.add(Metadata.CONTENT_TYPE, declaredMimeType.toString()); detectedMimeType = tika.getDetector().detect(input, metadata); From fba1ded21da85c5a310678b73fcd96a6127c7881 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Thu, 3 Mar 2022 10:58:12 +0100 Subject: [PATCH 16/25] improve documentation generator --- .../pom.xml | 4 +- .../spring/config/TransferDataConfig.java | 38 ++--- .../generator/Documentation.java | 38 +++-- .../generator/DocumentationGenerator.java | 144 +++++++++++++++--- 4 files changed, 166 insertions(+), 58 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml index 1acc081..21f78ea 100644 --- a/mii-dsf-process-projectathon-data-transfer/pom.xml +++ b/mii-dsf-process-projectathon-data-transfer/pom.xml @@ -75,10 +75,12 @@ de.medizininformatik_initiative.processes.documentation.generator.DocumentationGenerator - de.medizininformatik_initiative.processes.projectathon.data_transfer.spring.config + + de.medizininformatik_initiative.processes.projectathon.data_transfer true + true compile ${project.basedir} diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java index 874d94e..c6144ef 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java @@ -53,75 +53,77 @@ public class TransferDataConfig @Autowired private FhirContext fhirContext; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASE_URL", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = true, description = "The base address of the KDS FHIR server to read/store FHIR resources", recommendation = "None", example = "http://foo.bar/fhir") + @Documentation(required = true, description = "The base address of the KDS FHIR server to read/store FHIR resources", recommendation = "None", example = "http://foo.bar/fhir") @Value("${de.medizininformatik.initiative.kds.fhir.server.base.url:#{null}}") private String fhirStoreBaseUrl; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_CLIENT", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Client implementation used to connect to the KDS FHIR server in order to read/store FHIR resources", recommendation = "Use default value", example = "None") + @Documentation(description = "Client implementation used to connect to the KDS FHIR server in order to read/store FHIR resources", recommendation = "Use default value", example = "None") @Value("${de.medizininformatik.initiative.kds.fhir.server.client:de.medizininformatik_initiative.processes.projectathon.data_transfer.client.fhir.KdsFhirClientImpl}") private String fhirStoreClientClass; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TRUST_CERTIFICATES", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "PEM encoded file with one or more trusted root certificate to validate the KDS FHIR server certificate when connecting via https", recommendation = "Use docker secret file to configure", example = "/run/secrets/hospital_ca.pem") + @Documentation(description = "PEM encoded file with one or more trusted root certificate to validate the KDS FHIR server certificate when connecting via https", recommendation = "Use docker secret file to configure", example = "/run/secrets/hospital_ca.pem") @Value("${de.medizininformatik.initiative.kds.fhir.server.trust.certificates:#{null}}") private String fhirStoreTrustStore; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_CERTIFICATE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "PEM encoded file with client-certificate, if KDS FHIR server requires mutual TLS authentication", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_client_certificate.pem") + @Documentation(description = "PEM encoded file with client-certificate, if KDS FHIR server requires mutual TLS authentication", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_client_certificate.pem") @Value("${de.medizininformatik.initiative.kds.fhir.server.certificate:#{null}}") private String fhirStoreCertificate; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Private key corresponding to the KDS FHIR server client-certificate as PEM encoded file. Use *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD* or *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_private_key.pem") + @Documentation(description = "Private key corresponding to the KDS FHIR server client-certificate as PEM encoded file. Use *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD* or *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE* if private key is encrypted", recommendation = "Use docker secret file to configure", example = "/run/secrets/kds_server_private_key.pem") @Value("${de.medizininformatik.initiative.kds.fhir.server.private.key:#{null}}") private String fhirStorePrivateKey; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD or DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Password to decrypt the KDS FHIR server client-certificate encrypted private key", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_private_key.pem.password") + @Documentation(filePropertySupported = true, description = "Password to decrypt the KDS FHIR server client-certificate encrypted private key", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PRIVATE_KEY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_private_key.pem.password") @Value("${de.medizininformatik.initiative.kds.fhir.server.private.key.password:#{null}}") private char[] fhirStorePrivateKeyPassword; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_USERNAME", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Basic authentication username, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "None", example = "None") + @Documentation(description = "Basic authentication username, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "None", example = "None") @Value("${de.medizininformatik.initiative.kds.fhir.server.basicauth.username:#{null}}") private String fhirStoreUsername; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD or DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD_FILE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Basic authentication password, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_basicauth.password") + @Documentation(filePropertySupported = true, description = "Basic authentication password, set if the server containing the FHIR KDS data requests authentication using basic auth", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BASICAUTH_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "/run/secrets/kds_server_basicauth.password") @Value("${de.medizininformatik.initiative.kds.fhir.server.basicauth.password:#{null}}") private String fhirStorePassword; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_BEARER_TOKEN", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Bearer token for authentication, set if the server containing the FHIR KDS data requests authentication using a bearer token, cannot be set using docker secrets", recommendation = "None", example = "None") + @Documentation(description = "Bearer token for authentication, set if the server containing the FHIR KDS data requests authentication using a bearer token, cannot be set using docker secrets", recommendation = "None", example = "None") @Value("${de.medizininformatik.initiative.kds.fhir.server.bearer.token:#{null}}") private String fhirStoreBearerToken; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TIMEOUT_CONNECT", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "The timeout in milliseconds until a connection is established between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value") + @Documentation(description = "The timeout in milliseconds until a connection is established between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value") @Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.connect:10000}") private int fhirStoreConnectTimeout; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TIMEOUT_CONNECTION_REQUEST", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "The timeout in milliseconds used when requesting a connection from the connection manager between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value") + @Documentation(description = "The timeout in milliseconds used when requesting a connection from the connection manager between the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value") @Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.connection.request:10000}") private int fhirStoreConnectionRequestTimeout; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_TIMEOUT_SOCKET", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Maximum period of inactivity in milliseconds between two consecutive data packets of the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value") + @Documentation(description = "Maximum period of inactivity in milliseconds between two consecutive data packets of the KDS client and the KDS FHIR server", recommendation = "Change default value only if timeout exceptions occur", example = "See default value") @Value("${de.medizininformatik.initiative.kds.fhir.server.timeout.socket:10000}") private int fhirStoreSocketTimeout; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_CLIENT_VERBOSE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "The KDS client will log additional debug output", recommendation = "Change default value only if exceptions occur", example = "See default value") + @Documentation(description = "The KDS client will log additional debug output", recommendation = "Change default value only if exceptions occur", example = "See default value") @Value("${de.medizininformatik.initiative.kds.fhir.server.client.verbose:false}") private boolean fhirStoreHapiClientVerbose; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_URL", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Proxy location, set if the server containing the FHIR KDS data can only be reached through a proxy", recommendation = "None", example = "http://proxy.foo:8080") + @Documentation(description = "Proxy location, set if the server containing the FHIR KDS data can only be reached through a proxy", recommendation = "None", example = "http://proxy.foo:8080") @Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.url:#{null}}") private String fhirStoreProxyUrl; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_USERNAME", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Proxy username, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "None", example = "None") + @Documentation(description = "Proxy username, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "None", example = "None") @Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.username:#{null}}") private String fhirStoreProxyUsername; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD or DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD_FILE", processNames = "medizininformatik-initiativede_dataSend/, medizininformatik-initiativede_dataReceive/", required = false, description = "Proxy password, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "None") + @Documentation(filePropertySupported = true, description = "Proxy password, set if the server containing the FHIR KDS data can only be reached through a proxy which requests authentication", recommendation = "Use docker secret file to configure by using *DE_MEDIZININFORMATIK_INITIATIVE_KDS_FHIR_SERVER_PROXY_PASSWORD_FILE*. **Caution!** Editors like nano will add a `LF` (hex `0A`) character at the end of the last line. Make sure that the password file does not end with the `LF` character. For example by starting nano with `nano -L file.password`. If you want to check that the file does not end with an `LF` (hex `0A`) character, use `xxd file.password` to look at a hexdump.", example = "None") @Value("${de.medizininformatik.initiative.kds.fhir.server.proxy.password:#{null}}") private String fhirStoreProxyPassword; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_COS_PRIVATE_KEY", processNames = "medizininformatik-initiativede_dataReceive/", required = true, description = "Location of the COS private-key as 4096 Bit RSA PEM encoded, not encrypted file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_private_key.pem") + @Documentation(required = true, processNames = { + "medizininformatik-initiativede_dataReceive" }, description = "Location of the COS private-key as 4096 Bit RSA PEM encoded, not encrypted file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_private_key.pem") @Value("${de.medizininformatik.initiative.cos.private.key:#{null}}") private String cosPrivateKeyFile; - @Documentation(environmentVariables = "DE_MEDIZININFORMATIK_INITIATIVE_COS_PUBLIC_KEY", processNames = "medizininformatik-initiativede_dataReceive/", required = true, description = "Location of the COS public-key as 4096 Bit RSA PEM encoded file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_public_key.pem") + @Documentation(required = true, processNames = { + "medizininformatik-initiativede_dataReceive" }, description = "Location of the COS public-key as 4096 Bit RSA PEM encoded file", recommendation = "Use docker secret file to configure", example = "/run/secrets/cos_public_key.pem") @Value("${de.medizininformatik.initiative.cos.public.key:#{null}}") private String cosPublicKeyFile; diff --git a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java index e48419e..d4e8b78 100644 --- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java +++ b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/Documentation.java @@ -7,31 +7,39 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) -/* - * TODO add default values to properties where possible or a typical default value exists (required = false, - * recommendation = null) - */ public @interface Documentation { - /* - * TODO remove, should be generated using @Value annotation, if needed add a boolean property to configure that a - * ..._PASSWORD_FILE env Variable is not supported (boolean filePropertySupported() default true;) + /** + * @return true if this property is required for processes that are listed in + * {@link Documentation#processNames} */ - String environmentVariables(); + boolean required() default false; - boolean required(); + /** + * @return true if a docker secret file can be used to configure this property, else + * false, which means that a docker secret file cannot be used to configure this + * property + */ + boolean filePropertySupported() default false; - /* - * TODO change to String Array, default null -> all processes (Generator could use - * ProcessPluginDefinition#getBpmnFiles to parse BPMN file and find process names) - * - * Generator should validate process names against configured processes + /** + * @return an empty array if all processes use this property or an array of length >=1 containing only specific + * processes that use this property, but not all */ - String processNames(); + String[] processNames() default {}; + /** + * @return description helping to configure this property + */ String description(); + /** + * @return example value helping to configure this property + */ String example(); + /** + * @return recommendation helping to configure this property + */ String recommendation(); } diff --git a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java index e231877..06dc7f0 100644 --- a/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java +++ b/mii-dsf-processes-documentation-generator/src/main/java/de/medizininformatik_initiative/processes/documentation/generator/DocumentationGenerator.java @@ -1,15 +1,22 @@ package de.medizininformatik_initiative.processes.documentation.generator; +import static java.util.stream.Collectors.toList; + import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; -import java.lang.annotation.Annotation; +import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; +import org.camunda.bpm.model.bpmn.Bpmn; +import org.camunda.bpm.model.bpmn.instance.BaseElement; +import org.camunda.bpm.model.bpmn.instance.Process; +import org.highmed.dsf.bpe.ProcessPluginDefinition; import org.reflections.Reflections; import org.reflections.scanners.Scanners; import org.reflections.util.ClasspathHelper; @@ -32,57 +39,146 @@ public void execute(String[] args) Arrays.asList(args).forEach(this::generateDocumentation); } - private void generateDocumentation(String configDirectory) + private void generateDocumentation(String workingPackage) { - String filename = "target/Documentation_" + configDirectory + ".md"; - logger.info("Generating documentation for directory: {} in file: {}", configDirectory, filename); + String filename = "target/Documentation_" + workingPackage + ".md"; + logger.info("Generating documentation for package {} in file {}", workingPackage, filename); + + Reflections reflections = createReflections(workingPackage); + + List pluginProcessNames = getPluginProcessNames(reflections, workingPackage); + List fields = getFields(reflections); - Reflections reflections = createReflections(configDirectory); - List fields = getFields(reflections, Documentation.class); - writeFields(fields, filename, configDirectory); + writeFields(fields, pluginProcessNames, filename, workingPackage); } - private Reflections createReflections(String configDirectory) + private Reflections createReflections(String workingPackage) { ConfigurationBuilder configurationBuilder = new ConfigurationBuilder() - .setUrls(ClasspathHelper.forPackage(configDirectory)).setScanners(Scanners.FieldsAnnotated); + .setUrls(ClasspathHelper.forPackage(workingPackage)) + .setScanners(Scanners.FieldsAnnotated, Scanners.SubTypes); return new Reflections(configurationBuilder); } - private List getFields(Reflections reflections, Class annotation) + private List getPluginProcessNames(Reflections reflections, String workingPackage) + { + List> pluginDefinitionClasses = new ArrayList<>( + reflections.getSubTypesOf(ProcessPluginDefinition.class)); + + if (pluginDefinitionClasses.size() < 1) + { + logger.warn("No ProcessPluginDefinitions found in package {}", workingPackage); + return Collections.emptyList(); + } + + if (pluginDefinitionClasses.size() > 1) + logger.warn("Found {} ProcessPluginDefinitions ({}) in package {}, using only the first", + pluginDefinitionClasses.size(), pluginDefinitionClasses, workingPackage); + + try + { + ProcessPluginDefinition processPluginDefinition = pluginDefinitionClasses.get(0).getConstructor() + .newInstance(); + + return processPluginDefinition.getBpmnFiles().map(this::getProcessName).filter(Optional::isPresent) + .map(Optional::get).collect(toList()); + } + catch (Exception exception) + { + logger.warn( + "Could not read process names from package {} and ProcessPluginDefinition with name {}, reason is '{}'", + workingPackage, pluginDefinitionClasses.get(0).getName(), exception.getMessage()); + return Collections.emptyList(); + } + } + + private Optional getProcessName(String bpmnFile) + { + try + { + InputStream resource = getClass().getClassLoader().getResource(bpmnFile).openStream(); + return Bpmn.readModelFromStream(resource).getModelElementsByType(Process.class).stream() + .map(BaseElement::getId).findFirst(); + } + catch (Exception exception) + { + logger.warn("Could not read process name from resource file {}, reason is '{}'", bpmnFile, + exception.getMessage()); + return Optional.empty(); + } + } + + private List getFields(Reflections reflections) { - List fields = new ArrayList<>(reflections.getFieldsAnnotatedWith(annotation)); + List fields = new ArrayList<>(reflections.getFieldsAnnotatedWith(Documentation.class)); Collections.reverse(fields); return fields; } - private void writeFields(List fields, String filename, String configDirectory) + private void writeFields(List fields, List pluginProcessNames, String filename, + String workingPackage) { try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) { - fields.stream().map(this::createDocumentation).forEach(d -> write(writer, filename, d)); + fields.stream().map(field -> createDocumentation(field, pluginProcessNames)) + .forEach(d -> write(writer, filename, d)); } - catch (IOException e) + catch (Exception exception) { - logger.warn("Could not generate documentation for directory: {}, reason: {}", configDirectory, - e.getMessage()); + logger.warn("Could not generate documentation for package {}, reason is '{}'", workingPackage, + exception.getMessage()); } } - private String createDocumentation(Field field) + private String createDocumentation(Field field, List pluginProcessNames) { Documentation documentation = field.getAnnotation(Documentation.class); Value value = field.getAnnotation(Value.class); String[] valueSplit = value.value().replaceAll("\\$", "").replace("#", "").replace("{", "").replace("}", "") .split(":"); + String property = valueSplit[0]; + + String environment = property.replace(".", "_").toUpperCase(); + if (documentation.filePropertySupported()) + environment = String.format("%s or %s_FILE", environment, environment); + + boolean required = documentation.required(); + + String[] documentationProcessNames = documentation.processNames(); + String processesNamesAsString = getProcessNamesAsString(documentationProcessNames, pluginProcessNames); + + String description = documentation.description(); + String example = documentation.example(); + String recommendation = documentation.recommendation(); + + String defaultValue = (valueSplit.length == 2 && !"null".equals(valueSplit[1])) ? valueSplit[1] + : "not set by default"; + + return String.format("### %s\n- **Property:** %s\n- **Required:** %s\n- **Processes:** %s\n" + + "- **Description:** %s\n- **Example:** %s\n- **Recommendation:** %s\n" + "- **Default:** %s\n\n", + environment, property, required, processesNamesAsString, description, example, recommendation, + defaultValue); + } + + private String getProcessNamesAsString(String[] documentationProcessNames, List pluginProcessNames) + { + if (pluginProcessNames.size() == 0) + return "Could not read process names from ProcessPluginDefinition"; + + if (documentationProcessNames.length == 0) + return String.join(", ", pluginProcessNames); + + for (String documentationProcessName : documentationProcessNames) + { + if (!pluginProcessNames.contains(documentationProcessName)) + logger.warn( + "Documentation contains process with name '{}' which" + + " is not part of the processes {} defined in the ProcessPluginDefinition", + documentationProcessName, pluginProcessNames); + } - return String.format( - "### %s\n- **Property:** %s\n- **Required:** %s\n- **Processes:** %s\n- **Description:** %s\n- **Example:** %s\n- **Recommendation:** %s\n- **Default:** %s\n\n", - documentation.environmentVariables(), valueSplit[0], documentation.required(), - documentation.processNames(), documentation.description(), documentation.example(), - documentation.recommendation(), - (valueSplit.length == 2 && !"null".equals(valueSplit[1])) ? valueSplit[1] : "not set by default"); + return String.join(", ", documentationProcessNames); } private void write(BufferedWriter writer, String filename, String string) @@ -93,7 +189,7 @@ private void write(BufferedWriter writer, String filename, String string) } catch (IOException e) { - logger.warn("Writing the following string to file {} failed: \n {} reason: {}", filename, string, + logger.warn("Writing the following string to file {} failed: \n {} reason is '{}'", filename, string, e.getMessage()); } } From 1808ff679fe216ecc8205e0417f49e3ae0b23c90 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Thu, 3 Mar 2022 11:06:43 +0100 Subject: [PATCH 17/25] remove todo, improve logging --- .../data_transfer/message/StartReceiveProcess.java | 10 +--------- .../data_transfer/util/MimeTypeHelper.java | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java index 8c211cb..b94a8cf 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/message/StartReceiveProcess.java @@ -26,14 +26,6 @@ public StartReceiveProcess(FhirWebserviceClientProvider clientProvider, TaskHelp super(clientProvider, taskHelper, readAccessHelper, organizationProvider, fhirContext); } - /* - * TODO we should send the http://medizininformatik-initiative.de/sid/project-identifier as an input parameter (Task - * profile would require modification). On the receiving end, the identifier should be validated against current - * active projects. Maybe check if an active ResearchStudy resource with the same project identifier exists. The - * ResearchStudy could also reference sending organizations, to not except data from every one. The ResearchStudy - * active and sending organization expected status should be checked as part of a validate Task before downloading - * the Binary step. - */ @Override protected Stream getAdditionalInputParameters(DelegateExecution execution) { @@ -46,4 +38,4 @@ protected Stream getAdditionalInputParameters(DelegateExecut return Stream.of(parameterComponent); } -} +} \ No newline at end of file diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java index 123a5d2..432568f 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/MimeTypeHelper.java @@ -46,7 +46,7 @@ public static void validate(byte[] data, String declared) } if (!declaredMimeType.equals(detectedMimeType)) - logger.warn("Declared mime-type='{}' does not match detected mime-type='{}'", declaredMimeType.toString(), + logger.warn("Declared mime-type {} does not match detected mime-type {}", declaredMimeType.toString(), detectedMimeType.toString()); if (!declaredMimeType.getType().equals(detectedMimeType.getType())) From fc01149f030c68f5ed0fc6a3cae7a55bc6978653 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Thu, 3 Mar 2022 11:22:33 +0100 Subject: [PATCH 18/25] allow manual dispatch --- .github/workflows/maven-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 7a482c8..868f86b 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -4,6 +4,7 @@ name: Java CI Publish with Maven on: + workflow_dispatch: pull_request: types: [closed] branches: [develop] From 3103c46cb71d80cefeda831ddc229283e86474c4 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Mon, 7 Mar 2022 14:48:40 +0100 Subject: [PATCH 19/25] load apache tika via process folder and not plugin folder --- .gitignore | 1 + .../pom.xml | 50 +++++++++++-------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 4a453fc..dc6110c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ mii-dsf-processes-docker-test-setup/**/bpe/log/*.log.gz mii-dsf-processes-docker-test-setup/**/bpe/last_event/time.file mii-dsf-processes-docker-test-setup/**/bpe/plugin/*.jar mii-dsf-processes-docker-test-setup/**/bpe/process/*.jar +mii-dsf-processes-docker-test-setup/**/bpe/process/**/*.jar mii-dsf-processes-docker-test-setup/**/fhir/conf/bundle.xml mii-dsf-processes-docker-test-setup/**/fhir/log/*.log diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml index 21f78ea..7f2082a 100644 --- a/mii-dsf-process-projectathon-data-transfer/pom.xml +++ b/mii-dsf-process-projectathon-data-transfer/pom.xml @@ -102,8 +102,15 @@ ${project.artifactId} ${project.version} + + org.apache.tika + tika-core + ${apache.tika.version} + - ../mii-dsf-processes-docker-test-setup/dic/bpe/process + + ../mii-dsf-processes-docker-test-setup/dic/bpe/process/${project.artifactId}-${project.version} + @@ -119,11 +126,6 @@ hapi-fhir-client ${hapi.version} - - org.apache.tika - tika-core - ${apache.tika.version} - ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin @@ -141,8 +143,15 @@ ${project.artifactId} ${project.version} + + org.apache.tika + tika-core + ${apache.tika.version} + - ../mii-dsf-processes-docker-test-setup/cos/bpe/process + + ../mii-dsf-processes-docker-test-setup/cos/bpe/process/${project.artifactId}-${project.version} + @@ -158,11 +167,6 @@ hapi-fhir-client ${hapi.version} - - org.apache.tika - tika-core - ${apache.tika.version} - ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin @@ -175,32 +179,38 @@ - ../mii-dsf-processes-docker-test-setup/dic/bpe/process + + ../mii-dsf-processes-docker-test-setup/dic/bpe/process/${project.artifactId}-${project.version} + - ${project.artifactId}-${project.version}.jar + ** false - ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin + + ../mii-dsf-processes-docker-test-setup/dic/bpe/plugin + hapi-fhir-client-${hapi.version}.jar - tika-core-${apache.tika.version}.jar false - ../mii-dsf-processes-docker-test-setup/cos/bpe/process + + ../mii-dsf-processes-docker-test-setup/cos/bpe/process/${project.artifactId}-${project.version} + - ${project.artifactId}-${project.version}.jar + ** false - ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin + + ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin + hapi-fhir-client-${hapi.version}.jar - tika-core-${apache.tika.version}.jar false From ac7ccb1c4854f29c3d2244fa754ce42ff627a158 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Mon, 7 Mar 2022 17:13:02 +0100 Subject: [PATCH 20/25] remove not needed logger --- .../projectathon/data_transfer/service/ValidateDataDic.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java index 22f5a2c..eab4184 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ValidateDataDic.java @@ -11,16 +11,12 @@ import org.highmed.dsf.fhir.organization.OrganizationProvider; import org.highmed.dsf.fhir.task.TaskHelper; import org.hl7.fhir.r4.model.Binary; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.MimeTypeHelper; public class ValidateDataDic extends AbstractServiceDelegate implements InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(ValidateDataDic.class); - private final OrganizationProvider organizationProvider; public ValidateDataDic(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, From d07b1f515bac53d4a08098c675697ee8465274cf Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Tue, 8 Mar 2022 14:09:23 +0100 Subject: [PATCH 21/25] adds zip assembly of process data-transfer --- .../pom.xml | 36 +++++++++++++++++++ pom.xml | 5 +++ src/assembly/zip.xml | 26 ++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/assembly/zip.xml diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml index 7f2082a..e9aa48e 100644 --- a/mii-dsf-process-projectathon-data-transfer/pom.xml +++ b/mii-dsf-process-projectathon-data-transfer/pom.xml @@ -171,6 +171,23 @@ ../mii-dsf-processes-docker-test-setup/cos/bpe/plugin + + copy-dependencies/assembly + package + + copy + + + + + org.apache.tika + tika-core + ${apache.tika.version} + + + ${project.build.directory}/lib + + @@ -217,6 +234,25 @@ + + org.apache.maven.plugins + maven-assembly-plugin + + + zip-assembly + install + + single + + + + + false + + src/assembly/zip.xml + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index ff97086..4fa7d4d 100644 --- a/pom.xml +++ b/pom.xml @@ -193,6 +193,11 @@ + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + org.apache.maven.plugins maven-dependency-plugin diff --git a/src/assembly/zip.xml b/src/assembly/zip.xml new file mode 100644 index 0000000..d5ad227 --- /dev/null +++ b/src/assembly/zip.xml @@ -0,0 +1,26 @@ + + + zip + + zip + + + + + ${project.build.directory} + + + *.jar + + + + ${project.build.directory}/lib + + + *.jar + + + + \ No newline at end of file From 7c427973081136bd88e6c24f78f93d1c9ec229f9 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Tue, 8 Mar 2022 15:29:11 +0100 Subject: [PATCH 22/25] improve logging, fix typos --- .../client/KdsClientFactory.java | 4 +- .../data_transfer/crypto/KeyProviderImpl.java | 16 +++--- .../data_transfer/service/CreateBundle.java | 9 ++-- .../data_transfer/service/DecryptData.java | 10 ++-- .../data_transfer/service/DeleteData.java | 3 +- .../data_transfer/service/DownloadData.java | 7 ++- .../data_transfer/service/EncryptData.java | 5 +- .../data_transfer/service/ReadData.java | 10 ++-- .../data_transfer/service/StoreData.java | 5 +- .../spring/config/TransferDataConfig.java | 7 ++- .../data_transfer/util/LoggingHelper.java | 50 +++++++++++++++++++ 11 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java index e779d66..e3b96b6 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/client/KdsClientFactory.java @@ -90,8 +90,8 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event) try { logger.info( - "Testing connection to projectathon FHIR server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {}," - + " basicAuthUsername {}, basicAuthPassword {}, bearerToken {}, serverBase: {}, proxyUrl {}, proxyUsername, proxyPassword {}}", + "Testing connection to KDS FHIR server with {trustStorePath: {}, certificatePath: {}, privateKeyPath: {}, privateKeyPassword: {}," + + " basicAuthUsername {}, basicAuthPassword {}, bearerToken {}, serverBase: {}, proxyUrl {}, proxyUsername {}, proxyPassword {}}", trustStorePath, certificatePath, privateKeyPath, privateKeyPassword != null ? "***" : "null", kdsServerBasicAuthUsername, kdsServerBasicAuthPassword != null ? "***" : "null", kdsServerBearerToken != null ? "***" : "null", kdsServerBase, proxyUrl, proxyUsername, diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java index ec0c05d..5a72db2 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/crypto/KeyProviderImpl.java @@ -37,7 +37,7 @@ import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; -import ca.uhn.fhir.context.FhirContext; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper; import de.rwh.utils.crypto.io.PemIo; public class KeyProviderImpl implements KeyProvider, InitializingBean @@ -152,17 +152,16 @@ public void onContextRefreshedEvent(ContextRefreshedEvent event) else if (output.getTotal() == 0) { logger.info("Creating new PublicKey Bundle on DSF FHIR server..."); - Bundle bundleToCreate = getPublicKeyBundle(); + Bundle bundleToCreate = createPublicKeyBundle(); bundleOnServer = clientProvider.getLocalWebserviceClient().createConditionaly(bundleToCreate, "identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY + "|" + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY); } else { - logger.warn("Exist > 1 Bundle with identifier={}|{}", CODESYSTEM_MII_CRYPTOGRAPHY, - CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY); - throw new RuntimeException("Exist > 1 Bundle with identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY + "|" - + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY); + throw new RuntimeException( + "Exist " + output.getTotal() + " Bundle with identifier=" + CODESYSTEM_MII_CRYPTOGRAPHY + + "|" + CODESYSTEM_MII_CRYPTOGRAPHY_VALUE_PUBLIC_KEY + ", expected only one"); } logger.info("PublicKey Bundle has id='{}'", bundleOnServer.getId()); @@ -175,7 +174,7 @@ else if (output.getTotal() == 0) } } - private Bundle getPublicKeyBundle() + private Bundle createPublicKeyBundle() { Date date = new Date(); @@ -202,8 +201,7 @@ private Bundle getPublicKeyBundle() readAccessHelper.addAll(bundle); - logger.debug("Created Bundle: {}", - FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle)); + LoggingHelper.logDebugBundle("Created Bundle", bundle); return bundle; } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java index 5c5de68..a19e4ee 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/CreateBundle.java @@ -24,16 +24,12 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.DocumentReference; import org.hl7.fhir.r4.model.ResourceType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; -import ca.uhn.fhir.context.FhirContext; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper; public class CreateBundle extends AbstractServiceDelegate implements InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(CreateBundle.class); - private final OrganizationProvider organizationProvider; public CreateBundle(FhirWebserviceClientProvider clientProvider, TaskHelper taskHelper, @@ -61,7 +57,8 @@ protected void doExecute(DelegateExecution execution) Binary binary = (Binary) execution.getVariable(BPMN_EXECUTION_VARIABLE_BINARY); Bundle bundle = createTransactionBundle(projectIdentifier, documentReference, binary); - logger.debug("Created Bundle: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(bundle)); + + LoggingHelper.logDebugBundle("Created Bundle", bundle); execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundle)); } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java index 2032329..9efdc7a 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DecryptData.java @@ -16,18 +16,15 @@ import org.highmed.dsf.fhir.variables.FhirResourceValues; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Reference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import ca.uhn.fhir.context.FhirContext; import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.KeyProvider; import de.medizininformatik_initiative.processes.projectathon.data_transfer.crypto.RsaAesGcmUtil; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper; public class DecryptData extends AbstractServiceDelegate implements InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(DecryptData.class); - private final OrganizationProvider organizationProvider; private final KeyProvider keyProvider; @@ -58,8 +55,8 @@ protected void doExecute(DelegateExecution execution) Bundle bundleDecrypted = decryptBundle(keyProvider.getPrivateKey(), bundleEncrypted, sendingOrganizationIdentifier, localOrganizationIdentifier); - logger.debug("Decrypted Bundle: {}", - FhirContext.forR4().newXmlParser().encodeResourceToString(bundleDecrypted)); + + LoggingHelper.logDebugBundle("Decrypted Bundle", bundleDecrypted); execution.setVariable(BPMN_EXECUTION_VARIABLE_DATA_SET, FhirResourceValues.create(bundleDecrypted)); } @@ -87,7 +84,6 @@ private Bundle decryptBundle(PrivateKey privateKey, byte[] bundleEncrypted, Stri catch (Exception exception) { String taskId = getLeadingTaskFromExecutionVariables().getId(); - logger.warn("Could not decrypt received data-set for task with id='{}'", taskId); throw new RuntimeException("Could not decrypt received data-set for task with id='" + taskId + "'"); } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java index 0222b4e..adaf03b 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DeleteData.java @@ -31,7 +31,8 @@ protected void doExecute(DelegateExecution execution) IdType binaryId = new IdType((String) execution.getVariable(BPMN_EXECUTION_VARIABLE_DATA_SET_REFERENCE)); logger.info( - "Permanently deleting Binary with id='{}' provided for project-identifier='{}' referenced in Task with id='{}'...", + "Permanently deleting encrypted Binary with id='{}' provided for project-identifier='{}' " + + "referenced in Task with id='{}'...", binaryId.getValue(), projectIdentifier, getLeadingTaskFromExecutionVariables().getId()); deletePermanently(binaryId); diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java index 1b7fd98..db3ef78 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/DownloadData.java @@ -56,7 +56,7 @@ private IdType getDataSetReference(Task task) throw new IllegalArgumentException("No data-set reference present in task with id='" + task.getId() + "'"); if (dataSetReferences.size() > 1) - logger.warn("Found > 1 data-set references ({}) in task with id='{}', using only the first", + logger.warn("Found {} data-set references in task with id='{}', using only the first", dataSetReferences.size(), task.getId()); return new IdType(dataSetReferences.get(0)); @@ -72,11 +72,10 @@ private byte[] readDataSet(IdType dataSetReference) { return binary.readAllBytes(); } - catch (Exception excpetion) + catch (Exception exception) { - logger.warn("Downloading Binary with id='{}' failed", dataSetReference.getValue()); throw new RuntimeException("Downloading Binary with id='" + dataSetReference.getValue() + "' failed.", - excpetion); + exception); } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java index 877fafb..97ce0a5 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/EncryptData.java @@ -125,7 +125,7 @@ private DocumentReference getDocumentReference(Bundle bundle) "Could not find any DocumentReference in PublicKey Bundle with id='" + bundle.getId() + "'"); if (documentReferences.size() > 1) - logger.warn("Found {} DocumentReferences in PublicKey Bundle with id='{}', using first", + logger.warn("Found {} DocumentReferences in PublicKey Bundle with id='{}', using the first", documentReferences.size(), bundle.getId()); return documentReferences.get(0); @@ -141,7 +141,7 @@ private Binary getBinary(Bundle bundle) "Could not find any Binary in PublicKey Bundle with id='" + bundle.getId() + "'"); if (binaries.size() > 1) - logger.warn("Found {} Binaries in PublicKey Bundle with id='{}', using first", binaries.size(), + logger.warn("Found {} Binaries in PublicKey Bundle with id='{}', using the first", binaries.size(), bundle.getId()); return binaries.get(0); @@ -155,7 +155,6 @@ private PublicKey getPublicKey(Binary binary, String publicKeyBundleId) } catch (Exception exception) { - logger.info("Could not read PublicKey from Binary in PublicKey Bundle with id='{}'", publicKeyBundleId); throw new RuntimeException( "Could not read PublicKey from Binary in PublicKey Bundle with id='" + publicKeyBundleId + "'", exception); diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java index baef93a..2b406fa 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/ReadData.java @@ -34,6 +34,7 @@ import ca.uhn.fhir.context.FhirContext; import de.medizininformatik_initiative.processes.projectathon.data_transfer.client.KdsClientFactory; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper; public class ReadData extends AbstractServiceDelegate { @@ -68,11 +69,10 @@ protected void doExecute(DelegateExecution execution) String coordinatingSiteIdentifier = getCoordinatingSiteIdentifier(task); DocumentReference documentReference = readDocumentReference(projectIdentifier, task.getId()); - logger.debug("Read DocumentReference: {}", - FhirContext.forR4().newXmlParser().encodeResourceToString(documentReference)); + LoggingHelper.logDebugResource("Read DocumentReference", documentReference); Binary binary = readBinary(documentReference, task.getId()); - logger.debug("Read Binary: {}", FhirContext.forR4().newXmlParser().encodeResourceToString(binary)); + LoggingHelper.logDebugBinary("Read Binary", binary); execution.setVariable(BPMN_EXECUTION_VARIABLE_PROJECT_IDENTIFIER, projectIdentifier); execution.setVariable(BPMN_EXECUTION_VARIABLE_COORDINATING_SITE_IDENTIFIER, coordinatingSiteIdentifier); @@ -94,8 +94,8 @@ private String getProjectIdentifier(Task task) throw new IllegalArgumentException("No project identifier present in task with id='" + task.getId() + "'"); if (identifiers.size() > 1) - logger.warn("Found > 1 project identifiers ({}) in task with id='{}', using only the first", - identifiers.size(), task.getId()); + logger.warn("Found {} project identifiers in task with id='{}', using only the first", identifiers.size(), + task.getId()); return identifiers.get(0); } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java index 4e63926..99624ac 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/service/StoreData.java @@ -29,7 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.uhn.fhir.context.FhirContext; +import de.medizininformatik_initiative.processes.projectathon.data_transfer.util.LoggingHelper; public class StoreData extends AbstractServiceDelegate { @@ -81,8 +81,7 @@ private Binary createBinary(byte[] content, String coordinatingSiteIdentifier) Binary binary = new Binary().setContentType(MediaType.APPLICATION_OCTET_STREAM) .setSecurityContext(securityContext).setData(content); - logger.debug("Created Binary: {}", - FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(binary)); + LoggingHelper.logDebugBinary("Created Binary", binary); return binary; } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java index c6144ef..b9cf338 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/spring/config/TransferDataConfig.java @@ -132,7 +132,7 @@ public class TransferDataConfig @Bean @SuppressWarnings("unchecked") - public KdsClientFactory projectathonClientFactory() + public KdsClientFactory kdsClientFactory() { Path trustStorePath = checkExists(fhirStoreTrustStore); Path certificatePath = checkExists(fhirStoreCertificate); @@ -172,7 +172,7 @@ private Path checkExists(String file) @Bean public ReadData readData() { - return new ReadData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, projectathonClientFactory()); + return new ReadData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, kdsClientFactory()); } @Bean @@ -243,7 +243,6 @@ public ValidateDataCos validateDataCos() @Bean public InsertData insertData() { - return new InsertData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, - projectathonClientFactory()); + return new InsertData(fhirClientProvider, taskHelper, readAccessHelper, fhirContext, kdsClientFactory()); } } diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java new file mode 100644 index 0000000..4bcca76 --- /dev/null +++ b/mii-dsf-process-projectathon-data-transfer/src/main/java/de/medizininformatik_initiative/processes/projectathon/data_transfer/util/LoggingHelper.java @@ -0,0 +1,50 @@ +package de.medizininformatik_initiative.processes.projectathon.data_transfer.util; + +import java.nio.charset.StandardCharsets; + +import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; + +public class LoggingHelper +{ + private static final Logger logger = LoggerFactory.getLogger(LoggingHelper.class); + + public static void logDebugBundle(String message, Bundle bundle) + { + Bundle copy = bundle.copy(); + + // replace actual content with content size in bytes to not leak sensitive information + copy.getEntry().stream().filter(Bundle.BundleEntryComponent::hasResource) + .map(Bundle.BundleEntryComponent::getResource).filter(r -> r instanceof Binary).map(r -> (Binary) r) + .forEach(b -> b.setContent(createReplacementContent(b))); + + logDebugResource(message, copy); + } + + public static void logDebugBinary(String message, Binary binary) + { + Binary copy = binary.copy(); + + // replace actual content with content size in bytes to not leak sensitive information + copy.setContent(createReplacementContent(copy)); + + logDebugResource(message, copy); + } + + public static void logDebugResource(String message, Resource resource) + { + logger.debug(message + ": {}", + FhirContext.forR4().newXmlParser().setPrettyPrint(true).encodeResourceToString(resource)); + } + + private static byte[] createReplacementContent(Binary binary) + { + return ("original content (" + binary.getContent().length + " bytes) replaced") + .getBytes(StandardCharsets.UTF_8); + } +} From 7d94f9a2248268e6fea9cf95e4ca9bd1b3b61a6b Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Tue, 8 Mar 2022 18:03:38 +0100 Subject: [PATCH 23/25] Add warning for windows curl command --- mii-dsf-processes-docker-test-setup/README.md | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/mii-dsf-processes-docker-test-setup/README.md b/mii-dsf-processes-docker-test-setup/README.md index c487e6e..1030b1a 100644 --- a/mii-dsf-processes-docker-test-setup/README.md +++ b/mii-dsf-processes-docker-test-setup/README.md @@ -7,41 +7,51 @@ mvn clean package ``` Add entries to your hosts file + ``` 127.0.0.1 dic 127.0.0.1 cos ``` -*A total of four console windows are required. Start docker-compose commands from sub-folder:* `mii-dsf-processes/mii-dsf-processes-docker-test-setup` +*A total of four console windows are required. Start docker-compose commands from +sub-folder:* `mii-dsf-processes/mii-dsf-processes-docker-test-setup` + +Console 1: Start DIC HAPI FHIR Server -Console 1: Start DIC HAPI FHIR Server ```sh docker-compose up dic-fhir-store-hapi ``` + Access at http://localhost:8080/fhir/ Console 4: Start COS HAPI FHIR Server + ```sh docker-compose up cos-fhir-store-hapi ``` + Access at http://localhost:8081/fhir/ Console 2: Start DIC DSF FHIR Server and wait till started + ```sh docker-compose up -d dic-fhir && docker-compose logs -f dic-fhir ``` -Console 2: Disconnect from log output (Ctrl-C) if Server started -Console 2: Start DIC DSF BPE Server + +Console 2: Disconnect from log output (Ctrl-C) if Server started Console 2: Start DIC DSF BPE Server + ```sh docker-compose up -d dic-bpe && docker-compose logs -f dic-fhir dic-bpe ```` Console 3: Start COS DSF FHIR Server and wait till started + ```sh docker-compose up -d cos-fhir && docker-compose logs -f cos-fhir ``` -Console 3: Disconnect from log output (Ctrl-C) if Server started -Console 3: Start COS DSF BPE Server + +Console 3: Disconnect from log output (Ctrl-C) if Server started Console 3: Start COS DSF BPE Server + ```sh docker-compose up -d cos-bpe && docker-compose logs -f cos-fhir cos-bpe ```` @@ -54,6 +64,7 @@ Webbrowser at http://localhost:8080/fhir/: Add Demo Data to DIC HAPI FHIR Server *Start curl commands from root-folder:* `mii-dsf-processes` Console 6: Execute Demo Transaction-Bundle for HAPI + ```sh curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \ -d @mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml \ @@ -61,21 +72,29 @@ http://localhost:8080/fhir ``` Console 6: Start Data Send Process at DIC using the following command + +*Unfortunately this command does not work on Windows. An alternative for starting the process is using WSL or the +example starter class with name `DataSendExampleStarter` +in `mii-dsf-process-projectathon-data-transfer/src/test/java/../bpe/start`* + ```sh curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \ -d @mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml \ --ssl-no-revoke --cacert mii-dsf-processes-test-data-generator/cert/ca/testca_certificate.pem \ --cert mii-dsf-processes-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_certificate.pem \ --key mii-dsf-processes-test-data-generator/cert/Webbrowser_Test_User/Webbrowser_Test_User_private-key.pem \ +--pass password \ https://dic/fhir/Task ``` Console X: Check data transferred to COS + ```sh curl http://localhost:8081/fhir/DocumentReference ``` Console X: Stop everything + ```sh docker-compose down -v ``` \ No newline at end of file From 95bcf8f2c30a3ca69f9be3ab1b2c078d38653e09 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Tue, 8 Mar 2022 18:09:24 +0100 Subject: [PATCH 24/25] further improvements --- mii-dsf-processes-docker-test-setup/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mii-dsf-processes-docker-test-setup/README.md b/mii-dsf-processes-docker-test-setup/README.md index 1030b1a..0359884 100644 --- a/mii-dsf-processes-docker-test-setup/README.md +++ b/mii-dsf-processes-docker-test-setup/README.md @@ -13,7 +13,7 @@ Add entries to your hosts file 127.0.0.1 cos ``` -*A total of four console windows are required. Start docker-compose commands from +*A total of five console windows are required. Start docker-compose commands for consoles 1 to 4 from sub-folder:* `mii-dsf-processes/mii-dsf-processes-docker-test-setup` Console 1: Start DIC HAPI FHIR Server @@ -61,9 +61,9 @@ Webbrowser at http://localhost:8080/fhir/: Add Demo Data to DIC HAPI FHIR Server [DicFhirStore_Demo.xml](../mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml) --> -*Start curl commands from root-folder:* `mii-dsf-processes` +*Start curl commands in console 5 from root-folder:* `mii-dsf-processes` -Console 6: Execute Demo Transaction-Bundle for HAPI +Console 5: Execute Demo Transaction-Bundle for HAPI ```sh curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \ @@ -71,11 +71,11 @@ curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \ http://localhost:8080/fhir ``` -Console 6: Start Data Send Process at DIC using the following command +Console 5: Start Data Send Process at DIC using the following command *Unfortunately this command does not work on Windows. An alternative for starting the process is using WSL or the -example starter class with name `DataSendExampleStarter` -in `mii-dsf-process-projectathon-data-transfer/src/test/java/../bpe/start`* +example starter class with name* `DataSendExampleStarter` *in* +`mii-dsf-process-projectathon-data-transfer/src/test/java/../bpe/start` ```sh curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \ @@ -87,13 +87,13 @@ curl -H "Accept: application/xml+fhir" -H "Content-Type: application/fhir+xml" \ https://dic/fhir/Task ``` -Console X: Check data transferred to COS +Console 5: Check data transferred to COS ```sh curl http://localhost:8081/fhir/DocumentReference ``` -Console X: Stop everything +Console 5: Stop everything ```sh docker-compose down -v From 1e2c3e01fde6b5bb979fb8c8d7b8a4486cce5c97 Mon Sep 17 00:00:00 2001 From: Reto Wettstein Date: Wed, 9 Mar 2022 10:19:37 +0100 Subject: [PATCH 25/25] 0.1.0-RC1 preparations --- mii-dsf-process-projectathon-data-transfer/pom.xml | 2 +- .../ActivityDefinition/mii-projectathon-data-receive.xml | 2 +- .../fhir/ActivityDefinition/mii-projectathon-data-send.xml | 2 +- .../src/main/resources/fhir/CodeSystem/mii-cryptography.xml | 2 +- .../src/main/resources/fhir/CodeSystem/mii-data-transfer.xml | 2 +- .../resources/fhir/NamingSystem/mii-project-identifier.xml | 5 +++-- .../mii-projectathon-task-start-data-receive.xml | 4 +++- .../mii-projectathon-task-start-data-send.xml | 4 +++- .../src/main/resources/fhir/ValueSet/mii-cryptography.xml | 2 +- .../src/main/resources/fhir/ValueSet/mii-data-transfer.xml | 2 +- .../src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml | 4 ++-- .../src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml | 2 +- mii-dsf-processes-documentation-generator/pom.xml | 2 +- .../src/main/resources/log4j2.xml | 4 ++-- mii-dsf-processes-test-data-generator/pom.xml | 2 +- .../src/main/resources/log4j2.xml | 4 ++-- pom.xml | 2 +- 17 files changed, 26 insertions(+), 21 deletions(-) diff --git a/mii-dsf-process-projectathon-data-transfer/pom.xml b/mii-dsf-process-projectathon-data-transfer/pom.xml index e9aa48e..cf27e48 100644 --- a/mii-dsf-process-projectathon-data-transfer/pom.xml +++ b/mii-dsf-process-projectathon-data-transfer/pom.xml @@ -8,7 +8,7 @@ de.medizininformatik-initiative mii-dsf-processes - 0.1.0-SNAPSHOT + 0.1.0-RC1 diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml index 55d01a5..fe89b80 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-receive.xml @@ -85,7 +85,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml index 72956e5..46f707b 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ActivityDefinition/mii-projectathon-data-send.xml @@ -65,7 +65,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml index 913c2a2..088591d 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-cryptography.xml @@ -13,7 +13,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml index cfc0686..fb228d5 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/CodeSystem/mii-data-transfer.xml @@ -13,7 +13,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml index 12f494d..91af56f 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/NamingSystem/mii-project-identifier.xml @@ -6,9 +6,10 @@ - + + - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml index 9b48772..bc58dee 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-receive.xml @@ -6,11 +6,13 @@ + + - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml index 4ce0a82..00d10c5 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/StructureDefinition/mii-projectathon-task-start-data-send.xml @@ -6,11 +6,13 @@ + + - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml index 4d38819..e71b1ab 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-cryptography.xml @@ -13,7 +13,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml index f4d2952..221a68f 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/main/resources/fhir/ValueSet/mii-data-transfer.xml @@ -13,7 +13,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml index 542296d..b744708 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Bundle/DicFhirStore_Demo.xml @@ -17,7 +17,7 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml index 420649b..d85d569 100644 --- a/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml +++ b/mii-dsf-process-projectathon-data-transfer/src/test/resources/fhir/Task/TaskStartDataSend_Demo.xml @@ -5,7 +5,7 @@ - + diff --git a/mii-dsf-processes-documentation-generator/pom.xml b/mii-dsf-processes-documentation-generator/pom.xml index b2e68be..564f3af 100644 --- a/mii-dsf-processes-documentation-generator/pom.xml +++ b/mii-dsf-processes-documentation-generator/pom.xml @@ -9,7 +9,7 @@ de.medizininformatik-initiative mii-dsf-processes - 0.1.0-SNAPSHOT + 0.1.0-RC1 diff --git a/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml b/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml index 67a1731..e8e6da7 100644 --- a/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml +++ b/mii-dsf-processes-documentation-generator/src/main/resources/log4j2.xml @@ -8,9 +8,9 @@ - - + + diff --git a/mii-dsf-processes-test-data-generator/pom.xml b/mii-dsf-processes-test-data-generator/pom.xml index 9fb926c..3724159 100644 --- a/mii-dsf-processes-test-data-generator/pom.xml +++ b/mii-dsf-processes-test-data-generator/pom.xml @@ -8,7 +8,7 @@ de.medizininformatik-initiative mii-dsf-processes - 0.1.0-SNAPSHOT + 0.1.0-RC1 diff --git a/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml b/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml index 67a1731..e8e6da7 100644 --- a/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml +++ b/mii-dsf-processes-test-data-generator/src/main/resources/log4j2.xml @@ -8,9 +8,9 @@ - - + + diff --git a/pom.xml b/pom.xml index 4fa7d4d..fba3abd 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ de.medizininformatik-initiative mii-dsf-processes - 0.1.0-SNAPSHOT + 0.1.0-RC1 pom