Skip to content
Snippets Groups Projects

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:

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:

url: 'https://api-gateway-stage.dataport.de:443/api/osi_postfach/1.0.0'
tenant: 'SH'
name-identifier: 'ozgkopfstelle'

(Der Wert von name-identifier wird momentan nicht von der Postfach-Facade geprüft.)

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.
%% 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
    activate A
    A-->>B: {Liste an Anhang-Metadaten}
    deactivate A
    loop Für jeden Anhang
      B->>A: GRPC GetBinaryFileContent
      activate A
      loop Für jeden Daten-Chunk
        B->>C: POST /Quarantine/v1/Upload/Chunked (chunk)
        activate C
        C-->>B: 
        deactivate C
      end
      A-->>B: 
      deactivate A
      B->>C: POST /Quarantine/v1/Upload/Chunked (empty chunk)
      activate C
      C-->>B: 
      deactivate C
    end
    loop Regelmäßiges Polling bis alle Anhänge geprüft sind
      loop Für jeden Anhang
        B->>C: GET /Quarantine/v1/Upload/{guid}
        activate C
        C-->>B: 
        deactivate C
      end
    end
    Note left of B: (3) Nachricht senden
    B->>C: POST /MessageExchange/v1/Send/{mailboxId}
    activate C
    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.
%% Empfangen von Nachrichten
  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
    activate B
    B->>C: GET /MessageExchange/v1/Receive
    activate C
    C-->>B: {Liste an Nachrichten-Kennungen (max 100)}
    deactivate C
    loop Für jede Nachrichten-Kennung (messageId)
      Note left of B: (1) Nachricht abrufen
      B->>C: GET /MessageExchange/v1/Receive/{messageId}
      activate C
      C-->>B: {Nachricht mit Anhang-Metadaten}
      deactivate C
      Note left of B: (2) Herunterladen der Anhänge
      loop Für jeden Anhang
        B->>C: GET /MessageExchange/v1/Receive/{messageId}/Attachment/{attachmentId}
        activate C
        B->>A: GRPC UploadBinaryFileAsStream
        activate A
        A-->>B: 
        deactivate A
        C-->>B: 
        deactivate C
      end
      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:

%% Empfangen einer Nachricht
  sequenceDiagram
    participant N as nachrichten-manager
    participant B as Client
    participant C as OPF
    
    activate N
    N->>B: OsiPostfachRemoteService::deleteMessage
    activate B
    B->>C: GET /MessageExchange/v1/Delete/{messageId}
    activate C
    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) mit client_id und client_secret in Verbindung mit einem Resource-URI-Parameter (siehe RFC 8707), 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 und ServicePortal-Dokumentation).

Beispiel:

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:

  • Mit einem ungültigen resource-Parameter kommt ein invalid_target-Fehler bei der Token-Erstellung.
  • Ohne resource-Parameter (d.h. ohne aud-Claim) kommt 401 Unauthorized von der Postfach-Facade.
  • Ohne default-Scope kommt ein invalid_target-Fehler bei der Token-Erstellung
  • Ohne access_urn:dataport:osi:sh:stage:ozgkopfstelle-Scope kommt ein Internal Server Error 500 von der Postfach-Facade.