feat(verzeichnis): SCIM-Endpunkt als dritte Quellenart (#029)
Bisher holt Laufzettel Personen aus dem Verzeichnis. Das setzt Lesezugriff und einen Netzweg dorthin voraus, und beides ist nicht ueberall gegeben. Mit der Art SCIM ruft stattdessen der Anbieter an — sofort, nicht beim naechsten Intervall. Umgesetzt ist, was authentik, Entra ID und Okta wirklich schicken: Users mit dem Filter userName eq, POST/GET/PUT/PATCH/DELETE, dazu ServiceProviderConfig, Schemas und ResourceTypes. Jeder Handler prueft sein Token selbst. Ein Token je Quelle, argon2-gehasht, einmal angezeigt — es ist der einzige Mandantenbeweis, den eine Zustellung mitbringt. DELETE deaktiviert und loescht nichts. Eine SCIM-Quelle wird nicht abgeglichen, an zwei Stellen gehalten: ein Abgleich, der dort nichts liest und ERFOLG meldet, haette ueber die Abschaltregel die ganze Belegschaft deaktiviert. Zwei Befunde kamen aus Gegenproben, nicht aus Tests: - PATCH remove wirkte gar nicht. Der Schalter nurGesetzte las bei PATCH jedes null als "nicht mitgeschickt"; eine beim Anbieter entfernte Abteilung stand hier weiter. Noetig war er nie — patchAnwenden liefert immer den vollstaendigen Zielzustand. - Entra ID schickt active als "True"/"False". Beim Deaktivieren kommt mit einem reinen value === true zufaellig das Richtige heraus, beim Aktivieren nicht: ein wieder freigeschaltetes Konto waere fuer immer inaktiv geblieben. Dazu ein Fehler aus #028: in verbindungTestenAktion stand zweimal dieselbe Bedingung, der zweite Zweig war seit dem ersten Tag unerreichbar. 1432 Tests (vorher 1373). Klickprobe am gebauten Stand mit einer echten Zustellung. Gegen echte Mandanten ist nichts gelaufen — die Anfrageformen stammen aus der Dokumentation, und das steht so in der Testdatei. Closes #49 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
76a61ec771
commit
fcd67018b8
@@ -151,6 +151,14 @@ describe.runIf(datenbankVerfuegbar)("Handgeschriebene Datenbankobjekte", () => {
|
||||
*/
|
||||
"Verzeichnisquelle_clientsecret_verschluesselt",
|
||||
"Verzeichnisquelle_felder_je_art",
|
||||
/*
|
||||
* Das SCIM-Token steht nur als argon2-Hash da (#029). Ein Token, das
|
||||
* jemand versehentlich roh speichert, faellt hier auf — und zwar in der
|
||||
* Datenbank, also auch dann, wenn jemand am Dienst vorbei schreibt.
|
||||
*/
|
||||
"Verzeichnisquelle_scimtoken_gehasht",
|
||||
// Und ein Token gehoert zu einem Zeitpunkt, in beide Richtungen.
|
||||
"Verzeichnisquelle_scimtoken_mit_zeitpunkt",
|
||||
"VorlagenVersion_veroeffentlicht_mit_zeitpunkt",
|
||||
"Zustellung_bezug_passt_zum_anlass",
|
||||
"Zustellung_empfaenger_nicht_leer",
|
||||
|
||||
+9
-5
@@ -552,10 +552,13 @@ describe.runIf(datenbankVerfuegbar)("Der Abgleich einer Graph-Quelle", () => {
|
||||
|
||||
it("weist eine SCIM-Quelle ab, statt stillschweigend nichts zu tun", async () => {
|
||||
/*
|
||||
* `SCIM` steht im Enum, weil #029 dieselbe Weiche braucht. Ein Abgleich, der
|
||||
* null Einträge liest und ERFOLG meldet, hätte über die Abschaltregel die
|
||||
* ganze Belegschaft deaktiviert — genau der Fall, der in #016 einen
|
||||
* Reviewbefund gekostet hat.
|
||||
* Dieselbe Weiche, dritter Fall. Ein Abgleich, der null Einträge liest und
|
||||
* ERFOLG meldet, hätte über die Abschaltregel die ganze Belegschaft
|
||||
* deaktiviert — genau der Fall, der in #016 einen Reviewbefund gekostet hat.
|
||||
*
|
||||
* Seit #029 ist SCIM umgesetzt, und die Antwort bleibt dieselbe: dort wird
|
||||
* nicht geholt, sondern geliefert. Die Meldung sagt das und nennt keine
|
||||
* Issue-Nummer mehr — sie steht auch in der Oberfläche.
|
||||
*/
|
||||
const { eigene } = await graphQuelleAnlegen();
|
||||
const scim = await testPrisma.verzeichnisquelle.create({
|
||||
@@ -564,7 +567,8 @@ describe.runIf(datenbankVerfuegbar)("Der Abgleich einer Graph-Quelle", () => {
|
||||
|
||||
const ergebnis = await abgleichAusfuehren(scim.id, ADMIN);
|
||||
expect(ergebnis.status).not.toBe("ERFOLG");
|
||||
expect(ergebnis.fehler).toContain("#029");
|
||||
expect(ergebnis.fehler).toMatch(/beliefert/);
|
||||
expect(ergebnis.fehler).toContain("SCIM später");
|
||||
});
|
||||
|
||||
it("liest eine LDAP-Quelle weiter über den LDAP-Weg", async () => {
|
||||
|
||||
+1111
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user