Empfangsbestätigung
Der letzte Schritt zum Empfang einer Einreichung ist die Bestätigung des Empfangs und damit auch der Gültigkeit der Einreichung. Mit Gültigkeit ist hier gemeint, dass alle Informationen erfolgreich heruntergeladen, entschlüsselt und im Falle der Metadaten validiert werden konnten.
Wie auf der Event Log Übersichtsseite zu sehen, gibt es für ein empfangendes System ein festes Set an Events, die dem Zustelldienst gesendet werden können.
Event | Autor | Bedeutung |
---|---|---|
https://schema.fitko.de/fit-connect/events/forward-submission | Ein nachgelagertes System hat die Einreichung zur Weiterleitung übernommen. | |
https://schema.fitko.de/fit-connect/events/reject-submission | Empfangendes System | Die Einreichung wurde durch den Empfänger zurückgewiesen. |
https://schema.fitko.de/fit-connect/events/accept-submission | Empfangendes System | Die Einreichung wurde durch den Empfänger akzeptiert. |
Um diese Events bzw. ein entsprechendes Event korrekt an den Zustelldienst zu versenden, muss es in Form eines SETs an diesen gesendet werden.
Die technische Empfangsbestätigung ist klar von der fachlichen Empfangsbestätigung abzugrenzen. Die fachliche Empfangsbestätigung meint hier die tatsächliche Verarbeitung durch den Adressaten, während die technische Empfangsbestätigung lediglich eine erfolgreiche technische Übermittlung bestätigt. Die fachliche Verarbeitung kann nicht über FIT-Connect nachvollzogen werden.
Erstellung und Versand eines Security Event Token (SET)
Ein Security Event Token (SET) kann dann über den Endpunkt POST /v1/cases/{caseId}/events
im zugehörigen Vorgang hinterlegt werden und ist anschließend für sendende Systeme abrufbar.
Bei der Übermittlung des SETs an den Zustelldienst wird dieses vom Zustelldienst syntaktisch und auf eine korrekte Signatur geprüft.
Sind alle Prüfungen erfolgreich durchlaufen, wird das SET im Event Log abgespeichert.
Der öffentliche Schlüssel des hierbei verwendeten Schlüsselpaares muss zuvor über das Self-Service-Portal oder über die Submission API im Zustelldienst hinterlegt werden.
Die öffentlichen und privaten Schlüssel des verwendeten Schlüsselpaares MÜSSEN dabei den Vorgaben für Signaturschlüssel entsprechen.
Der private Schlüsel (signaturePrivateKey
) MUSS sicher vom empfangenden System gespeichert werden und DARF das empfangende System NIEMALS verlassen.
Weiterhin ist es notwendig, dass die Id der Einreichung (submissionID
) und des zugehörigen Vorgangs (caseId
) bekannt sind.
Der Ausstellzeitpunkt des SET muss nach den bereits im Event Log befindlichen Einträgen, aber in der Vergangenheit liegen.
Sofern Sie den Fehler "'iat' must not be after ..." (https://schema.fitko.de/fit-connect/submission-api/problems/security-event-token-validation
) bekommen, prüfen Sie bitte folgendes:
- Ist die Systemzeit auf Ihrem System korrekt?
- Ist die Zeitzone auf Ihrem System korrekt?
- Wurde die Zeitzone richtig angewendet (UTC + Zeitzone = lokale Zeit)?
- Wird die Systemzeit mit einem NTP-Server synchronisiert?
- .NET (SDK)
- Java
Das folgende Beispiel zeigt, wie Sie das .NET-SDK nutzen, um den Empfang einer Einreichungen zu bestätigen:
await receivedSubmission.AcceptSubmissionAsync();
Das Beispiel ruft die Methode AcceptSubmissionAsync()
an der Einreichung (Submission) auf,
die zuvor vom Zustelldienst heruntergeladen wurde.
Der Aufruf der Methode setzt den Status dieser Einreichung im Zustelldienst auf accepted
.
Der Quellcode ist ein Auszug aus einem Beispiel, das zeigt, wie Sie mit dem .NET-SDK Submissions vom Zustelldienst laden.
Dieses Beispiel finden Sie auf der Seite Einreichung herunterladen.
Der Quellcode ist dem Projekt ConsoleAppExample
entnommen, das im Repository Codebeispiele - examples von FIT-Connect hinterlegt ist.
Im folgenden werden Auszüge aus dem Quellcode von Beispielen verwendet. Die vollständigen Beispiele finden Sie im entsprechenden Repository.
JWK signaturePrivateKey; // privater (geheimer) Schlüssel des für die Signaturerstellung/-prüfung genutzten Schlüsselpaares des empfangenden Systems
JWK signaturePublicKey; // öffentlicher Schlüssel des für die Signaturerstellung/-prüfung genutzten Schlüsselpaares des empfangenden Systems
String issuer = "943da3e2-c178-4b63-aa2d-2fe964b0e09d"; // our own destinationId (MUST match destinationId of this submission)
String subject = "submission:f65feab2-4883-4dff-85fb-169448545d9f"; // submissionId
String event ="https://schema.fitko.de/fit-connect/events/accept-submission";
String transactionId = "case:f73d30c6-8894-4444-8687-00ae756fea90"; // caseId
Map<> payload = ...; // payload passend zum Event
Der folgende Code kann zur Validierung des Schlüssels benutzt werden.
public static void validateRSAKey(RSAKey RSAKey, boolean isPrivate){
validateTrueOrElseThrow(RSAKey.getModulus().decodeToBigInteger().bitLength() >= 4096, "JWK has wrong key length.");
validateTrueOrElseThrow(RSAKey.getAlgorithm().equals(JWSAlgorithm.PS512), "The specified public key does not use PS512 as algorithm.");
if(isPrivate){
validateTrueOrElseThrow(RSAKey.getKeyOperations().size() == 1 &&
RSAKey.getKeyOperations().contains(KeyOperation.SIGN),
"The specified private key is not intended for 'sign' as specified through key operation.")
}
else{
validateTrueOrElseThrow(RSAKey.getKeyOperations().size() == 1 &&
RSAKey.getKeyOperations().contains(KeyOperation.VERIFY),
"The specified public key is not intended for 'verify' as specified through key operation.")
};
validateTrueOrElseThrow(RSAKey.getPublicExponent().toString().equals("AQAB"), "The specified public key does not match the public exponent 'AQAB'.");
}
private static void validateTrueOrElseThrow(boolean expression, String msg) {
if (!expression) {
throw new RuntimeException(msg);
}
}
Die Payload- und Header-Attribute des SETs müssen wie oben beschrieben definiert werden (siehe markierte Zeilen). Mehr Informationen zu dem SET-Aufbau finden Sie unter SET Erzeugen
Im folgenden Block wird das SET mit dem Schlüssel signiert. Anschließend kann der serialisierte Wert an den Endpunkt POST /v1/cases/{caseId}/events
gesendet werden.
// Schlüssel validieren
validateRSAKey(key.toRSAKey(), true);
try {
JWSSigner signer = new RSASSASigner(signaturePrivateKey.toRSAKey());
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.issuer(issuer)
.issueTime(new Date())
.jwtID(UUID.randomUUID().toString())
.subject(subject)
.claim("events", Map.of(event, payload == null ? Map.of() : payload))
.claim("txn", transactionId)
.build();
JWSHeader header = JWSHeader.parse(Map.of(
"typ", "secevent+jwt",
"kid", signaturePrivateKey.getKeyID(),
"alg", "PS512"
));
SignedJWT signedJWT = new SignedJWT(
header,
claimsSet);
signedJWT.sign(signer);
String signedAndSerializedSET = signedJWT.serialize(); // => SET, serialized as Base64 encoded string
} catch (JOSEException e) {
throw new RuntimeException("Could not generate SET");
}
Event Log abfragen
Auch empfangende Systeme können das Event Log abfragen. Die Abfrage des Event Log erfolgt analog zur Abfrage für sendende Systeme und ist im Artikel Status abfragen beschrieben.