CodamAIDocs
Themafertig

Die Keycloak-Erweiterung für den Passwort-Link

Ein Jar, das in Keycloak läuft und den signierten Link zurückgibt, statt ihn selbst zu mailen. Was ohne die Erweiterung passiert.

Ausprägungen
Erweiterung installiert: LinkErweiterung fehlt: kein LinkKonto unbekanntAnfrage abgelehntClient nicht freigegebenSpeicher-Adapter statt KeycloakKeycloak mit --optimized gestartet

Worum es geht

Ein Konto, das CIAS anlegt, hat kein Passwort. CIAS nimmt nie eines entgegen. Die Person soll es selbst bei Keycloak setzen, auf der Seite von Keycloak.

Nur: Wie kommt sie dorthin? Die Pflichtaktion „Passwort setzen“ (UPDATE_PASSWORD) hilft allein nicht. Keycloak fragt Pflichtaktionen erst nach der Anmeldung ab, und ohne Passwort kann sich niemand anmelden. Übrig bliebe nur „Passwort vergessen“.

Keycloak kann einen Einmal-Link ausstellen, der genau dieses Problem löst. Er gilt einmal, läuft ab, gehört zu einem Konto, einer Liste von Aktionen, einem Client und einer Rücksprungadresse. Keycloak signiert ihn mit dem Schlüssel des Realms, also kann ihn niemand außerhalb von Keycloak bauen, auch CIAS nicht. Aber Keycloaks eigene Admin-API liefert diesen Link nur in einer Mail, die Keycloak selbst verschickt, mit Keycloaks Text und Keycloaks Absender.

Die Erweiterung ist kein Adapter. Der Adapter (cias-iam-keycloak) läuft in CIAS und ruft sie über HTTP auf. Die Erweiterung ist das andere Ende dieses Aufrufs, im Server von Keycloak.

Der Ablauf

sequenceDiagram
    participant C as CIAS
    participant K as Keycloak
    participant X as Erweiterung in Keycloak
    participant M as E-Mail
    participant B as Benutzer
    C->>K: Konto freischalten, UPDATE_PASSWORD verlangen
    C->>X: POST /admin/realms/{realm}/cias-action-links
    X->>X: prüft Aufrufer, Konto, Aktionen, Client, Rücksprungadresse
    X-->>C: Link und Ablaufzeit
    C->>M: Mail mit dem Link, in CIAS' eigener Vorlage
    M-->>B: Mail
    B->>K: öffnet den Link
    K-->>B: Seite „Neues Passwort“
    B->>K: Passwort setzen
    K-->>B: weiter zur Rücksprungadresse, also zur Anmeldung der Anwendung

CIAS sieht dabei nie ein Passwort. Es trägt nur den Link zur Person, so wie es auch den Bestätigungslink einer Registrierung trägt.

Anfrage und Antwort

Anfrage
POST /admin/realms/codamai/cias-action-links
Authorization: Bearer <Token des Dienstkontos cias-admin>
{
  "userId": "5c9e…",
  "actions": ["UPDATE_PASSWORD"],
  "clientId": "hub-frontend",
  "redirectUri": "https://app.example.com/login",
  "lifespan": 86400
}
Antwort
HTTP 200
{
  "link": "https://sso.example.com/realms/codamai/login-actions/action-token?key=…",
  "expiresAt": "2026-09-23T09:14:03Z"
}
FeldBedeutung
userIddas Konto in Keycloak
actionsdie Pflichtaktionen, durch die der Link führt, in dieser Reihenfolge
clientIdder Client der Oberfläche, bei der sich die Person danach anmeldet
redirectUriwohin es nach dem Passwort geht; muss zu diesem Client passen
lifespanGültigkeit in Sekunden, höchstens 72 Stunden; fehlt sie, gilt die Einstellung des Realms für Links, die ein Administrator auslöst, ebenfalls gekappt auf 72 Stunden
linkder Einmal-Link
expiresAtwann er abläuft

Was die Erweiterung prüft

Die Erweiterung sitzt unter /admin/realms/{realm}. Keycloak prüft deshalb das Token des Aufrufers, bevor ihr Code überhaupt läuft. Danach prüft sie selbst:

Von der Anfrage zum Link
  1. Keycloak
    Anmeldung
    Gültiges Token für die Admin-API?
    ↳ nein 401
  2. Keycloak
    Aufrufer
    Steht der Client, für den das Token ausgestellt ist, in der Serveroption allowed-clients?
    ↳ nein 403, bevor irgendetwas anderes geprüft wird
  3. Keycloak
    Pflichtfelder
    Sind Konto und mindestens eine Aktion genannt?
    ↳ nein 400
  4. Keycloak
    Konto
    Gibt es das Konto in diesem Realm?
    ↳ nein 404
  5. Keycloak
    Recht
    Darf der Aufrufer dieses Konto verwalten? Dasselbe Recht wie für Keycloaks eigene Mail.
    ↳ nein 403
  6. Keycloak
    Konto nutzbar
    Hat das Konto eine E-Mail-Adresse und ist es freigeschaltet?
    ↳ nein 400
  7. Keycloak
    Aktionen
    Ist jede Aktion erlaubt (UPDATE_PASSWORD, UPDATE_PROFILE, TERMS_AND_CONDITIONS), ist UPDATE_PASSWORD dabei, und ist jede Aktion im Realm eingeschaltet?
    ↳ nein 400, mit den betroffenen Aktionen im Text
  8. Keycloak
    Client
    Gibt es den Client, und ist er eingeschaltet?
    ↳ nein 400
  9. Keycloak
    Rücksprungadresse
    Ist eine Adresse genannt, und passt sie zu den erlaubten Adressen dieses Clients?
    ↳ nein 400
  10. Keycloak
    Gültigkeit
    Ist die Gültigkeit positiv und höchstens 72 Stunden, falls angegeben?
    ↳ nein 400
  11. Link wird gebaut; im Admin-Ereignis von Keycloak stehen Konto, Aktionen, Client und Gültigkeit, aber nie der Link

Jede Prüfung hat einen Grund. Anders als bei Keycloaks eigener Mail landet der Link beim Aufrufer, nicht im Postfach der Person. Ohne die Liste der Aufrufer könnte deshalb jeder, der Konten verwalten darf (manage-users), sich Links für beliebige Konten abholen. Ohne die feste Liste der Aktionen ließe sich ein Link bauen, der zum Beispiel ein Konto löscht (delete_account). Die Obergrenze von 72 Stunden sorgt dafür, dass ein Link nicht wochenlang gültig in einem Postfach liegt. Ohne die Prüfung der Rücksprungadresse könnte eine Mail von der Plattformadresse auf eine fremde Seite führen. Ohne die Prüfung der Aktionen gäbe es Links, die mitten in der Anmeldung stecken bleiben. Ein Konto, das nicht freigeschaltet ist, könnte sich nach dem Passwort ohnehin nicht anmelden. Deshalb lehnt die Erweiterung hier laut ab, statt einen nutzlosen Link auszugeben.

Zwei Stellen fragen nach einem Link:

EinstellungBedeutung
codamai.cias.registration.password-setup.client-idder Client der Oberfläche, für den der Link der Registrierung gilt. Leer heißt: die Registrierung fragt nach keinem Link
codamai.cias.registration.password-setup.valid-forwie lange der Link gilt, höchstens 72 Stunden; leer heißt: Einstellung des Realms, gekappt auf 72 Stunden. Ein größerer Wert verhindert den Start
codamai.cias.keycloak.password-setup-actionswelche Aktionen der Link verlangt; leer heißt nur UPDATE_PASSWORD. Wer zusätzlich die Zustimmung zu Nutzungsbedingungen (TERMS_AND_CONDITIONS) oder ein vollständiges Profil (UPDATE_PROFILE) will, trägt sie hier ein, und die Person erledigt alles in einem Besuch. Andere Aktionen sind nicht erlaubt, und UPDATE_PASSWORD muss in der Liste stehen, denn sie ersetzt die Voreinstellung. Sonst startet CIAS nicht

Die Varianten

Gibt es einen Link?

Wann: Das Jar liegt in Keycloaks Verzeichnis providers/, Keycloak hat es beim Start geladen, und die Anfrage besteht alle Prüfungen.

Die Erweiterung gibt Link und Ablaufzeit zurück. CIAS setzt den Link als passwordUrl in die Mail.

Ergebnis: ein Klick zum eigenen Passwort

Wann: Das Jar ist nicht installiert.

Keycloak kennt den Pfad cias-action-links nicht und antwortet 404. Der Adapter liest das als „kein Link“. Die Registrierung wird trotzdem fertig. Die Willkommensmail führt zur Anmeldung und erklärt „Passwort vergessen“. Der Administrator-Aufruf „Link erneut schicken“ verschickt dagegen gar keine Mail.

Ergebnis: Umweg über „Passwort vergessen“

Wann: Keycloak kennt das Konto nicht.

Die Erweiterung antwortet ebenfalls 404. Für den Adapter sieht das aus wie eine fehlende Erweiterung: kein Link.

Ergebnis: kein Link

Wann: Eine der Prüfungen scheitert, etwa eine Rücksprungadresse, die nicht zum Client passt, eine Aktion, die im Realm abgeschaltet ist, oder eine Gültigkeit über 72 Stunden.

Die Erweiterung antwortet 400 oder 403. Bei der Registrierung schreibt CIAS eine Warnung ins Log, ohne Link und ohne Adresse, und die Mail geht ohne Link hinaus. Beim Administrator-Aufruf scheitert der Aufruf.

Ergebnis: kein Link, Hinweis im Log

Wann: Die Erweiterung ist geladen, aber der Client, mit dem CIAS sich anmeldet, steht nicht in allowed-clients, etwa weil die Einstellung bei der Installation vergessen wurde.

Die Erweiterung antwortet 403, bevor sie irgendetwas anderes prüft. Keycloak schreibt schon beim Start „no client may request links“ ins Protokoll und bei jeder Ablehnung den Client dazu. CIAS verhält sich wie bei jeder abgelehnten Anfrage.

Ergebnis: kein Link, Hinweis in beiden Logs

Wann: codamai.cias.iam-provider: memory

Der Speicher-Adapter gibt einen Link zurück, der mit memory:// beginnt und nirgendwohin führt. So lassen sich Mails mit Link testen. Eine Gültigkeit über 72 Stunden lehnt er ab wie Keycloak.

Ergebnis: Test-Link

Wann: Keycloak startet mit --optimized und wurde nicht mit dem Jar zusammen gebaut.

Keycloak überspringt dann das Einlesen neuer Erweiterungen. Das Jar liegt im Verzeichnis, wird aber nie geladen. Der Pfad antwortet 404, und alles verhält sich wie ohne Erweiterung, ohne Fehlermeldung.

Ergebnis: kein Link

Enthält die Willkommensmail einen Link?
password-setup.client-id gesetzt?Neues Konto?Erweiterung geladen?Prüfungen bestanden?Mail
nein–––ohne Link, mit Hinweis auf „Passwort vergessen“
janein––ohne Link: wer schon ein Konto hat, hat ein Passwort
jajanein–ohne Link
jajajaneinohne Link, Warnung im Log
jajajajamit Link

Die Erweiterung installieren

Keycloak lädt Erweiterungen beim Start aus dem Verzeichnis /opt/keycloak/providers. Das Jar heißt cias-iam-keycloak-provider.jar und meldet sich über den Dienstnamen cias-action-links an.

Wie das Jar zu Keycloak kommt

Wann: Du startest den Stapel aus cias-runtime/docker-compose.yml.

Erst das Jar bauen (mvn install in cias-iam-keycloak-provider), dann in der Compose-Datei die vorbereitete Zeile für den Mount einkommentieren. Keycloak läuft dort mit start-dev und lädt das Jar beim Start.

Ergebnis: Link lokal testbar

Wann: Keycloak läuft in Kubernetes.

Ein kleines Image mit dem Jar läuft als Init-Container im Pod von Keycloak. Es kopiert das Jar in ein gemeinsames Verzeichnis und beendet sich. Erst danach startet Keycloak und findet das Jar. Die Vorlage dafür liegt unter deploy/keycloak-sidecar.yaml.

Ergebnis: Jar vor dem Start von Keycloak an Ort und Stelle

Das Jar allein genügt nicht. Keycloak muss außerdem wissen, welche Clients Links abholen dürfen. Ohne diese Einstellung lehnt die Erweiterung jede Anfrage ab.

KC_SPI_ADMIN_REALM_RESTAPI_EXTENSION__CIAS_ACTION_LINKS__ALLOWED_CLIENTS=cias-admin
EintragBedeutung
cias-adminder Client dieses Namens in dem Realm, der verwaltet wird. Der Normalfall: CIAS meldet sich mit einem Dienstkonto des Realms an, den es verwaltet
master/admin-clider Client dieses Namens in genau diesem Realm, für einen Aufrufer, der sich in einem anderen Realm anmeldet, als er verwaltet

Mehrere Einträge trennt ein Komma. Ein Eintrag ohne Realm passt nie auf einen gleichnamigen Client in einem anderen Realm, denn Client-Namen sind nur innerhalb eines Realms eindeutig. In cias-runtime/docker-compose.yml ist cias-admin schon eingetragen, im Cluster setzt deploy/keycloak-sidecar.yaml die Variable am Keycloak-Container.

Ob die Erweiterung wirklich geladen ist, siehst du nicht an einem Aufruf ohne Anmeldung. Die Admin-API prüft die Anmeldung vor dem Pfad und antwortet in beiden Fällen 401. Verlässlich sind zwei Wege: Im Startprotokoll von Keycloak taucht ActionLinkResourceProviderFactory auf, oder ein angemeldeter Aufruf ohne Inhalt antwortet 400 oder 403 (Erweiterung da) statt 404 (Erweiterung fehlt). Das Skript deploy/smoke-test.sh fragt einen echten Link an und prüft danach, dass eine fremde Rücksprungadresse, eine unbekannte Aktion, eine nicht erlaubte Aktion und eine Gültigkeit über 72 Stunden abgelehnt werden. Der Client, mit dem sich das Skript anmeldet, muss dafür in allowed-clients stehen.

Fallen

Weiter

Quellen im Code und in der Wissensdatenbank
  • CIAS/cias-iam-keycloak-provider – ActionLinkResourceProviderFactory (ID cias-action-links), ActionLinkResourceProvider, ActionLinkResource (create, requireAllowedCaller, validActions, PERMITTED_ACTIONS, client, redirectUri, lifespan, MAX_LIFESPAN_SECONDS), AllowedCallers (allowed-clients), META-INF/services, Dockerfile, deploy/install-provider.sh, deploy/keycloak-sidecar.yaml, deploy/smoke-test.sh, README.md, CLAUDE.md
  • CIAS/cias-iam-keycloak – KeycloakIdentityAdapter (ACTION_LINKS, PERMITTED_PASSWORD_SETUP_ACTIONS, createPasswordSetupLink, seconds), KeycloakAdminApi.post, KeycloakPasswordSetupLinkTest, KeycloakTestEnvironment
  • CIAS/cias-iam-api – IdentityProvisioningPort.createPasswordSetupLink, PasswordSetupLink (MAX_VALIDITY, requireValidity)
  • CIAS/cias-iam-memory – InMemoryIdentityProvider.createPasswordSetupLink
  • CIAS/cias-registration – RegistrationService.passwordSetupContext, PasswordSetupPolicy; CIAS/cias-user – UserService.sendPasswordSetupLink
  • CIAS/cias-spring-boot-starter – CiasProperties (registration.password-setup.client-id, valid-for; keycloak.password-setup-actions), CiasAutoConfiguration.passwordSetupPolicy
  • CIAS/cias-runtime – docker-compose.yml (providers-Mount, allowed-clients)
Suchen