Dieser Service bietet Zugriff auf die URL der Marktpartner, d.h. er gibt die jeweils aktuelle URL eines Marktpartners auf Anfrage aus oder aktualisiert diese. Dafür besitzt der Service eine REST Schnittstelle. Ist die Mandant-URL inaktiv, wird keine Marktpartner Adresse an den AS4 Outbound Market Message Service übergeben und somit keine ausgehende AS4 Kommunikation durchgeführt.
Aktualisierungen der Adressen erfolgt gemäß dem AS4 Adresswechsel Workflows, im hiesigen Kontext als Pathswitch bezeichnet, über den Message Broker. Mithilfe des Pathswitches können Marktparnter und Mandant ihre Adresse aktualisieren.
Features & Nutzung
Der AS4-Address-Service erfüllt folgende Aufgaben:
- Administration der AS4 Adressen (sowohl Mandanten Adressen als auch Partner Adressen)
- REST API zur Administration, genutzt durch die Frontends
- inkl. AS4 Aktivierung / Deaktivierung je Mandant
- asynchrone Benachrichtigung der Backends über Statusänderungen der AS4-Beziehungen
- REST API zur Administration, genutzt durch die Frontends
- Pathswitch Verarbeitung
- Pathswitch Request Erzeugen / Behandeln
- Pathswitch Confirmation Erzeugen / Behandeln
- Pathswitch Nachrichten monitoren über REST API
Der AS4-Adress-Service kann auch über folgende Frontends angesprochen werden:
Mandantenpflege
Jeder Mandant muss zunächst per REST-API angelegt werden. Ein Beispiel-Script zum Erstellen von Mandanten per API-Aufruf ist hier (intern) verfügbar. Beispiel:
curl -X 'POST' "http://localhost:8080/aep-as4-address-service/as4-address/tenants" \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{"tenantCodes": [99123456]}'
Jede Mandanten-MPID ist im AS4-Address-Service zu hinterlegen. Die zugehörige AS4 Adresse ist zu pflegen und der Mandant muss aktiviert werden.
Ein deaktivierter Mandant verschickt niemals Nachrichten per AS4.
Beim Aktivieren werden Pathswitch-Nachrichten an alle bekannten Partneradressen geschickt, sofern die Partner in Beziehung zum Mandanten stehen.
Falls ein Mandant deaktiviert und reaktiviert wird, werden erneut Pathswitch Nachrichten an alle bekannten Partneradressen, die in Beziehung zum Mandanten stehen, verschickt, auch wenn der Pathswitch vor der Deaktivierung bereits erfolgreich durchgeführt worden ist.
Partnerbeziehungspflege
Jede Partner-ILN kann dem AS4-Address-Service bekannt gemacht werden. Ein Partner muss mit mind. einem Mandanten in Beziehung gesetzt werden.
Für Partner können optional die AS4-Adressen gepflegt werden. Dies ermöglicht das Versenden von Pathswitch Requests. Alternativ könnte auch ein Pathswitch vom Partner verschickt werden.
Ein Beispiel-Script zum Erstellen von Partnerbeziehungen per API-Aufruf ist hier (intern) verfügbar. Beispiel:
curl -X 'POST' "http://localhost:8080/aep-as4-address-service/as4-address/partner-addresses" \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{"tenantCode": "99123456", "partnerCode": "99765432", "address": "https://blue-energy.de/99765432/as4"}'
Alternativ zur REST-API kann die Partnerbeziehungspflege auch per Frontend erfolgen.
Falls mehrere Partnerbeziehungen gleichzeitig hinzugefügt werden möchten, so kann eins der Skripte verwendet werden.
Falls ausgehende AS4 Kommunikation gezielt für einzelne Partner deaktiviert werden soll, sind die zugehörigen Partnerbeziehungen zu löschen.
Automatische Anlage von Beziehungen
Über die Queue as4.relation.create.default
können automatisch Beziehungen angelegt werden. Diese Queue kann z.B. vom Receipt Service befüllt werden, falls dort entsprechend konfiguriert. Eine Beziehung kann noch nicht bestätigt werden, wenn das Zertifikat fehlt.
Auf Basis der Anlage von Beziehungen kann automatisch ein Zertifikatsdownload gestartet werden, falls das zugehörige Zertifikat fehlt. Hierfür wird eine Message an die Exchange certificate.download.command
übermittelt.
Pathswitch Monitoring
Über die REST API können Informationen über alle verarbeiteten Pathswitch Requests & Confirmations eingesehen werden. Die Daten enthalten auch Referenzen auf die zugehörigen AS4 Nachrichten, welche über die API des AS4-Message-Service abgerufen werden können.
Hardware Anforderungen
Eine Service-Instanz erfordert mindestens 512 MB RAM.
Wir empfehlen 0,4 CPU-Kerne je Instanz.
Logs werden auf die Festplatte geschrieben, entsprechend muss genügend Speicherplatz vorhanden sein.
Abhängigkeiten
Der Service greift auf einen Message-Broker zu, um Nachrichten zu empfangen und zu versenden.
Der Service greift auf eine SQL Datenbank zu, um Adressen zu speichern. Der Speicherverbrauch ist gering.
REST API Dokumentation
Die API wird durch das Frontend und durch den AS4 Outbound Market Message Service genutzt.
Darüber hinaus bietet die API Server-Health Informationen an.
Die Beschreibung der REST API lässt sich, im Fall einer Docker Installation, unter http://host.docker.internal:8085/aep-as4-address-service/swagger-ui/index.html
oder unter http://localhost:8080/aep-as4-address-service/swagger-ui/index.html
finden.
Ein KontextPath Präfix kann über folgende Property konfiguriert werden: server.servlet.contextPath
.
Der Port lässt sich über folgende Property konfigurieren: server.port=8080
.
Für produktive Systeme wird ein Loadbalancer benötigt, um die Anfragen auf mehrere Instanzen zu verteilen.
Konfiguration
Einfache Konfiguration der as4-address-service.properties
SQL Datenbank Anbindung
Der Einsatz des Microservice erfordert Zugriff auf eine SQL-Datenbank. Im Vorfeld muss ein Schema angelegt worden sein. Die Tabellen werden automatisch vom Microservice angelegt (via flyway).
Diese speziellen Datenbankparameter können je nach Bedarf verändert werden. Das Passwort wird als Environment Variable mit übergeben. Momentan werden die Datenbanksysteme MSSQL, Oracle und Postgresql unterstützt.
datasource.url=jdbc:postgresql://as4-database:5432/as4_address?currentSchema=as4_address
datasource.username=postgres
datasource.password=${DB_PASSWORD}
datasource.type=postgres
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Im Fall einer Oracle-DB kann sich an den nachfolgenden Parametern orientiert werden.
datasource.url=jdbc:oracle:thin:@//as4-database-oracle:1521/orclas4
datasource.username=as4_address
datasource.password=${DB_PASSWORD}
datasource.type=oracle
Es muss mindestens Oracle 12.2 eingesetzt werden, ältere Versionen werden nicht unterstützt.
Message Broker Anbindung
Die Kommunikation zwischen den verschiedene AS4 Services erfolgt über einen Message-Broker.
rabbitmq.host=rabbitmq3
rabbitmq.port=5672
rabbitmq.username=guest
rabbitmq.password=guest
Tenant-Partner-Beziehungsvalidierung
Darüber hinaus validiert der Address-Service die Partner-Mandanten-Beziehung, wenn eine Pathswitch-Anfrage eingeht. Eine Bestätigung wird nur generiert, wenn eine Beziehung besteht und der Mandant aktiv ist. Mit anderen Worten muss die Beziehung zwischen dem Partner und dem Mandanten in einem Zustand von Ausstehend oder Bereit sein. Diese Funktion kann mit der folgenden Eigenschaft genutzt werden:
partnerTenantRelationValidation=true
Routing Konfiguration der as4-address-service.properties
Falls Sie das Standard Routing nutzen, muss das Routing nicht weiter konfiguriert werden. Wenn Sie Ihr Routing anpassen möchten, lesen Sie die folgende Dokumentation.
Für die Aktivierung des Routings müssen der headerName und die headerValues gesetzt werden. Den headerName kann man sich als Filterkategorie vorstellen, während die headerValues den zu filternden Werten entsprechen. Nachrichten mit Werten, die nicht explizit als headerValues aufgelistet sind, laufen weiterhin über die default Route.
Als headerName werden folgende Parameter angeboten:
- tenant: ILN Nummer des Senders
- partner: ILN Nummer des Empfängers.
- sector: GAS, ELECTRICITY
Es können mehrere Werte kommasepariert angegeben werden.
pathswitchExchangeName=as4.outbound.request.pathswitch
pathswitchHeaderName=partner
pathswitchHeaderValues=
Wird der Producer für das Routing konfiguriert muss natürlich auch die Gegenstelle dafür eingerichtet werden. Dem Consumer wird über die Gruppe der Wert (Value) aus der HeaderValues Liste zugewiesen nach welchem gefiltert werden soll. Bitte den Default Wert nur ändern, wenn Routing verwendet werden soll.
pathswitchOutboundExchangeName=as4.outbound.pathswitch
pathswitchOutboundGroup=default
Externes Pathswitch-Ereignis AS4-Address-Service erstellt ein externes API-Pathswitch-Ereignis (AMQP), nachdem es ein internes AS4-Ereignis empfangen hat.
externalEventPathswitchExchangeName=as4.pathswitch.delivery
externalEventPathswitchHeaderName=tenant
externalEventPathswitchHeaderValues=
Eingehender Pathswitch
Die Queue as4.inbound.pathswitch enthält die Pathswitch Message vom AS4 Message Service basierend auf dem routing key der serviceId für pathswitch Nachrichten https://www.bdew.de/as4/communication/services/pathSwitch. Das Objekt enthält alle notwendigen Informationen über die Business Message und das Receipt.
pathswitchInboundExchangeName=as4.inbound
pathswitchInboundGroup=pathswitch
pathswitchInboundRoutingKey=https://www.bdew.de/as4/communication/services/pathSwitch
Wenn das Receipt positiv ist und erfoglreich zugestellt wurde, liest der Adress Service die Adresse aus der eingehenden Pathswitch-Nachricht aus und speichert sie in der Datenbank. Konnten die Informationen nicht in der Datenbank gespeichert werden, so werden sie in eine Error Queue geroutet. Bei Interesse kann die Error Queue nach Routing Keys gefultert werden, z. B. nach Partner oder Mandant
inboundErrorPathswitchExchangeName=as4.inbound.pathswitch.error
inboundErrorPathswitchHeaderName=partner
inboundErrorPathswitchHeaderValues=
Ausgehender Pathswitch
Die Queue as4.outbound.pathswitch.default ist die Bestätigung des Marktpartners, dass dieser die Adressänderung angenommen hat, und wird vom AS4 Receipt Server ausgelöst.
pathswitchOutboundExchangeName=as4.outbound.pathswitch
Die Queue as4.outbound.request.pathswitch.default startet die Bekanntmachung der eigenen Adressänderung.
pathswitchExchangeName=as4.outbound.request.pathswitch
Zugriff zur FSS REST API
Der as4 address service muss auf den FSS zugreifen können. Dies kann wie folgt in den application.properties
konfiguriert werden:
## FSS
fss.server.api.url=http://fss:2222/fss/api/v1
fss.page.size.value=100
client=shared-client
Max Concurrency - Parallelität
Für jeden Consumer ist es möglich die Eigenschaft max-concurrency
zu setzen. Diese definiert die maximale Anzahl von gleichzeitigen Verarbeitungsthreads, die für einen Consumer gestartet werden können. Der Default steht für jeden Consumer auf 50.
pathswitchOutboundMaxConcurrency=50
pathswitchInboundMaxConcurrency=50
Pfadschalter auslösen
um den Pathswitch auszulösen, wenn der Zertifikatspeicher verbraucht wird, Aktivieren Sie die folgende Eigenschaft
pathswitch-triggered-by-certificate: false # default
Automatisches Aktivieren von AS4-Beziehungen
Es besteht die Möglichkeit, eine zuvor unbestätigte Beziehung während der Nachrichtenverarbeitung automatisch zu bestätigen, wenn die AS4-Adressen auf Basis von Zertifikaten automatisch gepflegt werden und das Verschlüsselungszertifikat vorhanden ist.
Diese Funktion kann aktiviert werden, indem der folgende Parameter auf „true“ gesetzt wird. Standardmäßig ist er auf „false“ gesetzt.
autoConfirmRelation=true
Keycloak
Bei Bedarf kann die REST-API per Keycloak abgesichert werden.
In Keycloak können die Mandanten, auf die der User Zugriff hat, eingeschränkt werden. Weitere Details entnehmen Sie der Doku.
Zeitzone
Es wird empfohlen, die Server-Zeitzone auf die gewünschte Zeitzone einzustellen. Alle Server müssen die gleiche Zeitzone nutzen. Die Server-Zeitzone darf nachträglich nicht mehr geändert werden.
AS4-Adressen auf Basis von Zertifikaten automatisch pflegen
Der AS4-Address-Service kann per Message-Broker an den Certificate-Manager angebunden werden, um Certificate-Events zu verarbeiten. Er extrahiert dann automatisch AS4-Adressen. (Certificate-Events entstehen z.B. beim Download von Zertifikaten durch den Certificate-Manager.) Unter Einsatz des Certificate-Managers ist es somit nicht nötig, AS4-Adressen manuell zu pflegen. Das Event wird im Standard über die Queue certificate.store.event.default
übertragen.
Falls das Zertifikat eines Mandanten per Event empfangen und verarbeitet wird, kann auf Wunsch automatisch ein Pathswitch ausgelöst werden. Hierfür ist folgende Property zu konfigurieren:
pathswitch-triggered-by-certificate: true
Verify AMQP Tenant Header
Mit dieser Eigenschaft kann eine Prüfung beim Konsumieren des “AS4-Relation-Create”-AMQP-Events aktiviert werden. Es wird überprüft, ob die Tenant-MPID aus dem Payload mit dem Tenant aus dem Header des AMQP-Events übereinstimmen. Ist dies nicht der Fall, wird die Nachricht nicht verarbeitet und ein Fehler gelogged. Diese Funktion kann wie folgt aktiviert werden:
validateTenantHeader=true
Anhang: Gesamtkonfiguration
Folgende Konfiguration reicht in einem Standard-System aus:
application.properties
:
#--------------------- DB Connection ------------------
datasource.url=jdbc:postgresql://as4-database:5432/as4_address?currentSchema=as4_address
datasource.username=postgres
datasource.password=${DB_PASSWORD}
datasource.type=postgres
#==== RabbitMQ
rabbitmq.host=rabbitmq3
rabbitmq.port=5672
rabbitmq.username=guest
rabbitmq.password=${RABBITMQ_PASSWORD}
Allgemeine Hinweise zur Konfiguration finden Sie hier.
Anhang: Skripte zum Anlegen von Partnerbeziehungen
Mit folgendem Skript können Partnerbeziehungen aus einer csv-Datei der Adressdatenbank hinzugefügt werden.
#!/bin/bash
# This script stores all tenant-partner-relations with as4-address-service based on a csv file.
# Provide the file path as first command-line-argument: ./create-partner-relations-from-csv.sh partner-relations.csv
# The csv file should have no header line.
# Linux and windows line endings are supported.
# Only semicolon-separated values are supported.
# The csv file should be structured as follows: <tenant-code>;<partner-code>;<as4-address>
# Semicolon ; can be escaped with \.
# Text delimiter " are not supported.
# AS4-Address is optional.
# Before execution, configure the AS4_ADDRESS_SERVICE within the script.
# When oAuth2 is enabled, configure the KEYCLOAK_URL, CLIENT_ID, USERNAME and PASSWORD within the script before execution.
# Precondition: all tenants must be configured.
# stop script execution on error
set -e
AS4_ADDRESS_SERVICE_URL="http://localhost:8080/aep-as4-address-service"
# Keycloak configuration
KEYCLOAK_URL="http://host.docker.internal:9000/auth/realms/as4/protocol/openid-connect/token"
CLIENT_ID="as4-address-service"
USERNAME="admin"
PASSWORD="admin"
file_path=$1
# API-endpoint to add partner-addresses to as4 address service
PARTNER_API="${AS4_ADDRESS_SERVICE_URL}/as4-address/partner-addresses"
echo "Is Keycloak enabled? (y/n)"
read answer
if [ "$answer" = "y" ]; then
# Get keycloak access token first
auth_response=$(curl -X POST "$KEYCLOAK_URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=$CLIENT_ID" \
-d "username=$USERNAME" \
-d "password=$PASSWORD" \
-w "\n%{http_code}" \
-s)
auth_response_code=$(echo "$auth_response" | tail -n 1)
echo "Response Code of getting Keycloak access token: $auth_response_code"
access_token=$(echo $auth_response | grep -o '"access_token":"[^"]*' | grep -o '[^"]*$')
AUTHORIZATION_HEADER="Authorization: Bearer $access_token"
elif [ "$answer" = "n" ]; then
echo "Skipping token access"
AUTHORIZATION_HEADER=""
else
echo "Invalid input. Please enter y or n."
exit
fi
# read csv file for every line
while read line || [[ -n "$line" ]]; do
line="${line//$'\r'/}"
IFS=';' read -r tenantCode partnerCode address <<<"$line"
JSON_DATA="{\"tenantCode\": \"$tenantCode\", \"partnerCode\": \"$partnerCode\", \"address\": \"$address\"}"
echo "Sending POST Request for tenantCode=$tenantCode, partnerCode=$partnerCode, address=$address"
response=$(curl -X POST "$PARTNER_API" \
-H 'Content-Type: application/json' \
-H "$AUTHORIZATION_HEADER" \
-d "$JSON_DATA" \
-w "\n%{http_code}" \
-s)
# Split response into response_code and response_data
response_code=$(echo "$response" | tail -n 1)
response_data=$(echo "$response" | head -n -1)
echo "Response Code: $response_code"
echo "Response: $response_data"
echo ""
done <"$file_path"
Beispiel der csv:
tenant1;partner1;address1
tenant1;partner2;address2
tenant2;partner1
tenant3;partner1;
Import von MPID-Exports
Um die Partnerbeziehungen anhand eines MPID-Exports aus dem MPID-Editor anzulegen, kann folgendes Skript verwendet werden. Die AS4-Adresse wird dabei nicht gefüllt.
#!/bin/bash
# This script stores all tenant-partner-relations based on a csv file exported from mpid editor.
# Provide the file path as first command-line-argument: ./create-partner-relations-from-csv.sh partner-relations.csv
# The csv file should have no header line.
# Linux and windows line endings are supported.
# Only semicolon-separated values are supported.
# The csv file should be structured as follows: <tenant-code>;<partner-code>;<other-parameters>
# Semicolon ; can be escaped with \.
# Text delimiter " are not supported.
# <other-parameters> is optional and will not be imported.
# Before execution, configure the AS4_ADDRESS_SERVICE within the script.
# Precondition: all tenants must be configured.
# stop script execution on error
set -e
AS4_ADDRESS_SERVICE_URL="http://localhost:8080/aep-as4-address-service"
# Keycloak configuration
KEYCLOAK_URL="http://host.docker.internal:9000/auth/realms/as4/protocol/openid-connect/token"
CLIENT_ID="as4-address-service"
USERNAME="admin"
PASSWORD="admin"
file_path=$1
# API-endpoint to add partner-addresses to as4 address service
PARTNER_API="${AS4_ADDRESS_SERVICE_URL}/as4-address/partner-addresses"
echo "Is Keycloak enabled? (y/n)"
read answer
if [ "$answer" = "y" ]; then
# Get keycloak access token first
auth_response=$(curl -X POST "$KEYCLOAK_URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=$CLIENT_ID" \
-d "username=$USERNAME" \
-d "password=$PASSWORD" \
-w "\n%{http_code}" \
-s)
auth_response_code=$(echo "$auth_response" | tail -n 1)
echo "Response Code of getting Keycloak access token: $auth_response_code"
access_token=$(echo $auth_response | grep -o '"access_token":"[^"]*' | grep -o '[^"]*$')
AUTHORIZATION_HEADER="Authorization: Bearer $access_token"
elif [ "$answer" = "n" ]; then
echo "Skipping token access"
AUTHORIZATION_HEADER=""
else
echo "Invalid input. Please enter y or n."
exit
fi
first_line=true
# read csv file for every line
while read line || [[ -n "$line" ]]; do
if $first_line; then
#First line is header line
first_line=false
header="$line"
continue
fi
line="${line//$'\r'/}"
IFS=';' read -r tenantCode partnerCode otherParameter <<<"$line"
JSON_DATA="{\"tenantCode\": \"$tenantCode\", \"partnerCode\": \"$partnerCode\"}"
echo "Sending POST Request for tenantCode=$tenantCode, partnerCode=$partnerCode"
response=$(curl -X POST "$PARTNER_API" \
-H 'Content-Type: application/json' \
-H "$AUTHORIZATION_HEADER" \
-d "$JSON_DATA" \
-w "\n%{http_code}" \
-s)
# Split response into response_code and response_data
response_code=$(echo "$response" | tail -n 1)
response_data=$(echo "$response" | head -n -1)
echo "Response Code: $response_code"
echo "Response: $response_data"
echo ""
done <"$file_path"
Beispiel der csv:
System MPID;Partner;SA-ID;Emailadresse(Marktkommunition);Name;Gültig von;Gültig bis
9903111000003;9907647000009;;test@b2bbp.org;9907647000008;04.07.2023;28.06.2024
11223344;9907647000002;BKV;Test@test.de;Test;03.08.2023;04.08.2023
9903111000003;9900000000000;;clearing@b2bbp.org;Lieferant;16.11.2015;01.01.9999