CodamAIDocs
Themafertig

Module melden Rollen und Attribute an

Wie CDMS seine Rollen und Attribute an CIAS meldet, eingebettet als Bean, getrennt über /cias/fetch mit eigener Rolle, und was bei einer Ablehnung passiert.

Ausprägungen
eingebettetgetrenntabgelehnt

Worum es geht

CIAS erfindet keine Rollen. Jedes Modul sagt selbst, welche Rollen es kennt und welche Werte es über eine Person braucht. Diese Liste heißt Deklaration, und CIAS macht daraus Client-Rollen in Keycloak, Einträge im Benutzerprofil und Einträge im eigenen Katalog.

Diese Seite zeigt den Weg über beide Module: wo die Liste in CDMS entsteht, wie sie zu CIAS kommt und was passiert, wenn CIAS sie nicht annimmt.

Was CIAS mit einer angenommenen Deklaration macht, steht unter Module melden ihre Rollen an und Der Abgleich mit Keycloak. Hier geht es um die Strecke davor.

Woher die Liste in CDMS kommt

Ein CDMS-Projekt schreibt seine Deklaration nicht von Hand. Der Generator baut sie beim Build aus den Modellen, als Klasse RoleRegistryService.

Vom Modell zur Deklaration
  1. 1
    Entwickler→Hub
    modelliert customer und trägt an den Operationen Rollennamen ein, etwa crm-read
  2. 2
    Build
    sammelt jede Rolle, die ein Modell für Anlegen, Lesen, Ändern, Löschen, Herunterladen, Historie oder Rollback verlangt
    Dazu jede Rolle, die an einem Feld steht. Eine Feldrolle, die CIAS nicht kennt, wäre eine Rolle, die zur Laufzeit wirkt und niemandem vergeben werden kann.
  3. 3
    Build
    sammelt jedes Attribut, nach dem ein Attributfilter Zeilen aussiebt
    Ein Projekt ohne Attributfilter deklariert gar kein Attribut. Ein erfundener Eintrag würde CIAS ein Feld ins Benutzerprofil schreiben lassen, das kein Filter liest.
  4. 4
    Generator
    schreibt daraus eine Klasse mit zwei Methoden: roles() und attributes()
    Ergebnis: Genau diese Klasse liest CIAS — als Bean oder als JSON. Es gibt nur die eine.

Was der Generator dabei festlegt:

AngabeWie sie entsteht
Rollenschlüsselgenau der Name, der im Modell steht
Anzeigegruppedas Stück vor dem ersten Bindestrich, also crm bei crm-read. Ohne Bindestrich: keine Gruppe
Anzeigenamewofür die Rolle im Projekt gebraucht wird, je Modell mit seinen Operationen
Attributeoptional und mehrwertig, ohne Standardwert

Warum die Attribute optional sind: Ein Pflichtattribut braucht in Keycloak einen Standardwert, sonst lehnt CIAS die ganze Deklaration ab. Der einzige Standardwert, den ein Generator hier hinschreiben könnte, wäre ein leerer — und der ließe die Anfrage genauso scheitern, nachdem er in jedem Konto des Realms stünde. Warum sie mehrwertig sind: Der Filter zur Laufzeit zerlegt den Wert in mehrere und sucht damit; einwertig deklariert, käme aus Keycloak genau die Form zurück, für die der Filter nicht geschrieben ist.

Die zwei Wege

Wie die Deklaration bei CIAS ankommt

Wann: CDMS und CIAS laufen im selben Prozess.

  1. 1
    CIAS
    sucht die Bean, deren Namen die Konfiguration nennt, etwa roleRegistryService
  2. 2
    CIAS→CDMS
    ruft roles() und attributes() auf
    Ein Methodenaufruf. Kein Netz, kein Token, keine Zeitüberschreitung.
  3. 3
    CIAS
    bekommt die zwei Listen

Ergebnis: Liefert die Bean null statt einer leeren Liste oder wirft sie, gilt das Modul als nicht lesbar — nie als „hat keine Rollen mehr“.

Wann: CDMS ist ein eigener Dienst.

sequenceDiagram
    participant S as CIAS-Dienst
    participant C as CDMS-Dienst
    S->>C: GET /cias/fetch (Leser-Token)
    C->>C: Trägt der Aufrufer eine Leserolle?
    alt ja
        C-->>S: 200 { roles: [...], attributes: [...] }
    else nein
        C-->>S: 403
    end

Ergebnis: Nur 200 ist eine Antwort. Alles andere heißt „nicht lesbar“, und für jeden Fall gibt es einen eigenen Grund im Bericht.

Die Auswahl steht in der Konfiguration von CIAS, je Modul eine Zeile:

codamai:
  cias:
    authorization:
      declarations:
        reader-client:
          token-uri: https://iam.example.com/realms/codamai/protocol/openid-connect/token
          client-id: ${CIAS_DECLARATION_CLIENT_ID}
          client-secret: ${CIAS_DECLARATION_CLIENT_SECRET}
        modules:
          - name: cias
            client: cias-backend
            bean: ciasIdentityRegistry      # im selben Prozess
          - name: cdms
            client: cdms-backend
            url: https://cdms.internal/cias/fetch   # ein eigener Dienst

Beide Formen kommen nebeneinander vor: CIAS ist selbst ein Modul und liest seine eigene Deklaration immer als Bean.

  • name sagt, wem eine Rolle gehört. Er muss eindeutig sein und darf sich zwischen zwei Läufen nicht ändern.
  • client gehört zur Anwendung, nicht zum Modul. Ein Prozess ist ein Client, also teilen sich alle Module in einem Prozess einen. Das Hub-Backend etwa führt cias und cdms auf demselben Client — genau deshalb braucht es den Namen daneben.
  • Genau eine von bean und url. Beides oder keines bricht den Start ab, siehe Kaltstart einer Installation.

Die Leserolle auf beiden Seiten

Der Endpunkt liefert die vollständige Rechtekarte der Anwendung: jede Rolle, die ein Modell verlangt, und jeden Wert, den ein Filter liest. Das ist nichts, was offen stehen darf.

Was GET /cias/fetch prüft
  1. CDMS
    Token vorhanden?
    Hat die Filterkette einen Aufruferkontext gefüllt?
    ↳ nein abgelehnt — eine Anfrage ohne Token hat keine Rollen
  2. CDMS
    Leserolle vorhanden?
    Trägt der Aufrufer eine der Realm-Rollen aus codamai.cdms.cias.reader-roles?
    ↳ nein 403, ohne zu verraten, welche Rolle gereicht hätte
  3. Die zwei Listen als JSON

Zwei Dinge daran sind leicht zu übersehen:

  • Geprüft werden Realm-Rollen, nicht die fachlichen Rollen der Anwendung. Der Aufrufer ist CIAS, und es liest denselben Endpunkt bei jedem Modul; eine Client-Rolle müsste je Client einmal vergeben werden.
  • codamai.cdms.cias.reader-roles hat keinen Standardwert. Wer nichts hinschreibt, dessen Anwendung startet nicht. Eine ausdrücklich leere Angabe ist erlaubt und heißt „niemand“ — das ist die richtige Einstellung für eine Installation, deren Rollen gar nicht über CIAS abgeglichen werden.

Auf der anderen Seite braucht CIAS ein Token, das eine dieser Rollen trägt. CIAS holt es sich selbst beim IAM (Identity and Access Management, hier Keycloak), und zwar mit einem eigenen Client (reader-client). Das Verfahren heißt Client Credentials: Der Dienst meldet sich mit Client-ID und Secret am Token-Endpunkt an und bekommt ein Token für sich selbst, ohne dass eine Person beteiligt ist. CIAS behält das Token für drei Viertel seiner Laufzeit und holt dann ein neues.

  • Ist kein Client eingetragen, nimmt CIAS ein festes Token aus reader-token. Das erneuert sich nicht.
  • Ein Client, dem ein Teil fehlt (etwa das Secret), bricht den Start ab.
  • Kommt kein Token zustande, gilt das Modul in diesem Lauf als nicht lesbar.

Dieser Aufruf liegt nicht auf dem Anfrageweg — er läuft beim Start und auf Zuruf — und darf deshalb Sekunden dauern.

Wenn CIAS nicht annimmt

CIAS liest erst alle Module, prüft dann alles und schreibt erst danach. Ein Lauf, der schon beim Lesen schriebe, würde eine widersprüchliche Konfiguration halb anwenden.

Was eine Ablehnung trifft
BefundReichweiteFolge
das Modul antwortet nicht, oder nicht mit 200dieses Modulnichts ändert sich an seinen Rollen, auch keine Stilllegung
Pflichtattribut ohne Standardwert, oder ein Attribut zweimal verschiedendieses Moduldie ganze Deklaration fällt aus dem Lauf, auch die Rollen
ein Rollenschlüssel gehört auf diesem Client schon einem anderen Moduldieser Clientan diesem Client wird nichts geschrieben, andere Clients laufen normal
zwei Module melden denselben Schlüssel auf einem Client andieser Clientwie oben
zwei Module beschreiben ein Attribut im selben Lauf verschiedenallesder Lauf schreibt nichts, für kein Modul

Der mittlere Fall ist der, den man beim Zusammenspiel zweier Module am ehesten trifft:

Zwei Module, die ein Attribut gleich beschreiben, sind kein Widerspruch; beide dürfen es anmelden. Und eine abgelehnte Deklaration hält CIAS nie an: CIAS ist das, woran sich alle anmelden, und ein Fehler eines Moduls darf nicht den Weg versperren, ihn zu beheben.

Was danach in Keycloak steht

Anfrage
GET /cias/fetch
Authorization: Bearer <Token mit der Leserolle>
Antwort
{
  "roles": [
    { "key": "crm-read",  "group": "crm", "name": "Customer: read" },
    { "key": "crm-write", "group": "crm", "name": "Customer: create, update, delete" }
  ],
  "attributes": [
    { "key": "regionen", "multivalued": true, "defaultValue": null,
      "required": false, "selfEditable": false, "binding": "USER" }
  ]
}

Aus jedem Rolleneintrag wird eine Client-Rolle auf dem Client des Moduls, dazu ein Katalogeintrag mit Eigentümer und Mandanten-Geltungsbereich. Aus jedem Attributeintrag wird ein Feld im Benutzerprofil und ein Claim-Mapper, damit der Wert im Token ankommt.

Was das Modul nicht bestimmt: den Client, den Geltungsbereich und die Delegation. Die legt die Installation fest — ein Modul darf nicht entscheiden, wer seine Rollen weitergibt.

Fallen

Weiter

Quellen im Code und in der Wissensdatenbank
  • CDMS/cdms-generator – RoleRegistryProcessor (Rollen je Modell und Feld, Gruppe vor dem ersten Bindestrich, Attribute aus den Attributfiltern, optional und mehrwertig)
  • CDMS/cdms-authorization – CiasApi (GET /cias/fetch), CiasReaderRoles (codamai.cdms.cias.reader-roles ohne Standardwert), Response
  • CIAS/cias-authorization – LocalModuleDeclarationAdapter, RemoteModuleDeclarationAdapter (nur 200 zählt), ModuleDeclarationPort, ModuleDeclarationSources, DeclarationReaderCredentials, ClientCredentialsDeclarationReaderCredentials (Token vom IAM, erneuert nach drei Vierteln der Laufzeit)
  • CIAS/cias-authorization – RoleReconciliationService (defect, attributeContradictions, attributeTakenFromAnotherModule, keyCollisions, write), ReconciliationReport.Status, CiasIdentityRegistry
  • CIAS/cias-spring-boot-starter – CiasDeclarationAutoConfiguration (Prüfungen beim Start, declarationReaderCredentials: reader-client vor reader-token)
  • commons – IdentityRegistryInterface, models.Role, models.Attribute, models.AttributeBinding
  • CIAS/cias-runtime – application.yml (codamai.cias.authorization.declarations); hub-backend – application.yaml (zwei Module auf einem Client)
Suchen