CodamAIDocs
Themafertig

Ports und Adapter

Die Fachlogik spricht mit Schnittstellen („Ports“), ein Adapter übersetzt für Keycloak. Welche Ports es gibt und warum ein zweiter Provider ein zweites Artefakt ist.

Ausprägungen
Keycloak-Adapter eingestelltSpeicher-Adapter eingestelltkein Provider eingestelltProvider nicht erreichbarProvider meldet KonfliktProvider kennt das Objekt nichtProvider lehnt abein zweiter Provider

Worum es geht

CIAS schreibt vieles in den Identity Provider (kurz IdP), also in Keycloak: Konten, Organisationen, Rollen, Gruppen, Attribute. Trotzdem kennt keines der Fachmodule Keycloak. Die Registrierung weiß nicht, welche URL Keycloak hat, und die Rollenvergabe weiß nicht, wie Keycloak eine Rolle speichert.

Das liegt an einer Trennung in zwei Teile:

  • Ein Port ist eine Schnittstelle in Java. Sie sagt nur, was gebraucht wird: „lege ein Konto an“, „vergib diese Rolle in diesem Mandanten“.
  • Ein Adapter ist eine Klasse, die diese Schnittstelle für ein bestimmtes System erfüllt. Er weiß, wie das in Keycloak geht: welcher HTTP-Aufruf, welche Felder, welche Antwort.

Das Bild

flowchart LR
    subgraph Fachmodule
      R["cias-registration"]
      U["cias-user"]
      A["cias-authorization"]
    end
    subgraph P["cias-iam-api: Ports"]
      P1["Konten"]
      P2["Organisationen"]
      P3["Rollen"]
      P4["Gruppen"]
      P5["Attribute"]
    end
    R --> P
    U --> P
    A --> P
    P --> KA["cias-iam-keycloak<br/>Keycloak-Adapter"]
    P --> MA["cias-iam-memory<br/>Speicher-Adapter"]
    KA -- "Admin-REST-API" --> K["Keycloak"]
    MA --> M[("Speicher<br/>im Prozess")]

Lies es von links nach rechts: Die Fachmodule kennen nur die Mitte. Rechts steht genau ein Adapter, je nach Einstellung. Die Pfeile zeigen nur in eine Richtung. Kein Fachmodul greift an der Mitte vorbei auf Keycloak zu. Das prüft in jedem Fachmodul ein Architekturtest: ein Test, der beim Bauen scheitert, sobald eine Klasse ein Keycloak-Paket importiert.

Die Ports

Es gibt elf Ports. Jeder deckt eine Fähigkeit ab, nicht ein ganzes System. Ein Modul, das nur Adressen nachschlägt, hängt nicht an der Rollenverwaltung.

PortWas er kannWer ihn nutzt
IdentityProvisioningPortKonto gesperrt anlegen, Adresse als bestätigt markieren, freischalten, sperren, „Passwort setzen“ verlangen, einen Passwort-Link holen, beim Aufräumen löschenRegistrierung, Benutzer
IdentityLookupPortein Konto über die E-Mail-Adresse oder die ID findenRegistrierung, Benutzer
IdentityDirectoryPortalle Konten seitenweise lesenBenutzer (Import)
IdentityAttributePortein Attribut an einem Konto setzen oder entfernenRegistrierung, Benutzer
OrganizationManagementPortOrganisation anlegen, über ihren Alias finden, beim Aufräumen löschenRegistrierung
MembershipManagementPortMitgliedschaft in einer Organisation geben, nehmen, lesenRegistrierung, Benutzer
RoleManagementPortRealm-Rollen: prüfen, anlegen, global oder in einer Organisation vergeben, entziehen, lesenRollen, Registrierung
ClientRoleManagementPortdasselbe für Rollen eines Clients, also ModulrollenRollen, Registrierung
GroupManagementPortdie Kopie einer CIAS-Gruppe in Keycloak pflegenGruppen
UserProfileManagementPortwelche Attribute ein Konto überhaupt tragen darfRollen und Attribute (Abgleich)
ClaimMappingPortein Attribut in die Tokens eines Clients bringenRollen und Attribute (Abgleich)

Drei Begriffe aus der Tabelle:

  • Eine Realm-Rolle gilt im ganzen Realm und damit in allen Modulen, etwa platform-admin. Eine Client-Rolle gehört zu einem Client und bedeutet nur dort etwas, etwa eine Rolle von CDMS. Siehe Realm-Rolle, Client-Rolle, Organisationsrolle.
  • Eine Organisation ist in Keycloak das Abbild eines dynamischen Mandanten. Siehe Statische und dynamische Mandanten.
  • Das User Profile ist in Keycloak ein Dokument je Realm, das festlegt, welche Attribute ein Konto haben darf.

Die Regeln hinter den Ports

Die Ports sind mit Absicht so geschnitten. Jede Regel verhindert einen bestimmten Fehler.

  • Kein Keycloak-Typ in einem Port. Keine Signatur und keine Fehlerklasse nennt Keycloak. Der Port kennt nur eigene, kleine Datensätze wie NewIdentity oder IamIdentity.
  • Kein Passwort. Es gibt „Passwort setzen verlangen“, aber kein „Passwort setzen“. CIAS nimmt nie ein Passwort entgegen.
  • Kein Benutzername. Die E-Mail-Adresse ist die Anmeldung. Ein Konto je Adresse, beliebig viele Mandanten.
  • Global und „in einer Organisation“ sind getrennte Methoden. assign vergibt plattformweit, assignInOrganization nur in einem Mandanten. Wären beide eine Methode mit einem optionalen Mandanten, könnte ein Mandanten-Administrator sich aus Versehen plattformweite Rechte geben.
  • Realm-Rollen und Client-Rollen sind getrennte Ports. Aus demselben Grund: Über den Port für Client-Rollen kann man keine Realm-Rolle erreichen.
  • Jeder Aufruf darf zweimal kommen. Eine Rolle vergeben, die schon da ist, ändert nichts. Ein Konto freischalten, das schon frei ist, auch nicht. Zwischen CIAS und Keycloak gibt es keine gemeinsame Transaktion. Geht eine Antwort verloren, ist Wiederholen der einzige Weg, und der darf nichts kaputt machen.
  • Eine neue Fähigkeit ist ein neuer Port. Keine Sammelschnittstelle mit dreißig Methoden.
  • Ein Attribut braucht drei Schritte, jeder in seinem Port. Das Profil erlaubt es (UserProfileManagementPort), ein Konto bekommt einen Wert (IdentityAttributePort oder beim Anlegen), und der Wert kommt ins Token (ClaimMappingPort). Siehe Der Weg ins Token.

Verweise statt Schlüssel

Keycloak vergibt eigene IDs. CIAS hält sie in kleinen Hüllen fest: ExternalUserId, ExternalOrganizationId, ExternalGroupId, ExternalRoleId. Das sind nur Verweise: „dieses Ding liegt dort im IdP“.

Die fachliche Identität bleibt in CIAS:

Objektfachlich bestimmt durchin Keycloak wiedergefunden über
Personihre CIAS-IDExternalUserId
Mandantden MandantenschlüsselAlias der Organisation = Mandantenschlüssel
Gruppeden GruppenschlüsselName der Gruppe = Gruppenschlüssel
Rolleihren NamenName der Rolle

Wer den IdP wechselt, ändert also Verweise, nicht Daten.

Wenn Keycloak etwas nicht tut

Jeder Port meldet Probleme mit einer von vier Fehlerarten. Die Fachmodule reagieren auf die Art, nicht auf einen HTTP-Status.

Die vier Fehlerarten

Wann: Keycloak antwortet nicht, antwortet mit einem Serverfehler, oder CIAS bekommt kein Anmelde-Token für sich selbst.

IamUnavailableException. Die einzige Art, die man wiederholen darf. Ob der Aufruf schon gewirkt hat, weiß niemand, und deshalb ist jeder Aufruf so gebaut, dass er zweimal kommen darf.

Ergebnis: Aufrufer wartet oder versucht es später erneut

Wann: Es gibt schon ein Konto mit dieser Adresse, eine Organisation mit diesem Alias oder eine Gruppe mit diesem Namen.

IamConflictException. Keycloak setzt Eindeutigkeit durch. Diese Meldung darf nie ungefiltert bei einer nicht angemeldeten Person ankommen, sonst verrät ein öffentlicher Endpunkt, welche Adressen es gibt.

Ergebnis: Aufrufer entscheidet, oft: so weitermachen, als hätte die Suche das Objekt gefunden

Wann: CIAS verweist auf ein Konto, eine Rolle, einen Client oder eine Gruppe, die es in Keycloak nicht (mehr) gibt.

IamNotFoundException. Meist ein Zeichen, dass CIAS und Keycloak auseinandergelaufen sind, etwa weil jemand in der Keycloak-Konsole etwas gelöscht hat.

Ergebnis: Fehler, oft ein Fall für einen Abgleich

Wann: Keycloak lehnt aus einem anderen Grund ab, oder CIAS soll etwas ändern, das nicht CIAS gehört.

IdentityProvisioningException. Der ehrliche Sammeltopf: nicht wiederholen, sondern festhalten und stehen bleiben.

Ergebnis: Fehler, der Vorgang bleibt in einem erkennbaren Zustand

Suchen melden „nicht gefunden“ nicht als Fehler, sondern als leeres Ergebnis. „Unter dieser Adresse gibt es kein Konto“ ist auf einem öffentlichen Endpunkt die normale Antwort.

Welcher Adapter läuft

Zwei Dinge müssen zusammenkommen: Das Jar des Adapters liegt im Klassenpfad, und die Einstellung nennt ihn.

codamai.cias.iam-provider

Wann: codamai.cias.iam-provider: keycloak, und cias-iam-keycloak liegt im Klassenpfad.

CIAS spricht über die Admin-REST-API mit Keycloak. Wo Keycloak steht und mit welchem Dienstkonto CIAS sich anmeldet, steht unter codamai.cias.keycloak.*. Siehe Der Keycloak-Adapter.

Ergebnis: Normalfall jeder Installation

Wann: codamai.cias.iam-provider: memory, und cias-iam-memory liegt im Klassenpfad.

Alle Ports arbeiten auf einer Ablage im Arbeitsspeicher des Prozesses. Nach einem Neustart ist alles weg. Siehe Der Speicher-Adapter für Tests und Entwicklung.

Ergebnis: Tests und lokale Entwicklung

Wann: Die Einstellung fehlt, oder sie nennt einen Adapter, dessen Jar fehlt.

Es gibt keine Ports. Die Anwendung startet nicht und nennt den fehlenden Port. Das ist Absicht: Ein CIAS ohne IdP würde Registrierungen annehmen, die es nie ausführen kann.

Ergebnis: kein Start

Welcher Adapter ist aktiv?
Wert von iam-providerJar im Klassenpfad?Ergebnis
keycloakjaKeycloak-Adapter
memoryjaSpeicher-Adapter
keycloak oder memoryneinkeine Ports, kein Start
leer–keine Ports, kein Start

Liegen beide Jars im Klassenpfad, läuft trotzdem nur der eine, den die Einstellung nennt. Das eigenständige CIAS liefert beide mit: Im Profil local steht memory, sonst keycloak.

Ein zweiter Provider ist ein zweites Artefakt

Soll CIAS einmal mit einem anderen IdP arbeiten, ändert niemand die Fachmodule. Stattdessen entsteht ein neues Modul, etwa cias-iam-<name>:

Was ein neuer Adapter braucht
  1. 1
    Entwickler
    legt ein eigenes Modul an, das nur cias-iam-api und die Bibliothek des neuen IdP kennt
  2. 2
    Entwickler
    setzt die Ports um, die der neue IdP beherrscht, und übersetzt seine Fehler in die vier Fehlerarten
  3. 3
    Build
    lässt dieselben Vertragstests laufen wie für Keycloak und den Speicher
  4. 4
    Entwickler
    gibt dem Adapter einen Namen für codamai.cias.iam-provider und verdrahtet ihn
    Ergebnis: Fachmodule unverändert, nur die Einstellung ändert sich

Warum ein eigenes Artefakt und nicht ein Schalter im Keycloak-Adapter? Jeder Adapter bringt die Bibliotheken seines IdP mit. Stünden zwei IdPs in einem Modul, hinge jede Installation an beiden. Und die Vertragstests prüfen genau einen Adapter auf einmal.

Nicht jeder IdP kann alles. Organisationen, Rollen in Organisationen oder Rollen an Gruppen sind Fähigkeiten von Keycloak. Ein IdP ohne Organisationen kann keine dynamischen Mandanten tragen.

Fallen

Weiter

Quellen im Code und in der Wissensdatenbank
  • CIAS/cias-iam-api – ClaimMappingPort, ClientRoleManagementPort, GroupManagementPort, IdentityAttributePort, IdentityDirectoryPort, IdentityLookupPort, IdentityProvisioningPort, MembershipManagementPort, OrganizationManagementPort, RoleManagementPort, UserProfileManagementPort
  • CIAS/cias-iam-api – model (ExternalUserId, ExternalOrganizationId, ExternalGroupId, ExternalRoleId, NewIdentity, IamIdentity, NewOrganization, IamOrganization, IamGroup, ProfileAttribute, PasswordSetupLink), exception (IamException, IamUnavailableException, IamConflictException, IamNotFoundException, IdentityProvisioningException)
  • CIAS/cias-spring-boot-starter – CiasIamAutoConfiguration (iamPorts, KeycloakConfiguration, MemoryConfiguration), CiasProperties (iam-provider)
  • CIAS/cias-runtime – application.yml, application-local.yml (codamai.cias.iam-provider)
  • CIAS/*/src/test – ArchitectureTest je Fachmodul
  • CIAS/cias-iam-api/docs/adr – ADR-004, ADR-039
Suchen