CodamAIDocs
Themafertig

Woher der Mandant einer Anfrage kommt

Der Mandant steht im Token. Hier steht, wie er gelesen wird und was ohne Mandant passiert.

Ausprägungen
aus der Organisation im Tokenaus dem Attribut tenantAuswahl unter mehreren Organisationenmehrere Organisationen ohne Auswahl → 403Organisation und Attribut widersprechen sich → 403kein Mandant in MULTI → 403, dahinter 400SINGLE ignoriert ihn

Worum es geht

CDMS muss bei jeder Anfrage wissen, für welchen Mandanten sie läuft. Nur so findet es die richtige Datenbank. Der Mandant kommt aus dem Token, das Keycloak ausgestellt und signiert hat. Der Client schickt ihn nicht als eigenes Feld mit, und CDMS nimmt ihn auch aus keinem Feld der Daten.

Die Filterkette von CIAS liest das Token, bevor CDMS irgendetwas tut. Sie legt das Ergebnis im RequestContext ab. Das ist ein Speicher, der genau eine Anfrage lang lebt und am Ende gelöscht wird. Alles Spätere liest den Mandanten nur noch von dort.

Der Weg des Mandanten

flowchart LR
    T["Token<br/>organization: acme<br/>tenant: acme<br/>allowedTenants: …"] --> F["CIAS-Filterkette<br/>liest und prüft"]
    H["Header tenant<br/>(nur ein Wunsch)"] -.-> F
    F --> RC["RequestContext<br/>Mandant: acme<br/>erlaubte Mandanten: acme, …"]
    RC --> P["CDMS-Persistenz<br/>wählt die Datenbank"]
    P --> DB[("Datenbank acme")]

Wo der Mandant im Token steht

Keycloak kann den Mandanten auf zwei Arten ins Token schreiben:

  • Organisation: Die Person ist Mitglied einer Organisation in Keycloak. Das Token trägt sie im Claim organization. Der Alias der Organisation, ihr Kurzname in Keycloak, ist der Mandantenschlüssel. So entstehen Mandanten, die CIAS zur Laufzeit anlegt.
  • Attribut tenant: Die Person hat ein Benutzerattribut tenant mit dem Mandantenschlüssel. Das ist der fest zugeordnete Mandant.

Ein Mandantenschlüssel besteht nur aus Kleinbuchstaben, Ziffern und Bindestrichen, zum Beispiel acme oder stadtwerke-nord. Er ist zugleich der Name der Datenbank des Mandanten.

Wie Mandanten und Organisationen in CIAS entstehen, steht unter Statische und dynamische Mandanten.

Welcher Mandant gilt

Wie CIAS den Mandanten aus dem Token bestimmt
Organisationen im TokenAttribut tenantHeader tenant nennt eine eigene OrganisationMandant der Anfrage
keinefehlt–kein Mandant
keineacme–acme
eine oder mehrerenennt keine davon–403 cias.authentication.tenant-unresolved: die zwei Quellen widersprechen sich
mehrere–ja, z. B. globexglobex: Auswahl unter den eigenen Organisationen
mehrerenennt eine davonneindie Organisation aus dem Attribut
genau einefehltneindiese eine Organisation
mehrerefehltnein403 cias.authentication.tenant-unresolved: unklar, wessen Daten gemeint sind

Die Zeilen werden von oben nach unten gelesen. Einen Standard-Mandanten, auf den CIAS zurückfällt, gibt es nicht. Ein falscher Mandant wäre schlimmer als keine Antwort: Er würde einem Kunden die Daten eines anderen zeigen.

Was im RequestContext landet

Ist der Mandant bestimmt, prüft CIAS noch, ob er bedient wird. Danach schreibt es in den RequestContext:

EintragInhalt
Mandantder eben bestimmte Mandantenschlüssel
erlaubte Mandantender eigene Mandant, alle eigenen Organisationen und alle Einträge aus dem Benutzerattribut allowedTenants
Wechselwunschder Wert des Headers tenant, falls vorhanden
Benutzer, Rollen, Attributewie unter Die drei Ebenen der Sicherheit beschrieben

Die Liste der erlaubten Mandanten begrenzt, wohin ein Mandantenwechsel überhaupt führen kann. Sie kommt aus dem signierten Token, nie aus einem Header. Das Attribut allowedTenants darf mehrere Werte haben oder eine durch Kommas getrennte Liste sein.

Varianten

Mandant vorhanden, fehlt oder wird ignoriert

Wann: MULTI, das Token nennt genau einen Mandanten

  1. 1
    Client→CDMS
    schickt die Anfrage mit Authorization: Bearer …
  2. 2
    CIAS
    prüft das Token und bestimmt den Mandanten acme
  3. 3
    CIAS
    fragt, ob acme bedient wird: ja
  4. 4
    CDMS→Database
    liest und schreibt Mandanten-Modelle in der Datenbank acme

Ergebnis: Die Anfrage läuft vollständig im Mandanten acme.

Wann: Das Token gehört einer echten Person oder einem Dienstkonto, nennt aber weder Organisation noch Attribut tenant.

  1. 1
    CIAS
    prüft das Token: gültig, aber ohne Mandant
  2. 2
    CIAS→Client
    403 cias.authentication.tenant-required, noch bevor CDMS die Anfrage sieht

Ergebnis: Der Fehler sagt: Dieser Person wurde nie ein Mandant zugeordnet. Das wird in Keycloak bzw. CIAS behoben, nicht im Client.

Wann: Eine Anfrage erreicht die Persistenz trotzdem ohne Mandanten, etwa aus eigenem Code.

  1. 1
    CDMS
    will ein Mandanten-Modell lesen oder schreiben und findet keinen Mandanten
  2. 2
    CDMS
    400 CDMS_TENANT_REQUIRED, kein Rückfall auf die System-Datenbank

Ergebnis: System-Modelle sind davon nicht betroffen, sie brauchen keinen Mandanten.

Wann: CODAMAI_PERSISTENCE_TENANT_MODE=SINGLE

CIAS wertet Organisation und Attribut tenant gar nicht aus. Die Anfrage läuft ohne Mandanten, die Liste der erlaubten Mandanten bleibt leer, ein Header tenant bleibt wirkungslos. Alles landet in der einen Datenbank.

Ergebnis: Ein Token mit Mandant und eines ohne verhalten sich in SINGLE gleich.

Die Fehlerantworten der Filterkette

Lehnt die Filterkette ab, kommt die Antwort von CIAS und nicht von CDMS. Sie hat deshalb ein eigenes, kurzes Format:

Anfrage
POST /api/rest/crm/customer/query
Authorization: Bearer <Token mit zwei Organisationen, ohne Auswahl>
Antwort
HTTP 403
{ "error": "cias.authentication.tenant-unresolved", "message": "request refused" }
SchlüsselBedeutung
cias.authentication.tenant-unresolvedDas Token nennt Mandanten, aber nicht eindeutig einen.
cias.authentication.tenant-requiredDas Token nennt gar keinen Mandanten, obwohl die Installation MULTI ist.
cias.authentication.tenant-not-servedDer Mandant ist eindeutig, wird aber nicht bedient. Siehe Wird der Mandant bedient?

Ein ungültiges oder abgelaufenes Token ist ein anderer Fall: Das ergibt 401, siehe Zugriff ohne Token.

Fallen

Wie es weitergeht

Quellen im Code und in der Wissensdatenbank
  • CIAS/cias-authentication – JwtSessionFilter (Header tenant/user vor dem Token lesen, tenantMissing, refuse), TokenParser (admit, buildAllowedTenants), OrganizationTenantResolver, CiasTokenProperties (tenant, allowedTenants, organization)
  • CIAS/cias-authentication – TenantResolution (RESOLVED, NONE, AMBIGUOUS, CONFLICT), RequestAdmission (tenant-unresolved, tenant-not-served, tenant-required)
  • commons – RequestContext (userTenant, allowedTenants, userTenantSwitchRequest)
  • commons-persistence – DatabaseRequestContext.resolveTenant, PersistenceErrorCode (CDMS_TENANT_REQUIRED 400)
  • documentation/30-daten-und-persistenz/01-mandantentrennung.md
Suchen