Worum es geht
Getrennt heißt: CIAS ist ein eigenes Programm mit eigener Adresse und eigener Datenbank. Der CDMS-Dienst und der CIAS-Dienst laufen nebeneinander und reden über HTTP.
Das ausgelieferte Programm für den eigenständigen Betrieb heißt cias-runtime. Es besteht aus denselben Modulen, die eingebettet im Gastgeber laufen – die Fachlichkeit ist dieselbe, nur die Verpackung ist anders.
Der Gegenstück-Betrieb steht unter CIAS eingebettet, alle Unterschiede nebeneinander unter Eingebettet und getrennt im Vergleich.
Das Prozessbild
flowchart LR
F["Frontend mit BFF"]
subgraph D1["Dienst 1: CDMS"]
direction TB
FK["Filterkette<br/>cias-authentication"]
TC["cias-tenancy-client"]
C["CDMS"]
FK --> C
FK --> TC
end
subgraph D2["Dienst 2: cias-runtime"]
CI["CIAS-Module<br/>tenancy, user, authorization,<br/>registration, notification, audit"]
end
F -- "Bearer-Token<br/>/api/rest/…" --> FK
F -- "Bearer-Token<br/>/cias/…" --> CI
TC -- "HTTP + Dienst-Token<br/>Mandant? Attribute?" --> CI
CI -- "HTTP + Dienst-Token<br/>GET /cias/fetch" --> C
C --> SDB[("System-DB<br/>+ Mandanten-DBs")]
CI --> CDB[("CIAS-Datenbank")]
FK -- "Schlüssel, Token-Tausch" --> K[(Keycloak)]
CI -- "Adapter" --> K
classDef client fill:#475569,stroke:#475569,color:#fff
classDef cdms fill:#1976d2,stroke:#1976d2,color:#fff
classDef cias fill:#8e24aa,stroke:#8e24aa,color:#fff
classDef idp fill:#c2410c,stroke:#c2410c,color:#fff
classDef db fill:#4d7c0f,stroke:#4d7c0f,color:#fff
class F client
class C cdms
class FK,TC,CI cias
class K idp
class SDB,CDB db
Zwei Pfeile gehen zwischen den Diensten hin und her, und sie gehen in verschiedene Richtungen. Das ist der Punkt, den man sich merken sollte: CIAS fragt auch bei CDMS nach.
Was der CDMS-Dienst mitbringt
Von CIAS liegen genau zwei Jars im CDMS-Dienst:
cias-authentication- prüft bei jeder Anfrage das Token gegen Keycloak
- tauscht das Token und löst den Mandanten auf
- enthält das Mandanten-Tor und den Attribut-Lookup samt ihrem Gedächtnis
- läuft in beiden Betriebsarten im CDMS-Prozess
cias-tenancy-client- beantwortet dieselben zwei Fragen wie eingebettet – nur über HTTP
- absichtlich winzig:
cias-kernel, der HTTP-Client des JDK, sonst nichts - kein eigener Zwischenspeicher, kein Wiederholversuch
- existiert eingebettet gar nicht
Die Auswahl zwischen beiden Welten ist eine Eigenschaft ohne Standardwert:
codamai.cias.tenancy.lookup = local # cias-tenancy, Methodenaufruf
codamai.cias.tenancy.lookup = remote # cias-tenancy-client, HTTP
Ein Dienst, der dazu nichts sagt, startet nicht. Das ist gewollt: raten hieße hier, sich eine Antwort auf „Darf dieser Kunde bedient werden?“ auszudenken.
Welche Aufrufe über HTTP gehen
| Richtung | Aufruf | Wann | Antwort |
|---|---|---|---|
| CDMS → CIAS | GET /cias/lookup/tenants/{key} | bei jeder Anfrage mit Mandant, wenn nichts gemerkt ist | 200 {"key":"kunde-a","served":true} · 404 kein Mandant mit diesem Schlüssel · 403 der Aufrufer darf nicht fragen |
| CDMS → CIAS | GET /cias/lookup/users/{id}/attributes?tenantKey=kunde-a | bei jeder Anfrage, die einen Mandanten auflöst | 200 {"attributes":{"regionen":["nord"]}}, auch leer · 403 der Aufrufer darf nicht fragen |
| CIAS → CDMS | GET /cias/fetch | beim Start von CIAS und wenn ein Administrator den Abgleich anstößt | 200 mit Rollen und Attributen · 403 ohne Leserolle |
Die beiden ersten Aufrufe liegen auf dem Anfrageweg. Deshalb sind ihre Zeitlimits kurz (voreingestellt 2 Sekunden, Verbindung und Antwort getrennt) und absichtlich kein Stellknopf: ein langsamer CIAS-Dienst wäre sonst eine langsame Plattform. Lieber scheitern als warten, denn für „gescheitert“ gibt es eine festgelegte Antwort.
Der dritte Aufruf liegt nicht auf dem Anfrageweg. Er läuft beim Start und auf Zuruf, darf deshalb länger dauern und merkt sich nichts.
Mit welchem Token
Der CDMS-Dienst fragt als er selbst, nie im Namen des angemeldeten Benutzers.
-
1CDMSholt sein eigenes Dienst-Token bei Keycloak (
codamai.cias.tenancy.client.credentials)Mit Client-ID und Secret seines eigenen Clients, per Client Credentials. Das Token wird für drei Viertel seiner Laufzeit behalten und dann neu geholt. Es wird nie protokolliert. -
2CDMS→CIASschickt es als
Authorization: Bearer …an beide Lookup-Endpunkte -
3CIASprüft die Rolle des Aufrufers – eine eigene Rolle je Endpunkt, ohne StandardwertWeder die Plattform-Admin-Rolle noch dieselbe Rolle für beide Fragen. Der eine Endpunkt sagt, ob ein Schlüssel zu einem bedienten Kunden gehört, der andere gibt die Attributwerte heraus, nach denen ein Zeilenfilter aussiebt.
-
4CIASRolle fehlt → 403, der CDMS-Dienst lehnt die Anfrage ab
-
5CIASRolle passt → AntwortErgebnis: Der CDMS-Dienst merkt sich die Antwort für die eingestellte Zeit (voreingestellt 30 s)
Warum nicht einfach das Benutzer-Token weiterreichen? Zwei Gründe: der angemeldete Mensch hat keinen Anlass, eine Mandanten-Lookup-Rolle zu tragen, und es gibt Anfragen ganz ohne Benutzer-Token – ein Zeitgeber, eine Bereitschaftsprüfung –, die dann nichts mitzuschicken hätten.
Die Einstellungen dafür:
codamai:
cias:
tenancy:
client:
credentials:
token-uri: https://iam.example.com/realms/codamai/protocol/openid-connect/token
client-id: cdms-node
client-secret: ${CIAS_LOOKUP_CLIENT_SECRET}
- Ein Client, dem ein Teil fehlt, bricht den Start ab.
- Ohne Client nimmt der Dienst ein festes Token aus
codamai.cias.tenancy.client.token. Das erneuert sich nicht. - Was passiert, wenn Keycloak nicht antwortet oder den Client abweist, steht unter Wenn CIAS nicht erreichbar ist.
Mehr zu Dienstkonten unter Anmelden als Dienst.
In der Gegenrichtung gilt dasselbe Muster: CIAS liest GET /cias/fetch mit einem eigenen Leser-Token, das es ebenso bei Keycloak holt. Welche Realm-Rolle dort reicht, sagt die CDMS-Seite (codamai.cdms.cias.reader-roles, vorbelegt mit declaration-reader). Die Antwort ist die komplette Rechtekarte der Anwendung, also nichts, was öffentlich sein dürfte.
Wie CIAS die Deklaration holt
Getrennt steht in der CIAS-Konfiguration statt einer Bean eine URL:
codamai:
cias:
authorization:
declarations:
reader-token: ${CIAS_DECLARATION_TOKEN}
modules:
- name: cias
client: cias-backend
bean: ciasIdentityRegistry
- name: cdms
client: cdms-backend
url: https://cdms.internal/cias/fetch
Beide Formen kommen nebeneinander vor: CIAS ist selbst ein Modul und liest seine eigene Deklaration als Bean, während CDMS ein Dienst woanders ist. Jeder Eintrag nennt entweder bean oder url, und jeder nennt den Keycloak-Client, auf dem seine Rollen landen. Getrennt hat jeder Dienst seinen eigenen Client.
Nur 200 gilt als Antwort. Ein 404 heißt hier nicht „deklariert nichts“, sondern „der Endpunkt steht nicht, wo die Konfiguration sagt“ – sonst würde ein Tippfehler in der URL beim nächsten Abgleich alle Rollen dieses Moduls stilllegen. Was der Abgleich dann tut, steht unter Module melden ihre Rollen an und Der Abgleich mit Keycloak.
Eine Anfrage von vorn bis hinten
sequenceDiagram
participant B as BFF
participant F as Filterkette (in CDMS)
participant R as cias-tenancy-client
participant S as CIAS-Dienst
participant C as CDMS
participant DB as Mandanten-DB
B->>F: POST /api/rest/crm/customer/query + Token
F->>F: Token prüfen, tauschen, Mandant auflösen
F->>R: darf "kunde-a" bedient werden?
R->>S: GET /cias/lookup/tenants/kunde-a (Dienst-Token)
S-->>R: 200 served true
R-->>F: ja (30 s gemerkt)
F->>R: Attributwerte der Person in "kunde-a"?
R->>S: GET /cias/lookup/users/…/attributes
S-->>R: 200 regionen nord
R-->>F: Werte (30 s gemerkt)
F->>C: RequestContext gefüllt
C->>DB: SELECT … (nur erlaubte Zeilen)
DB-->>C: Zeilen
C-->>B: data + meta
Beide Aufrufe entfallen, solange die Antwort im Gedächtnis liegt. Das Gedächtnis sitzt in cias-authentication, also im CDMS-Dienst und je Knoten – nicht im kleinen Client und nicht bei CIAS.
Die eigene Datenbank von CIAS
Der CIAS-Dienst hat seine eigene Datenbank (CIAS_DATABASE_URL). Er leitet nichts nach Mandanten um: alle CIAS-Tabellen sind Systemtabellen, es gibt keine Datenbank je Kunde.
- System-Datenbank mit den eigenen Tabellen
- eine Datenbank je Mandant, je nach Persistenzziel
- gegebenenfalls einen Dateispeicher
- eine Datenbank, ohne Mandantenaufteilung
- je Modul ein eigener Migrationslauf mit eigener Historientabelle
- keine Geschäftsdaten – Benutzer, Mandanten, Rollen, Gruppen, Vorgänge
Eine Installation kann beide auf dieselbe Datenbank zeigen lassen – die CIAS-Tabellen sind genau die Tabellen, die eingebettet in der System-Datenbank liegen. Nötig ist das nicht.
Wenn CIAS nicht antwortet
Nur getrennt kann CIAS allein ausfallen. Dann entscheidet das Gedächtnis:
| CIAS antwortet? | schon gemerkt? | Ergebnis für die Anfrage |
|---|---|---|
| ja | – | CIAS entscheidet, die Antwort wird gemerkt |
| nein | ja | die letzte bekannte Antwort gilt weiter, so alt sie ist |
| nein | nein | abgelehnt – im Zweifel zu |
In einem Satz: ein Ausfall darf niemanden hinauswerfen, der schon arbeitete, und niemanden hereinlassen, der es nicht tat. Eine gemerkte Ablehnung bleibt dabei eine Ablehnung – „weiterlaufen“ heißt, die letzte Antwort zu behalten, nicht eine günstige anzunehmen.
Als Ausfall zählt dabei mehr, als man denkt:
- eine Zeitüberschreitung oder eine abgelehnte Verbindung,
- ein
401oder403– das sind die eigenen Zugangsdaten dieses Dienstes, kein Urteil über den Kunden, - eine Antwort ohne das Feld
served, denn ein fehlendes Feld darf nicht als „nicht bedient“ gelesen werden, - beim Attribut-Lookup auch ein
404, denn eine Person ohne Eintrag wird mit200und leerer Liste beantwortet.
Details stehen unter Wenn etwas ausfällt und Den Mandanten zulassen.