CodamAIDocs
Themafertig

CIAS eingebettet (eine Einheit)

CIAS läuft im selben Prozess wie CDMS oder das Hub-Backend. Welche Module eingebunden werden, wie CDMS CIAS aufruft und welche Datenbank CIAS nutzt.

Ausprägungen
mit Starterohne Starter (hub-backend, generiertes Projekt)Mandantenprüfung per MethodenaufrufAttribut-Lookup per MethodenaufrufDeklaration als BeanSystem-Datenbank des Gastgebers

Worum es geht

Eingebettet heißt: CIAS ist kein eigenes Programm, sondern eine Sammlung von Jar-Dateien im selben Prozess wie die Anwendung. Ein Prozess ist ein laufendes Programm; CDMS und CIAS teilen sich dann Speicher, Datenbankverbindung und Konfiguration.

Die Anwendung, die CIAS aufnimmt, heißt hier Gastgeber. Das ist zum Beispiel das Hub-Backend oder ein mit dem CDMS-Generator erzeugtes Projekt.

Wie derselbe Aufbau mit zwei Diensten aussieht, steht unter CIAS als eigener Service. Die Unterschiede nebeneinander stehen unter Eingebettet und getrennt im Vergleich.

Das Prozessbild

flowchart LR
    F["Frontend mit BFF"] -- "Bearer-Token" --> P
    subgraph P["Ein Prozess"]
        direction TB
        FK["Filterkette<br/>(cias-authentication)"]
        C["CDMS"]
        CI["CIAS-Module<br/>tenancy, user, authorization, …"]
        FK --> C
        FK --> CI
        C <-->|Methodenaufruf| CI
    end
    P --> SDB[("System-Datenbank<br/>CDMS-Tabellen + CIAS-Tabellen")]
    C --> TDB[("Mandanten-Datenbanken")]
    CI -- "Adapter" --> K[(Keycloak)]
    FK -- "Schlüssel, Token-Tausch" --> 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,CI cias
    class K idp
    class SDB,TDB db

Alles innerhalb des Kastens ist ein Programm. Nach außen gehen nur noch drei Leitungen: zur Datenbank, zu Keycloak und zum Frontend.

Welche Module ein Gastgeber einbindet

CIAS besteht aus vielen kleinen Modulen, die jeweils ein eigenes Jar sind. Ein Gastgeber nimmt nicht automatisch alle. Es gibt zwei Wege, sie einzubinden.

Zwei Wege, CIAS einzubinden
Mit Starter
cias-spring-boot-starter
  • eine Abhängigkeit, die alle Fachmodule mitbringt: cias-tenancy, cias-user, cias-authorization, cias-registration, cias-notification, cias-audit
  • verdrahtet sie selbst (Auto-Konfiguration), der Gastgeber schreibt keine Konfigurationsklassen
  • baut auch die Ports zum Identity Provider, den ersten Start (Bootstrap) und die Zeitgeber
  • bringt einen eigenen Migrationslauf für die CIAS-Tabellen mit
  • so läuft der eigenständige CIAS-Dienst cias-runtime
Ohne Starter
einzelne Jars, eigene Konfiguration
  • der Gastgeber nennt jedes Modul einzeln in seiner pom.xml
  • er schreibt die Verdrahtung selbst, in eigenen Konfigurationsklassen
  • er nimmt nur, was er braucht – oft cias-tenancy, cias-user, cias-authorization, cias-iam-keycloak
  • so arbeitet das Hub-Backend, und so erzeugt der CDMS-Generator ein Projekt mit cias: EMBEDDED

Warum überhaupt ohne Starter? Weil der Starter mehr mitbringt, als ein CDMS-Gastgeber will: seinen eigenen Aufrufer-Kontext, seinen eigenen Migrationslauf und eine Bohne für den Identity Provider, die den Start abbricht, wenn kein Anbieter eingestellt ist. Ein Gastgeber, der CIAS nur schlafend mitführen möchte, nimmt deshalb die einzelnen Jars.

Kein CIAS-Modul schaltet sich selbst ein

Jedes Modul hängt an einem Schalter codamai.cias.<modul>.enabled, und keiner dieser Schalter hat einen Standardwert. Das ist Absicht: CDMS durchsucht beim Start alle Klassen unter com.codamai. Ohne diese Schalter würde CIAS in jeder Anwendung anspringen, die das Jar zufällig auf dem Klassenpfad hat.

Der Starter umgeht die Suche auf einem zweiten Weg: er meldet sich als Auto-Konfiguration an, und Auto-Konfigurationen sind von der Klassensuche ausgenommen. Er kommt also, weil das Jar da ist und die Bedingungen passen, nicht weil jemand einen Paketnamen durchsucht hat.

Wie CDMS CIAS aufruft

Eingebettet sind alle drei Fragen zwischen CDMS und CIAS gewöhnliche Methodenaufrufe. Kein HTTP, kein Token, keine Zeitüberschreitung.

FrageWer fragtWer antwortetWie
Darf Mandant kunde-a bedient werden?das Mandanten-Tor in cias-authenticationLocalTenantLookupAdapter in cias-tenancyMethodenaufruf
Welche mandantengebundenen Attributwerte hält diese Person hier?der Attribut-Lookup in cias-authenticationLocalTenantBoundAttributeAdapter in cias-userMethodenaufruf
Welche Rollen und Attribute meldet CDMS an?der Abgleich in cias-authorizationLocalModuleDeclarationAdapter liest die Bean des GastgebersMethodenaufruf

Ein paar Wörter dazu:

  • Das Mandanten-Tor ist die Stelle, die vor jeder Anfrage prüft, ob der Kunde überhaupt bedient wird. Details unter Den Mandanten zulassen.
  • Ein Attribut ist ein Wert an einer Person, mit dem CDMS Zeilen filtert, etwa regionen. Manche gelten je Mandant getrennt, siehe Ein Wert pro Person oder pro Mandant.
  • Die Deklaration ist die Liste aller Rollen und Attribute, die ein Modul kennt. Siehe Module melden ihre Rollen an.
  • Eine Bean ist ein Objekt, das Spring beim Start erzeugt und verwaltet. „Als Bean deklarieren“ heißt hier: das Objekt liegt schon im Prozess, man muss es nur benennen.

Die Deklaration als Bean

Eingebettet fragt CIAS den Endpunkt GET /cias/fetch nicht an. Stattdessen nennt die Konfiguration je Modul den Namen der Bean, die die Deklaration hält:

codamai:
  cias:
    authorization:
      declarations:
        modules:
          - name: cias
            client: ${cias_client}
            bean: ciasIdentityRegistry
          - name: cdms
            client: ${cias_client}
            bean: roleRegistryService

Beide Module liegen im selben Prozess und teilen sich deshalb einen Keycloak-Client. name sagt, wessen Rollen welche sind; ohne den Namen könnte der Abgleich sie nicht auseinanderhalten. roleRegistryService ist die Klasse, die der CDMS-Generator aus den Modellen schreibt.

Jeder Eintrag nennt entweder eine Bean oder eine URL, nie beides und nie keines von beidem. Wer sich vertippt, bekommt den Fehler beim Start und nicht Wochen später beim Abgleich.

Eine Anfrage von vorn bis hinten

sequenceDiagram
    participant B as BFF
    participant F as Filterkette (CIAS)
    participant T as Mandanten-Tor (CIAS)
    participant U as cias-user
    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->>T: darf "kunde-a" bedient werden?
    Note over F,T: Methodenaufruf, kein Netz
    T-->>F: ja (30 s gemerkt)
    F->>U: welche Attributwerte hält die Person in "kunde-a"?
    U-->>F: regionen = [nord]
    F->>C: RequestContext gefüllt
    C->>DB: SELECT … (nur erlaubte Zeilen)
    DB-->>C: Zeilen
    C-->>B: data + meta

Die 30 Sekunden sind der Vorrat des Mandanten-Tors (codamai.cias.tenant-gate.ttl). Eingebettet spart er nur eine Datenbankabfrage – ein Ausfall von CIAS allein ist hier nicht möglich, weil CIAS mit dem Prozess steht und fällt.

Welche Datenbank CIAS nutzt

Eingebettet hat CIAS keine eigene Datenbank. Seine Tabellen liegen in der System-Datenbank des Gastgebers, neben dessen eigenen Tabellen. Das muss so sein: cias_tenant listet alle Mandanten der Installation auf und kann deshalb nicht einmal pro Mandant existieren.

Welche Datenbanken es sonst gibt, steht unter Welche Datenbank? Das Persistenzziel.

Wie die Tabellen entstehen

Migrationen der CIAS-Tabellen

Wann: Der Gastgeber nimmt cias-spring-boot-starter und schaltet codamai.cias.migration.enabled: true.

Der Starter führt einen eigenen Flyway-Lauf je Modul aus, jeder mit einer eigenen Historientabelle (flyway_schema_history_cias_tenancy, …_cias_user, …). Das ist nötig, weil jedes CIAS-Modul ein eigenes Repository ist und seine Zählung bei V1__ beginnt – sechs Module mit sechs Skripten „Version 1“ passen nicht in eine gemeinsame Historie.

  1. 1
    Build
    Der Gastgeber nennt die Orte, die er migriert – je Modul einen. Ein genannter Ort ohne Skripte bricht den Start ab
  2. 2
    Datenbank
    Fehlt die Historientabelle eines Moduls, beginnt der Lauf bei Version 0 und wendet alle Skripte an
    Die übliche Grundlinie „Version 1“ wäre hier falsch: das Schema ist nach dem ersten Modul nie mehr leer, und das zweite Modul würde seine eigene V1__ als „schon erledigt“ überspringen.
  3. 3
    CIAS
    Erst danach startet die Persistenzschicht
    Ergebnis: Jedes Modul hat seine eigene Historie und kann für sich weiterwandern

Wann: Der Gastgeber bindet die Module einzeln ein, wie das Hub-Backend oder ein generiertes Projekt.

Dann gibt es keinen CIAS-Migrationslauf. Der Gastgeber meldet die CIAS-Entitäten stattdessen bei seiner eigenen Persistenz an – eine ManagedTypesContribution mit Geltungsbereich SYSTEM – und die Tabellen entstehen auf demselben Weg wie die Tabellen des Gastgebers.

Ergebnis: Ein Schema, ein Weg, keine zweite Migrationsmaschinerie im Prozess.

Wie ein CDMS-Projekt sein Schema führt, steht unter Datenbanken und Verbindungspools.

Was der Gastgeber selbst beisteuern muss

CIAS weigert sich, ein paar Dinge zu erraten. Ohne Starter nennt der Gastgeber sie in einer eigenen Konfigurationsklasse; mit Starter füllt der Starter die technischen Teile, die Sicherheitsaussagen bleiben beim Gastgeber.

Die Angaben, die der Gastgeber macht
  1. 1
    Entwickler
    Welche Rollen die Plattform verwalten (codamai.cias.platform-administrator-roles)
    Ohne Standardwert. Eine leere Angabe heißt „niemand“ und ist eine gültige Aussage; eine geratene Standardrolle würde die Plattformverwaltung an den verteilen, der zufällig diese Rolle hält.
  2. 2
    Entwickler
    Wer gerade aufruft – ein CallerContextProvider, der Benutzer und Rollen aus dem Anfragekontext liest
    CDMS führt diesen Kontext ohnehin. Eine Anfrage ohne Benutzer ist anonym und kein Fehler, denn Systemläufe haben keinen Aufrufer.
  3. 3
    Entwickler
    Die Entitäten anmelden, damit die CIAS-Tabellen zur System-Datenbank gehören
  4. 4
    Entwickler
    Eine Transaktionsklammer für die schreibenden CIAS-Dienste
    CDMS arbeitet ohne zentralen Transaktionsmanager – seine Grenze ist die Anfrage, nicht die Methode. Der Gastgeber baut die Klammer deshalb lokal und stellt sie nur CIAS zur Verfügung.
  5. 5
    Entwickler
    Welche Rollen GET /cias/fetch lesen dürfen (codamai.cdms.cias.reader-roles)
    Ergebnis: Auch eingebettet ist der Endpunkt vorhanden und geschützt. Vorbelegt ist die Realm-Rolle declaration-reader.

Fallen

Weiter

Quellen im Code und in der Wissensdatenbank
  • CIAS/cias-spring-boot-starter – pom.xml, AutoConfiguration.imports, CiasAutoConfiguration, CiasIamAutoConfiguration (iamPorts), CiasSchemaAutoConfiguration, CiasSchemaMigration, CiasMigrationProperties, CiasDeclarationAutoConfiguration, CiasReconciliationAutoConfiguration, CiasSchedulingAutoConfiguration, CiasBootstrapAutoConfiguration
  • hub-backend – pom.xml, CiasEmbeddedConfiguration, CiasIdentityConfiguration, CiasRepositoryTransactionsPostProcessor, CiasRegistrationSupportConfiguration, application.yaml (codamai.cias.*)
  • CIAS/cias-tenancy – CiasTenancyConfiguration (lookup local), LocalTenantLookupAdapter
  • CIAS/cias-user – CiasUserConfiguration, LocalTenantBoundAttributeAdapter
  • CIAS/cias-authentication – TenantGate, TenantGateProperties, AttributeLookup
  • CIAS/cias-authorization – LocalModuleDeclarationAdapter, ModuleDeclarationPort, ModuleDeclarationSources
  • CDMS/cdms-scaffold – cdms-version-registry.yaml (ciasDependencies EMBEDDED), CdmsScaffoldService (EMBEDDED_CIAS_YAML), CdmsReadmeWriter
  • commons-persistence – ManagedTypesContribution, SchemaMigrationConfiguration
  • CIAS/cias-kernel/docs/adr/adr-022-tenant-lookup-port.md; CIAS/CLAUDE.md §6, §38
Suchen