The project is intended to provide a simple way to run the ePA backend services in a local docker environment and includes docker-compose and other relevant files. This should help to get a better understanding of the ePA services and should help to develop & test ePA 3.0.x for PS applications.
Important
This project uses mock implementations based on the ePA specification and focuses on some selected backend services. The mock implementations try to realize many aspects of the specification, but are not 1:1 equivalent to a productive environment. The specification is always leading and should be used as a reference.
In particular, the following uses cases are covered:
- Perform VAU handshake and send and receive encrypted data
- Create a user session with the ePA authorization service and IDP (RU)
- Create an entitlement
- Get the medication list (eML) for a patient as XHTML and PDF/A document
You the following tools to run the services:
You need the following system resources to run the services:
- at least 4 GB of RAM
- the following ports should be available:
- for the ePA backend services 443 (https)
- port range to directly access the mock services via the exposed ports (8081-8090)
- for the testsuite 8123-8124 (http)
Start the mock services with the following command
docker-compose -f dc-mocks.yml up
Stop these services with the following command
docker-compose -f dc-mocks.yml down
To import medications related data to the medication-service execute the following script from the medication folder:
cd medication
./import-tx.sh
After successful import the data can be accessed via the following curl commands (placeholder have to be replaced with the actual host IP or name):
curl --location http://<docker-host>:8084/fhir/Organization
curl --location http://<docker-host>:8084/fhir/Practitioner
curl --location http://<docker-host>:8084/fhir/PractitionerRole
curl --location http://<docker-host>:8084/fhir/Patient
curl --location http://<docker-host>:8084/fhir/Medication
curl --location http://<docker-host>:8084/fhir/MedicationRequest
curl --location http://<docker-host>:8084/fhir/MedicationDispense
Searching by including references in the result:
- Query PractitionerRole with the related Organization
curl --location http://<docker-host>:8084/fhir/PractitionerRole?_include=PractitionerRole:organization
- Query MedicationRequest with requester (PractitionerRole) and the Organization related to it
curl --location http://<docker-host>:8084/fhir/MedicationRequest?_include=MedicationRequest:requester&_include:iterate=PractitionerRole:organization
The Tiger WebUI is a simple web interface to visualize the traffic between the client and the backend services. The WebUI is accessible via the following URL: http://<docker-host>:8086/webui.
The mock application vau-proxy-server sets specific HTTP headers VAU-DEBUG-S_K1_s2c
and VAU-DEBUG-S_K1_c2s
in the responses (M2 /M4) to indicate the encrypted data. The tiger-proxy decrypts the data and shows the decrypted data in the request & response body.
Important
This not specification compliant and is only supported by this mock implementation (vau-proxy-server in combination with the tiger-proxy).
The ePA client has to set a specific HTTP header VAU-nonPU-Tracing
in the request to indicate the encrypted data within nonPU environments (A_24477). Thus, the tiger-proxy decrypts and shows the decrypted data in the request & response body.
The offline page ./doc/html/InformationRecordStatus.html shows an example traffic of retrieving the status of a patient health record with information service (mock).
The offline page ./doc/html/InformationConsentDecision.html shows an example traffic of retrieving the consent decisions of a patient with information service (mock).
The offline page ./doc/html/VauHandshakeAndUserSession.html shows a decrypted example traffic of the VAU handshake between the client and the VAU Proxy Server as well as the user session creation with authorization service (mock) & IDP (RU).
The offline page ./doc/html/SetEntitlement.html shows a decrypted example traffic of adding a new entitlement with entitlement service (mock).
The offline page ./doc/html/MedicationPDF.html shows a decrypted example traffic of retrieving the entire medication list as PDF/A document with medication render service (mock).
The offline page ./doc/html/MedicationXHTML.mhtml shows a decrypted example traffic of retrieving the entire medication list as XHTML document with medication render service (mock).
The offline page ./doc/html/MedicationFHIR.html shows a decrypted example traffic of retrieving the entire medication list as FHIR resource with medication service (mock).
The PS-Testsuite is a test suite to verify specific functionality of a PS application.
As the testsuite container obtains Maven artefacts during execution, the internet must be accessible for the container. If the internet is only accessible via a proxy server, the settings in the ./ps-testsuite/settins.xml must be adjusted for the execution of the PS-Testsuite container. Please note that the parameter <active>true</active>
must be set to activate the settings and the docker volume ps-testsuite-maven
must be deleted to apply the changes.
To do this, the following entries must be adjusted:
<proxy>
<id>optional</id>
<active>true</active>
<protocol>https</protocol>
<host>proxy.example.com</host>
<port>8080</port>
<username>user</username>
<password>password</password>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
Start the testsuite container with the following command
docker-compose -f dc-testsuite.yml up
When the container log shows the following message, the testsuite is ready to be used and a webbrowser should call the URL http://<docker-host>:8123 to go on. Otherwise, the timeout will stop the testsuite and the container stops automatically. In this case you have to rerun the testsuite with the command above.
========================================================================================================================
____ _____ _ ____ _____ ___ _ _ ____ __ _____ ____ _ _______ _ _____ __ _ _ ___
/ ___|_ _|/ \ | _ \_ _|_ _| \ | |/ ___| \ \ / / _ \| _ \| |/ / ___| | / _ \ \ / / | | | |_ _|
\___ \ | | / _ \ | |_) || | | || \| | | _ \ \ /\ / / | | | |_) | ' /| |_ | | | | | \ \ /\ / / | | | || |
___) || |/ ___ \| _ < | | | || |\ | |_| | \ V V /| |_| | _ <| . \| _| | |__| |_| |\ V V / | |_| || | _ _ _
|____/ |_/_/ \_\_| \_\|_| |___|_| \_|\____| \_/\_/ \___/|_| \_\_|\_\_| |_____\___/ \_/\_/ \___/|___| (_|_|_)
========================================================================================================================
09:21:12.065 [main ] INFO d.g.t.t.l.TigerDirector - Waiting for workflow Ui to fetch status...
09:21:12.065 [main ] INFO d.g.t.t.l.TigerDirector - Workflow UI http://localhost:8123
Stop the testsuite container with the following command
docker-compose -f dc-testsuite.yml down
After calling the URL http://<docker-host>:8123 in a webbrowser, the workflowUI will be shown. As depicted in Waiting WorkflowUI the testcase for VAU handshake is automatically selected. Now, the testsuite will trace any traffic flow between the client and the mock services on https://<docker-host>:443. On the bottom of the page you can see the request to trigger a specific functionality within your PS application. Do so and after the finished execution click on the "Continue" button on the bottom of the page.
Now, the traffic will be analyzed and the results will be shown in the workflowUI. If everything is fine, the testcase will be marked as successful as depicted in Successful WorkflowUI.
If the testcase failed, the testcase will be marked as failed as depicted in Failed WorkflowUI and you can analyze the reason for the failure e.g. within message flow traced during the execution. Click in the upper right corner button to open the "Rbel Log Details" to have a closer look on the messages itself.
By default, the execution of the VAU handshake test case is selected. To select a different test case, you must configure it via the .env file, in which you must adjust the value for ‘PS_TESTSUITE_TESTS’ accordingly.
The testcase verifies the message with the information service (mock) necessary to retrieve the status of a patient health record. The testcase will be successful if the record status is successfully retrieved with the GET message.
The testcase verifies the message with the information service (mock) necessary to retrieve the consent decisions of a patient. The testcase will be successful if the consent decisions are successfully retrieved with the GET message.
The testcase verifies the VAU handshake between the client and the VAU Proxy Server (mock). The testcase will be successful if the VAU handshake is successfully completed with messages M1 to M4.
The testcase verifies the message with the authorization service (mock) necessary to create a user session, but NOT the messages with the IDP (RU). The testcase will be successful if the user session is successfully created with messages getNonce
, send_authorization_request_sc
and send_authcode_sc
.
The testcase verifies the message with the entitlement service (mock) necessary to create an entitlement. The testcase will be successful if the entitlement is successfully created with the POST message.
The testcase verifies the message with the medication render service (mock) necessary to retrieve the entire medication list as PDF/A document. The testcase will be successful if the medication list is successfully retrieved with the GET message.
The testcase verifies the message with the medication render service (mock) necessary to retrieve the entire medication list as XHTML document. The testcase will be successful if the medication list is successfully retrieved with the GET message.
The testcase verifies the message with the medication service (mock) necessary to retrieve the entire medication list as FHIR resource. The testcase will be successful if the medication list is successfully retrieved with the GET message.
The services can be accessed directly by using the exposed ports. The following table shows the services and the related ports and protocols. This should also give an overview of the ports to be opened in your setup.
Service | Port | Protocol |
---|---|---|
ePA health record system (tiger-proxy) | 443 | https |
vau-proxy-server | 8081 | http |
information-service | 8082 | http |
authorization-service | 8083 | http |
medication-service | 8084 | http |
medication-render-service | 8085 | http |
tiger-proxy (admin) | 8086 | http |
entitlement-service | 8087 | http |
Note
Please feel free to modify the exposed ports in the '.env' file in order to meet your own requirements. The docker container internal ports are not affected by this change as well as the docker network communication.
Important
Please use the already existing TI services through the connector e.g. to access the IDP (RU) using the following URL: https://idp-ref.zentral.idp.splitdns.ti-dienste.de
The tiger proxy is a reverse proxy which is used to route the incoming requests to the correct service. It is accessible via port 443 as it is using TLS/SSL. The proxy is also doing the SSL termination for the services. The configuration of the proxy is done in the /tiger-proxy/application.yaml
file.
- server certificate is generated on-the-fly using the
/tiger-proxy/root.p12
as authority chain - OCSP stabling is currently not supported
By specification some services inside the ePA has to be encrypted/decrypted by the VAU. The VAU Proxy Client handles the VAU handshake for a given PS instance. This handshake enables the VAU Proxy Client to encrypt messages which can be decrypted by the VAU Proxy Server before the messages are passed onto ePA services.
To trigger a restart of a VAU connection, you can send the request with the user data to /<VAU-CID>/restart
instead of /<VAU-CID>
. This will cause the VAU proxy server to release the connection by deleting the VAU-CID on the server side and the server state machine will be removed. A new VAU session is NOT created automatically. VAU proxy server sends a response as specified in A_24772. The VAU client must therefore start a new handshake.
To additionally activate trace information in this container, set the variable LIB_VAU_LOGGING_LEVEL to the value TRACE. It gives you additional information like the encrypted message right before it is decrypted. Therefore, you have to redeploy the container (not only restart).
EncryptedVauMessage: trying to decrypt:
Complete message : 0200010000000000000003e807d37d434aa2f5c2e279782efb541bf85f4a4bf52902a3eb4b017b065975c0cbd935c10000000000000003e24c47b1a0c573f1abb8e606d7d0742a25c3b822fdc427192afed5156ebb21991819c6b45872703314ed3377cd96a...
Message size (Bytes) : 3967
Complete header : 0200010000000000000003e807d37d434aa2f5c2e279782efb541bf85f4a4bf52902a3eb4b017b065975c0
Key to decrypt (K2_c2s_app_data): 25cb56e13d31ecc8e49f88dea29271780ba6d6c03b0869f54f8d86ed14581c7e
-------------------------------
Version (1 Byte): 02
PU (1 Byte): 00
Request (1 Byte): 01
Counter (8 Byte): 0000000000000003
KeyId (32 Byte): e807d37d434aa2f5c2e279782efb541bf85f4a4bf52902a3eb4b017b065975c0
IV (12 Byte): cbd935c10000000000000003
CT + GMAC : e24c47b1a0c573f1abb8e606d7d0742a25c3b822fdc427192afed5156ebb21991819c6b45872703314ed3377cd96a...
- interface operation/path to request the status of user authentication is not fully supported (A_25143) >
/VAU-Status as HTTP-GET
- "User-Authentication" is always "None"
- "Connection-Start" is the timestamp when M3 message of VAU handshake was successfully validated & completed on backend side
- interface operation/path to request AUT-VAU certificate + certificate chain via /CertData as HTTP-GET is not fully supported (A_24957) *
- rch_chain uses certificates from https://download.tsl.ti-dienste.de as array content (> RCA5)
This service provides information about the health record of a patient. The capabilities of the service are described detailed in following openAPI specification: InformationService.
- for consent decisions it will always send "permit" for "medication" as well as "erp-submission"
- for record status it will always send HTTP code 204 (OK)
- false case for both operations:
- to get HTTP code 404 use "X000000404" as header parameter 'x-insurantid'
- to get HTTP code 409 use "X000000409" as header parameter 'x-insurantid'
- for user experience it is checked that the header x-useragent is set, otherwise HTTP code 409 is given
To retrieve the consent decisions of a patient execute the following curl command:
curl -H "x-insurantid: Z1234567890" --location --request GET http://<docker-host>:8082/information/api/v1/ehr/consentdecisions
To retrieve the health record status of a patient execute the following curl command:
curl -H "x-insurantid: Z1234567890" --location --request GET http://<docker-host>:8082/information/api/v1/ehr
The authorization service is a component which is known from OAuth2. Together with the IDP server it is responsible for the authentication and authorization of the user (User of a PS). The authentication flow is described here: Authentication Flow. As IDP the reference IDP is used which is addressed by the following URL: https://idp-ref.app.ti-dienste.de. All necessary configurations like clientID are already set in the IDP.
- It will not end user session after 20 Min. (A_25006)
The medication service is a HAPI FHIR server which provides the medication relevant data. The details about ePA Medication can be found in the related repository: ePA-Medication.
- Currently, the HAPI FHIR does not support searching resources by logical references. Therefore, the medication service does not support searching for medication requests by the patient reference. A request like
GET /MedicationRequest?subject:identifier=....
will return an error message, that it is not supported. There is already an open issue in the HAPI FHIR repository: Issue 4723.
The medication render service is responsible for rendering the medication list (eML) data in a human-readable form. The service is described in the following openAPI specification: MedicationRenderService.
To retrieve the eML as XHTML execute the following curl command:
curl --location --request GET http://<docker-host>:8085/epa/medication/render/v1/eml/xhtml --header 'Accept: text/html' --header 'x-insurantid: Z123456783'
To retrieve the same eML as PDF/A document execute the following curl command:
curl --location --request GET http://<docker-host>:8085/epa/medication/render/v1/eml/pdf --header 'Accept: application/pdf' --header 'x-insurantid: Z123456783' --output eml.pdf
To retrieve the eML as FHIR Resource execute the following curl command:
curl --location http://<docker-host>:8084/fhir/Medication?status=active
The entitlement Service is responsible for managing entitlements. The service is described in the following openAPI specification: EntitlementService.
The entitlement service is NOT linked with the other services, and therefore, if an entitlement is missing, no error message is returned by the other services.
Adding a new entitlement:
curl --location --request POST \
'http://<docker-host>:8087/epa/basic/api/v1/ps/entitlements' \
-H 'accept: application/json' \
-H 'x-insurantid: Z123456789' \
-H 'x-useragent: CLIENTID1234567890AB/2.1.12-45' \
-H 'Content-Type: application/json' \
-d '{"jwt": "<your valid jwt>"}'
List all existing entitlements stored within the service (only available with the mock service)
Important
This is only available with the mock services. In production only the patient and its representative has access to this interface method.
curl --location 'http://localhost:8087/epa/basic/api/v1/entitlements' \
-H 'x-insurantid: X110435031' \
-H 'x-useragent: CLIENTID1234567890AB/2.1.12-45'
- No JWT signature verification
- No OCSP check during the validation of the client certificate
- HMAC validation work only with gematik test cards
In case of a failed test run and the writing of a support ticket in the gematik Service Desk, it is useful to attach the *.tgr file with the recorded messages. This makes it possible to import the traces into a local Tiger application in order to display the communication and its message details.
To do this, you must execute the following command to copy the *.tgr from the ps-testsuite container to the local directory.
docker cp ps-testsuite:/app/tiger-proxy.tgr .
The decryption of the incoming message was faulty. In this case, a look at the logs from the VAU proxy server can help. Additional information about the exact cause of the error should be written in the log.
You can enable additional TRACE information, too. Please have a look at section Lib-vau traces for troubleshooting
If this does not help, please send us the log file in a service ticket.
docker logs vau-proxy-server > vau-proxy-server.log
Response with Transcript Error: Cannot invoke "io.netty.handler.codec.http.FullHttpRequest.uri()" because "innerRequest" is null
The decryption was successful, and you can see the decrypted message in vau-proxy-server logs. But the netty lib was not able to convert the incoming HTTP request string into an object. This could be, due to a malformed inner HTTP Request. Please make sure you follow the RFC specification.
Example Requests:
GET /epa/authz/v1/getNonce HTTP/1.1<CRLF>
Content-Length: 0<CRLF>
x-useragent: PSSIM123456789012345/1.2.4<CRLF>
Host: localhost:443<CRLF>
<CRLF>
<CRLF>
Please make sure that you use HTTP/1.1 when communicating with the IDP.