Newer
Older
# OSIv2-Postfach-Anbindung für OZG-Cloud-Nachrichten
Senden und Empfangen von Postfach-Nachrichten über die OSI-Postfach-Facade 2.0 (OPF).
Das Maven-Artefakt `osiv2-postach` kann in ein Spring-Boot eingebunden werden.
Die Spring-Bean `osiPostfachRemoteService` mit dem Interface
`PostfachRemoteService` kann mit `ozgcloud.osiv2.enabled: true` aktiviert werden.
## Konfiguration
Um auf die Postfach-Facade zugreifen zu können, muss der Client sich beim Servicekonto anmelden.
Hierzu wird `ozgcloud.osiv2.auth` konfiguriert, wie bspw. hier für Stage-Schleswig-Holstein:
```yaml
client-id: 'OZG-Kopfstelle-SH'
client-secret: 'changeme'
scope: default, access_urn:dataport:osi:sh:stage:ozgkopfstelle
token-uri: 'https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token'
resource: 'urn:dataport:osi:postfach:rz2:stage:sh'
```
Für die Postfach-Facade muss zudem die URL, der Tenant, und der SAML-Name-Identifier konfiguriert werden.
Beim Nachschlagen des Postfachs der Antragsteller*in wird ein Postfach mit übereinstimmenden Tenant präferiert.
Zudem werden Tenant und SAML-Name-Identifier beim Upload von Anhängen angegeben.
Hierzu wird `ozgcloud.osiv2.api` konfiguriert:
```yaml
url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0'
tenant: 'SH'
name-identifier: 'ozgkopfstelle'
```
<small>(Der Wert von `name-identifier` wird momentan nicht von der Postfach-Facade geprüft.)</small>
## Senden einer Postfach-Nachricht
Der Aufruf `sendMessage(PostfachNachricht)` sendet eine Nachricht an die Antragsteller*in. Jede Nachricht ist stets in Bezug zu einem Vorgang.
1. Mit dem SAML-Name-Identifier der Antragsteller*in wird ein Postfach nachgeschlagen, welches die Nachricht empfangen soll.
2. Vor dem Senden der Nachricht werden alle Anhänge in die Quarantäne hochgeladen und auf Viren geprüft.
3. Nach dem erfolgreichen Hochladen der Anhänge wird die Nachricht an das Postfach gesendet.
```mermaid
%% Senden einer Nachricht
sequenceDiagram
participant N as nachrichten-manager
participant A as file-manager
participant B as Client
participant C as OPF
activate N
N->>B: OsiPostfachRemoteService::sendMessage
activate B
Note left of B: (1) Nachschlagen einer Empfänger-Postfach-Adresse
B->>C: POST /MailboxDirectory/v1/Lookup
activate C
C-->>B: {mailboxId}
deactivate C
Note left of B: (2) Hochladen der Anhänge
B->>A: GRPC findBinaryFilesMetaData
A-->>B: {Liste an Anhang-Metadaten}
loop Für jeden Anhang
B->>A: GRPC GetBinaryFileContent
loop Für jeden Daten-Chunk
B->>C: POST /Quarantine/v1/Upload/Chunked (chunk)
activate C
end
A-->>B:
B->>C: POST /Quarantine/v1/Upload/Chunked (empty chunk)
end
loop Regelmäßiges Polling bis alle Anhänge geprüft sind
B->>C: GET /Quarantine/v1/Upload/{guid}
activate C
C-->>B:
deactivate C
B->>C: POST /MessageExchange/v1/Send/{mailboxId}
C-->>B:
deactivate C
B-->>N:
deactivate B
deactivate N
```
## Empfangen von Postfach-Nachrichten
Der Aufruf `getAllMessages()` holt alle Nachrichten, die an das OZG-Cloud-Postfach gerichtet sind ab.
1. Es wird eine Liste an Nachrichten-Kennungen abgerufen.
2. Für jede Nachricht wird die Nachricht abgerufen und die Anhänge heruntergeladen.
3. Ein Stream an Nachrichten wird zurückgegeben. Anhand der Vorgangs-Kennung lässt sich jede Nachricht stets einem Vorgang zugordnen.
sequenceDiagram
participant N as nachrichten-manager
participant A as file-manager
participant B as Client
participant C as OPF
activate N
N->>B: OsiPostfachRemoteService::getAllMessages
B->>C: GET /MessageExchange/v1/Receive
C-->>B: {Liste an Nachrichten-Kennungen (max 100)}
loop Für jede Nachrichten-Kennung (messageId)
Note left of B: (1) Nachricht abrufen
B->>C: GET /MessageExchange/v1/Receive/{messageId}
C-->>B: {Nachricht mit Anhang-Metadaten}
Note left of B: (2) Herunterladen der Anhänge
loop Für jeden Anhang
B->>C: GET /MessageExchange/v1/Receive/{messageId}/Attachment/{attachmentId}
B->>A: GRPC UploadBinaryFileAsStream
Note left of B: (3) Bereitstellung der Postfach-Nachricht
B-->>N: {Postfach-Nachricht als Stream-Element}
end
deactivate B
deactivate N
```
Der nachrichten-manager erhält beim Aufruf von `getAllMessages` einen Stream von Postfach-Nachrichten. Nach der erfolgreichen Verarbeitung einer Nachricht sollte er `deleteMessage` aufrufen:
```mermaid
%% Empfangen einer Nachricht
sequenceDiagram
participant N as nachrichten-manager
participant B as Client
participant C as OPF
activate N
N->>B: OsiPostfachRemoteService::deleteMessage
B->>C: GET /MessageExchange/v1/Delete/{messageId}
C->>B:
deactivate C
B-->>N:
deactivate B
deactivate N
```
## Client-Authentifizierung beim Servicekonto
Die Client-Authentifizierung beim Authentication-Server (Servicekonto) erfolgt über den OAuth2-Client-Credentials-Flow (siehe [RFC 6749, Sec. 1.3.4](https://www.rfc-editor.org/rfc/rfc6749#section-1.3.4))
mit `client_id` und `client_secret` in Verbindung mit einem Resource-URI-Parameter (siehe [RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)), der den Zugriff des Clients auf den Resource-Server (Postfach-Facade) einschränkt.
Der Resource-Server liest die Resource-URI aus dem `aud`-Claim (siehe [RFC 9068, Sec. 3](https://datatracker.ietf.org/doc/html/rfc9068#section-3) und [ServicePortal-Dokumentation](https://idp.serviceportal-stage.hamburg.de/doc/external/articles/OIDC/OIDC-Protokoll.html)).
### Beispiel:
```bash
curl -v --output auth_response.json \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=OZG-Kopfstelle-SH" \
--data-urlencode "client_secret=${SH_STAGE_CLIENT_SECRET}" \
--data-urlencode "scope=default access_urn:dataport:osi:sh:stage:ozgkopfstelle" \
--data-urlencode "resource=urn:dataport:osi:postfach:rz2:stage:sh" \
https://idp.serviceportal-stage.schleswig-holstein.de/webidp2/connect/token
```
**Beobachtungen:**
- <small>Mit einem ungültigen `resource`-Parameter kommt ein `invalid_target`-Fehler bei der Token-Erstellung.</small>
- <small>Ohne `resource`-Parameter (d.h. ohne `aud`-Claim) kommt `401 Unauthorized` von der Postfach-Facade.</small>
- <small>Ohne `default`-Scope kommt ein `invalid_target`-Fehler bei der Token-Erstellung</small>
- <small>Ohne `access_urn:dataport:osi:sh:stage:ozgkopfstelle`-Scope kommt ein `Internal Server Error 500` von der Postfach-Facade.</small>