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>
16 KiB
Verzeichnis anbinden
Unter Admin → Verzeichnis wird ein Active Directory als Quelle der Personen eingerichtet. Dann
muss beim Start eines Laufs nichts abgetippt werden, und {{vorname}}, {{upn}}, {{sam}} und
{{abteilung}} stehen von selbst zur Verfügung.
Zwei Dinge vorweg:
- Der Reiter gibt es nur im Modus Intern. Dort hat das Haus ein Verzeichnis, aus dem seine Leute kommen. Im Modus Dienstleistung wären es Verzeichnisse fremder Kunden, und die bindet Laufzettel ausdrücklich nicht an — dort kommen Personen von Hand oder per CSV.
- Laufzettel schreibt nie ins Verzeichnis. Ein Dienstkonto mit Leserechten genügt. Gespeichert werden nur die zugeordneten Felder — keine Passwörter, keine Gruppenmitgliedschaften.
Wer im Verzeichnis verschwindet oder dort deaktiviert wird, wird hier inaktiv. Gelöscht wird nie, sonst verlöre die Historie ihre Namen.
Drei Arten von Quelle
Laufzettel braucht die Personen aus einem Verzeichnis. Dafür gibt es drei Wege, und du wählst ihn beim Anlegen der Quelle:
| Art | Für wen | Richtung |
|---|---|---|
| LDAP | ein lokales Active Directory (oder ein anderes LDAP-Verzeichnis) | Laufzettel holt |
| Microsoft Graph | Entra ID, also Microsoft 365 — für Häuser ohne lokales AD | Laufzettel holt |
| SCIM | authentik, Entra ID, Okta — wenn Laufzettel nicht ins Verzeichnis sehen soll oder es nicht erreicht | der Anbieter schickt |
Die ersten zwei sind dieselbe Arbeitsweise mit anderen Zugangsdaten: Laufzettel verbindet sich nach Zeitplan und liest. SCIM ist die andere Richtung — dort gibt es keine Zugangsdaten, keinen Zeitplan und keinen Verbindungstest; der Anbieter schickt jede Änderung in dem Moment, in dem sie dort entsteht. Für SCIM gibt es einen eigenen Abschnitt weiter unten.
Alle drei verhalten sich danach gleich: anlegen, aktualisieren, deaktivieren, nie löschen. Was LDAP und Graph unterscheidet, sind die Zugangsdaten und zwei Platzhalter:
{{ou}}bleibt bei Graph leer. Entra ID hat keine OU. Steht an der Abteilung eine Ziel-OU gepflegt, nimmt Laufzettel die; sonst bleibt der Platzhalter stehen.{{sam}}ist bei Graph leer, wenn der Mandant kein lokales AD synchronisiert — dort gibt es keinen Anmeldenamen in diesem Sinn.
Die Art lässt sich nachträglich nicht ändern. An ihr hängt, was die dauerhafte Kennung einer Person bedeutet; nach einem Wechsel würde niemand mehr wiedererkannt, und der nächste Abgleich legte alle neu an. Wer wechseln muss, legt eine zweite Quelle an und lässt die erste stehen.
Was in Entra ID einzurichten ist — App-Registrierung, Berechtigung, Einwilligung — steht in
docs/betrieb/entra-id.md.
SCIM: der Anbieter schickt
Bei den ersten zwei Arten fragt Laufzettel das Verzeichnis. Bei SCIM ist es umgekehrt: der Identitätsanbieter ruft Laufzettel an, sobald sich bei ihm etwas ändert. Das ist der Weg für zwei Lagen:
- Das Haus will Laufzettel keinen Lesezugriff auf sein Verzeichnis geben.
- Laufzettel läuft in einem Netz, das das Verzeichnis nicht erreicht — ein Push von außen nach innen geht, ein Lesezugriff von innen nach außen nicht.
Was anders ist
| LDAP und Graph | SCIM | |
|---|---|---|
| Zugangsdaten | Dienstkonto bzw. App-Registrierung | keine — ein Token für den Anbieter |
| Zeitplan | alle n Minuten | keiner, es kommt sofort |
| Verbindung testen | zeigt die ersten zehn Treffer | gibt es nicht — es gibt keine Verbindung |
| Abgleich-Log | je Lauf eine Zeile | gibt es nicht; stattdessen letzte Zustellung |
| Attributzuordnung | einstellbar | fest, der Anbieter bestimmt die Feldnamen (RFC 7643) |
{{ou}} |
aus dem DN bzw. der Abteilung | leer — SCIM kennt keine OU |
Was Laufzettel übernimmt: Anmeldename (userName), Vor- und Nachname, Anzeigename, Mailadresse,
Titel, Abteilung, der Vorgesetzte und ob das Konto aktiv ist. Mehr nicht — keine Gruppen, keine
Rollen, keine Passwörter.
Einrichten: Laufzettel zuerst
- Quelle anlegen. Unten auf der Seite Art → SCIM (wird geliefert) wählen, einen Namen geben (etwa „authentik Push“), Zustellungen annehmen anhaken und speichern. Mehr Felder gibt es nicht.
- Token erzeugen. An der neuen Quelle steht Token erzeugen. Es erscheint genau einmal — kopier es sofort. Gespeichert wird es nur als Hash; ein zweites Ansehen gibt es nicht. Wer es verliert, erzeugt ein neues, und das alte gilt dann nicht mehr.
- Adresse ablesen. Unter dem Namen der Quelle steht die Adresse, die der Anbieter braucht, etwa
https://laufzettel.firma.de/api/scim/v2.
Einrichten in authentik
Unter Applications → Providers → Create → SCIM Provider:
| Feld | Wert |
|---|---|
| Name | etwa „Laufzettel“ |
| URL | die Adresse von oben, also https://…/api/scim/v2 |
| Token | das erzeugte Token, unverändert eingefügt |
Bei User filtering wählst du die Gruppe, deren Mitglieder in Laufzettel stehen sollen — nicht
alle Konten, sondern die Menschen, für die Läufe entstehen. Unter Attribute mapping genügen die
Vorgaben; authentik schickt userName, name, emails und die Erweiterung
enterprise:2.0:User von selbst.
Danach Save und einmal Sync auslösen. In Laufzettel steht dann an der Quelle Letzte Zustellung am … und die Personen stehen unter Mitarbeiter.
Einrichten in Entra ID
Unter Entra ID → Enterprise applications → New application → Create your own application → Integrate any other application you don't find in the gallery. Dann in der neuen Anwendung Provisioning → New configuration:
| Feld | Wert |
|---|---|
| Tenant URL | die Adresse von oben, also https://…/api/scim/v2 |
| Secret Token | das erzeugte Token |
Test Connection muss grün werden — Entra ID fragt dabei ServiceProviderConfig, Schemas und
ResourceTypes ab und legt probeweise niemanden an. Danach unter Users and groups die Gruppe
zuweisen und das Provisioning auf On stellen.
Zwei Eigenheiten von Entra ID, die hier nicht stören, aber erklären, was in den Protokollen steht:
- Entra ID schickt
activeals Zeichenkette"True"/"False", nicht alstrue/false. Laufzettel liest beides. - Der erste vollständige Durchlauf beginnt bis zu 40 Minuten nach dem Einschalten. Das ist Entra ID und nichts, was sich hier beschleunigen ließe.
Löschen beim Anbieter heißt hier inaktiv
Nimmt jemand eine Person beim Anbieter aus der zugewiesenen Gruppe oder löscht sie dort, schickt
der Anbieter ein DELETE. Laufzettel setzt die Person dann auf inaktiv und löscht nichts. Die
Zeile bleibt, weil Läufe und Geräte an ihr hängen: ein archivierter Lauf muss auch in zehn Jahren
noch sagen können, für wen er lief.
Der Anbieter bekommt 204 und hält die Person damit für entfernt — aus seiner Sicht richtig, denn
sie wird ihm nicht mehr zugewiesen. In Laufzettel steht sie weiter in der Liste, inaktiv. Das
sieht aus wie ein Fehler und ist keiner. Wer sie aus der Ansicht haben will, filtert auf „nur
aktive“ — das ist die Vorgabe der Mitarbeiterliste.
Wenn nichts ankommt
| Was der Anbieter meldet | Woran es liegt |
|---|---|
401 |
Das Token stimmt nicht, oder Zustellungen annehmen ist nicht angehakt. Beides ergibt dieselbe Antwort — absichtlich. |
404 auf eine bekannte Person |
Die Person gehört zu einer anderen Quelle. Jedes Token sieht nur die Personen seiner eigenen. |
409 beim Anlegen |
Die Person gibt es in dieser Quelle schon. Der Anbieter fragt normalerweise vorher mit einem Filter; schickt er trotzdem, ist 409 die richtige Antwort und kein Datenverlust. |
400 invalidFilter |
Der Anbieter benutzt einen Filter, den Laufzettel nicht unterstützt — nur userName eq "…" geht. |
| nichts, Zeitüberschreitung | Der Reverse Proxy lässt /api/scim/ nicht durch, oder TLS stimmt nicht. Siehe docs/betrieb/scim.md. |
Eine Quelle stilllegen, ohne das Token beim Anbieter zu löschen: Häkchen Zustellungen
annehmen entfernen. Der Endpunkt antwortet dann mit 401, und beim Anbieter stehen die
Zustellungen als Fehler — sie gehen nicht verloren, er versucht es erneut.
Eine Quelle anlegen
Das Formular Quelle anlegen steht unten auf der Seite. Die Felder:
| Feld | Was hinein gehört |
|---|---|
| Name | wie du die Quelle nennst, etwa „Firmen-AD“ |
| Adresse | ldaps://dc01.firma.local:636 — nur Schema, Rechner und Port |
| Anmelde-DN | das Dienstkonto, etwa CN=laufzettel,OU=Dienstkonten,DC=firma,DC=local |
| Passwort | wird verschlüsselt gespeichert und nie wieder angezeigt |
| Basis-DN | wo gesucht wird, etwa OU=Benutzer,DC=firma,DC=local |
| Filter (optional) | leer lassen nimmt den Standard: aktive Personenkonten |
| Abgleich alle … Minuten | zwischen 5 und 10080 (fünf Minuten bis eine Woche) |
| Nach Zeitplan abgleichen | das Häkchen schaltet den Zeitplan ein |
Für die Adresse gibt es drei Formen:
ldaps://host:636— verschlüsselt ab dem ersten Byte. Die richtige Wahl.ldap+starttls://host:389— unverschlüsselt verbunden und dann hochgestuft.ldap://host:389— im Klartext. Sobald du das eintippst, warnt das Formular: dann geht auch das Bind-Passwort im Klartext über das Netz. Für ein Dienstkonto im Active Directory ist das keine gute Idee.
In die Adresse gehören kein Pfad und keine Zugangsdaten. Der Basis-DN hat sein eigenes Feld,
Bind-DN und Passwort ebenso; Laufzettel weist eine Adresse mit / oder @ dahinter ausdrücklich ab.
Der Standardfilter schließt deaktivierte Konten aus. Das ist der Sinn: wer aus dem Ergebnis verschwindet, wird hier deaktiviert. Ein eigener Filter engt weiter ein, etwa auf eine einzelne OU.
Dann Quelle anlegen.
Attributzuordnung
Hinter Attributzuordnung anpassen steht, welches Verzeichnis-Attribut auf welches Feld geht. Die Vorgaben sind die Namen eines Active Directory:
| Feld | Vorgabe |
|---|---|
| Vorname | givenName |
| Nachname | sn |
| Anzeigename | displayName |
mail |
|
| UPN | userPrincipalName |
| Anmeldename (sam) | sAMAccountName |
| Abteilung | department |
| Titel | title |
| Vorgesetzter | manager |
| Kennung (dauerhaft) | objectGUID |
Ein OpenLDAP heißt an einigen Stellen anders — dort ist die dauerhafte Kennung etwa entryUUID.
Leer gelassene Felder bekommen die Vorgabe zurück.
Die Kennung ist das eine Feld, das später nicht mehr geändert werden sollte. An ihr erkennt der Abgleich eine Person wieder. Ein anderer Wert legt beim nächsten Lauf alle Personen neu an.
Eigenes CA-Zertifikat
Nur nötig, wenn der Domänencontroller ein Zertifikat aus einer eigenen CA trägt. Hinter Eigenes
CA-Zertifikat hinterlegen fügst du den PEM-Text ein, beginnend mit
-----BEGIN CERTIFICATE-----. Ohne Eintrag gelten die Wurzelzertifikate des Systems.
Ist eines hinterlegt, sagt die Seite das. Das Feld bleibt beim Bearbeiten trotzdem leer: Text eintragen ersetzt es, leer lassen behält es, und das Häkchen Hinterlegtes Zertifikat entfernen nimmt es weg. Beides zugleich ergibt keinen Sinn und wird abgewiesen.
Dasselbe gilt für das Passwort: leer lassen behält das gespeicherte. Sonst nähme jede Namensänderung der Quelle ihre Anmeldung.
Verbindung testen
Die folgenden vier Abschnitte gelten für LDAP und Graph. Bei einer SCIM-Quelle gibt es weder Verbindungstest noch Zeitplan noch Abgleich-Log — dort steht an ihrer Stelle die letzte Zustellung, siehe oben.
Verbindung testen liest die ersten Einträge und zeigt sie so, wie sie ankämen — gespeichert wird nichts. Mach das immer vor dem ersten Abgleich. Klappt es nicht, steht der Grund in Rot darunter; die häufigsten stehen in Kapitel 08.
Der Wert steckt nicht im „geht“, sondern in der Liste darunter: erst an den zugeordneten Feldern
siehst du, ob die Zuordnung stimmt. Ein grünes „Verbindung erfolgreich“ sähe genauso aus, wenn sam
und upn vertauscht wären — und der Fehler fiele erst auf, wenn ein PowerShell-Befehl den falschen
Anmeldenamen trägt.
Prüf also Zeile für Zeile: Steht unter UPN wirklich der UPN? Unter sam der Anmeldename? Ist die Abteilung genau der Name, unter dem du die Abteilung gepflegt hast?
Ein Vorgesetzter erscheint im Test nur, wenn er zufällig unter diesen Einträgen ist. Beim vollständigen Abgleich wird er aufgelöst.
Zeitplan und „Jetzt abgleichen“
Ist Nach Zeitplan abgleichen gesetzt, läuft der Abgleich von selbst im gewählten Intervall; an der Quelle steht dann „alle 60 min“, sonst „kein Zeitplan“.
Jetzt abgleichen startet ihn sofort — nach einer Änderung am Filter will niemand bis zur nächsten vollen Stunde warten. Es ist derselbe Vorgang, den auch der Zeitplan ruft, es gibt also keinen zweiten Weg mit eigenen Regeln.
Läuft für diese Quelle gerade schon ein Abgleich, sagt Laufzettel das und tut nichts: „Für … läuft gerade schon ein Abgleich. Bitte das Ergebnis abwarten.“
Was der Abgleich tut
- Er liest das Verzeichnis in Seiten von je tausend Einträgen.
- Jeder Eintrag wird über die Kennung wiedererkannt und aktualisiert, oder neu angelegt.
- Eine von Hand angelegte Person wird über
upnodersamgefunden und übernommen, nicht verdoppelt. Genau so ist das Onboarding gedacht: die Person entsteht hier, das AD-Konto danach. - Erst nach einem vollständigen Durchlauf wird deaktiviert, wer nicht wiedergesehen wurde. Ein Netzwerkfehler nach der halben Liste soll nicht die andere Hälfte der Firma abschalten.
Drei Sicherungen, die alle denselben Fehler verhindern — dass eine kaputte Eingabe wie „alle sind gegangen“ aussieht:
- Ließ sich kein einziger Eintrag zuordnen, gilt der Abgleich als gescheitert und es wird niemand deaktiviert. Die Meldung sagt: „Niemand wurde deaktiviert. Prüf die Attributzuordnung, besonders das Kennungsattribut.“
- Übersprungene Einträge sind nicht verschwunden und werden aus der Abschaltung herausgenommen.
- Eine Person, die schon eine andere Quelle führt, wird nie übernommen.
Der Abgleich läuft nicht in einer Transaktion. Bricht er in der Mitte ab, bleiben die bis dahin geschriebenen Personen stehen — ein zweiter Lauf holt den Rest.
Das Abgleich-Log
An der Quelle steht der letzte Stand: „Zuletzt abgeglichen am …“ oder „Letzter Abgleich gescheitert“ mit der Meldung dazu.
Hinter Abgleich-Log stehen die letzten Läufe mit Zeitpunkt, wer sie ausgelöst hat (steht dort Zeitplan, war es niemand von Hand — das ist der Regelfall) und der Bilanz:
| Zahl | Bedeutung |
|---|---|
| gelesen | Einträge, die aus dem Verzeichnis kamen |
| angelegt | neue Personen |
| übernommen | von Hand angelegte Personen, die jetzt am Verzeichnis hängen |
| aktualisiert | vorhandene Personen mit geänderten Feldern |
| deaktiviert | nicht mehr wiedergesehene Personen |
| übersprungen | Einträge, die sich nicht zuordnen ließen |
Nullen werden gezeigt. „0 angelegt, 0 aktualisiert“ ist die Auskunft, dass der Abgleich lief und sich im Verzeichnis nichts geändert hat. Fehlte die Zeile, sähe ein erfolgreicher Lauf ohne Änderung aus wie ein Lauf, der nie stattfand.
Übersprungene Einträge sind kein Fehler der Quelle, sondern einzelne krumme Konten — sie stehen deshalb als Hinweis und nicht als Fehler da. Steigt die Zahl, prüf die Attributzuordnung.
Ohne Verzeichnis
Eine Quelle ist keine Voraussetzung. Personen lassen sich von Hand anlegen oder aus einer CSV-Datei einlesen — ein Verzeichnis nimmt nur die Arbeit ab. Siehe Kapitel 05.
Von Hand angelegte Personen gehen dabei nicht verloren, wenn später eine Quelle dazukommt: taucht jemand mit demselben Anmeldenamen aus dem Verzeichnis oder per SCIM auf, übernimmt Laufzettel die vorhandene Zeile statt eine zweite anzulegen. Ihre Läufe und Geräte bleiben an ihr hängen.


