CodamAIDocs
Themafertig

Was läuft, bestimmt die Konfiguration

Jedes CIAS-Modul ist hinter einem Schalter ohne Standardwert. Warum keine CIAS-Klasse sich selbst aktiviert und was im Build entschieden wird (welcher Provider-Adapter).

Ausprägungen
Modul anModul ausSchalter fehlt → Start scheitertGenerator: EMBEDDED / REMOTE / NONE

Worum es geht

CIAS ist keine Anwendung, die man startet, sondern eine Sammlung von Jars. Ein Jar ist eine Bibliothek, die im Klassenpfad einer Anwendung liegt. Ob ein CIAS-Modul in dieser Anwendung tatsächlich arbeitet, entscheidet allein die Konfiguration. Dass das Jar da ist, reicht nicht.

Warum kein Modul sich selbst einschaltet

Spring findet Klassen normalerweise über einen Komponentenscan: Es durchsucht Pakete nach Klassen mit Markierungen wie @Service oder @Component und baut sie zusammen. CDMS scannt dabei alles unter com.codamai — und CIAS liegt unter com.codamai.

Trüge eine CIAS-Klasse so eine Markierung, würde jede CDMS-Anwendung sie einsammeln, sobald das Jar irgendwie im Klassenpfad landet, etwa als Abhängigkeit einer Abhängigkeit. Zusammengesteckt würde sie dann mit Objekten, die es dort gar nicht gibt.

Deshalb:

Wie ein CIAS-Modul in eine Anwendung kommt
  1. 1
    Build
    legt das Jar in den Klassenpfad
    Keine Klasse darin trägt @Service, @Repository oder @Component. Der Komponentenscan findet nichts.
  2. 2
    CIAS
    eine Konfigurationsklasse je Modul registriert die Objekte ausdrücklich
    Der Starter meldet seine Konfigurationen zusätzlich als Auto-Konfiguration an. Auto-Konfigurationen nimmt Spring absichtlich vom Scan aus — auch das ist Schutz gegen die versehentliche Einbindung.
  3. 3
    CIAS
    liest den Schalter des Moduls
  4. 4
    CIAS
    Schalter steht nicht auf true → das Modul arbeitet nicht
  5. 5
    CIAS
    Schalter steht auf true → das Modul arbeitet
    Ergebnis: Ein Modul ist an, weil jemand es hingeschrieben hat, nie weil ein Jar mitgekommen ist.

Die Schalter

Das Bild zeigt, wo die Schalter sitzen. Links das, was immer da ist, sobald die Filterkette läuft; rechts die Module, die einzeln zugeschaltet werden.

flowchart LR
    subgraph P["Ein Prozess"]
        direction TB
        A["cias-authentication<br/>Filterkette, Mandanten-Tor<br/><i>kein Schalter: da oder nicht da</i>"]
        L{"codamai.cias.tenancy.lookup"}
        A --> L
        L -->|local| T["cias-tenancy<br/>codamai.cias.tenancy.enabled"]
        L -->|remote| C["cias-tenancy-client<br/>+ client.base-url, client.credentials"]
        A -.-> U["cias-user<br/>codamai.cias.user.enabled"]
        A -.-> Z["cias-authorization<br/>codamai.cias.authorization.enabled"]
        A -.-> R["cias-registration<br/>codamai.cias.registration.enabled"]
        A -.-> N["cias-notification<br/>codamai.cias.notification.enabled"]
        A -.-> AU["cias-audit<br/>codamai.cias.audit.enabled"]
    end
    IP{"codamai.cias.iam-provider"}
    Z --> IP
    U --> IP
    IP -->|keycloak| K[(Keycloak)]

Die vollständige Liste:

SchalterWofürWerte
codamai.cias.tenancy.enabledMandanten führen: anlegen, sperren, schließentrue
codamai.cias.tenancy.lookupwoher das Mandanten-Tor seine Antwort holtlocal oder remote
codamai.cias.tenancy.client.base-urlwo CIAS erreichbar istnur bei lookup: remote
codamai.cias.tenancy.client.credentials.*der eigene Client beim IAM, mit dem das Dienst-Token geholt wird (token-uri, client-id, client-secret); ohne ihn ein festes .tokennur bei lookup: remote
codamai.cias.tenancy.restdie Verwaltungs-API /cias/admin/tenantstrue / false
codamai.cias.tenancy.lookup-restder Endpunkt, den andere Dienste fragentrue / false; im eigenständigen CIAS-Dienst true
codamai.cias.tenancy.lookup-roleswer diesen Endpunkt fragen darfRollennamen
codamai.cias.user.enabled, .restder Benutzerdatensatz und seine APItrue / false
codamai.cias.user.lookup-rest, .lookup-rolesAttributwerte pro Mandant für andere Dienstetrue / false (im eigenständigen CIAS-Dienst true), Rollennamen
codamai.cias.authorization.enabled, .restRollenkatalog, Vergaben, Abgleich mit Keycloaktrue / false
codamai.cias.registration.enabled, .restRegistrierung und Einladungtrue / false
codamai.cias.notification.enabled, .restMailvorlagen und ihre Bearbeitungtrue / false
codamai.cias.notification.editor-roleswer jede Mailvorlage ändern darf, auch per CIAS_NOTIFICATION_EDITOR_ROLESStandard platform-admin,mail-template-admin
codamai.cias.notification.mail, .mail.fromwie Mails das Haus verlassensmtp oder log
codamai.cias.audit.enableddie Audit-Spurtrue / false
codamai.cias.<modul>.persistencewie das Modul an die Datenbank kommtjpa
codamai.cias.iam-providermit welchem Identity Provider CIAS sprichtkeycloak oder memory
codamai.cias.migration.enabledlegt die Tabellen von CIAS an und hebt sie antrue / false
codamai.cias.platform-administrator-roleswelche Rollen die Plattform verwaltenRollennamen, leer heißt niemand
codamai.cdms.cias.reader-roleswer in CDMS GET /cias/fetch lesen darfRollennamen
codamai.persistence.tenant.modedie Betriebsart der DatenhaltungSINGLE oder MULTI

cias-authentication hat keinen eigenen Schalter. Die Filterkette prüft jedes Token, und sie arbeitet, sobald das Jar da ist. Was sie braucht, ist kein Schalter, sondern eine Antwort: codamai.cias.tenancy.lookup sagt ihr, wen sie nach dem Mandanten fragt.

Die drei Ausprägungen

Was ein Schalter bewirkt

Wann: Der Schalter steht auf true.

  1. 1
    CIAS
    baut die Objekte des Moduls zusammen
  2. 2
    CIAS
    die Endpunkte des Moduls antworten, die Abläufe laufen

Ergebnis: Das Modul arbeitet.

Wann: Der Schalter fehlt oder steht auf false.

„Aus“ sieht je nach Modul verschieden aus, und beides ist Absicht. Bei tenancy und audit entscheidet der Schalter, ob die Objekte überhaupt entstehen: Sie sind dann nicht da. Bei user, authorization, registration und notification entstehen die Objekte immer, und der Schalter wird dort gelesen, wo er etwas entscheidet: Der Ablauf ist dann eine Ausführung, die jeden Aufruf verweigert, und die Endpunkte antworten 404, bevor überhaupt ein Controller erreicht wird.

Ergebnis: In beiden Fällen passiert fachlich nichts. Nach außen ist der Unterschied nur, ob ein Endpunkt 404 sagt oder gar nicht erst existiert.

Wann: Eine Angabe fehlt, ohne die CIAS raten müsste.

  1. 1
    CIAS
    findet die Angabe nicht; einen Standardwert gibt es absichtlich nicht
  2. 2
    CIAS
    bricht den Start ab, die Meldung nennt die Einstellung oder den Typ

Ergebnis: Die Anwendung kommt nicht hoch. Das ist besser als eine, die großzügig hochkommt.

Wann welcher Fall gilt, ist nicht Geschmackssache. Es hängt davon ab, was ein falscher Standardwert anrichten würde:

Warum manche Angabe den Start abbricht
Was fehltFolge
codamai.cias.tenancy.lookupStart scheitert. Ohne diese Angabe gibt es niemanden, der das Mandanten-Tor beantwortet — und ein Tor, das ohne Antwort jeden durchlässt, wäre ein Loch aus einer vergessenen Zeile.
client.base-url bei lookup: remoteStart scheitert. Eine erfundene Adresse wäre schlimmer als keine.
codamai.cias.iam-provider, wo die Module ihn brauchenStart scheitert. Ein CIAS ohne Identity Provider nähme Registrierungen an, die es nie ausführen kann.
codamai.persistence.tenant.mode, wo es CDMS-Persistenz gibtStart scheitert. Ein Standardwert würde still eine Mandantentrennung abschalten oder eine erfinden.
codamai.cias.notification.mail, wenn das Mailmodul an istStart scheitert. Der Standard log würde jede Mail als verschickt melden und keine zustellen.
codamai.cias.user.enabledKein Fehler. Das Modul ist aus, und eine Installation ohne Benutzerverwaltung ist ein gültiger Zustand.
codamai.cias.tenant-gate.ttl und andere ZeitenKein Fehler. Sie haben Standardwerte, denn ein falscher Wert macht die Anwendung träger, öffnet aber nichts.

Die ganze Regel dahinter steht unter Im Zweifel ablehnen, samt der Liste aller Pflicht-Angaben.

Was die Anwendung selbst beisteuern muss

Manche Angaben sind keine Zeile in einer Datei, sondern Beans. Eine Bean ist ein Objekt, das Spring beim Start zusammensteckt.

BeanWas sie entscheidetLiefert CIAS eine mit?
PlatformAdministratorswelche Rollen die Plattform verwaltennein, und das bleibt so: eine Bibliothek darf keine Administratorrolle erfinden
RegistrationRoleswelche Rollen eine Registrierung vergibtnein
MailTemplateEditPolicywelche Mails Mandanten-Administratoren umschreiben dürfen; die Editor-Rollen liest sie aus CIAS_NOTIFICATION_EDITOR_ROLESnein
ManagedTypesContributiondass die Tabellen von CIAS in der Persistenz des Gastgebers bekannt sindnein, das weiß nur der Gastgeber
CallerContextProviderwoher CIAS erfährt, wer gerade handeltder Starter bringt eine mit, die auf den RequestContext schaut; ohne Starter legst du sie selbst an
Clockdie Zeitquellewie oben

Fehlt eine davon, wo sie gebraucht wird, scheitert der Start mit dem Namen des Typs in der Meldung.

Was im Build entschieden wird

Ein Teil der Entscheidung fällt früher, nämlich wenn der Projektrahmen erzeugt wird. Im Hub steht am System ein Feld cias mit drei möglichen Werten. Der Generator legt danach fest, welche Jars in die Anwendung kommen und welche Konfigurationsklassen er schreibt.

Das Feld cias am System
NONEREMOTEEMBEDDED
Was es bedeutetDie Anwendung meldet niemanden über CIAS an.CIAS ist ein eigener Dienst.CIAS läuft in diesem Prozess.
Welche Jars dazukommenkeinecias-tenancy-clientcias-tenancy, cias-user, cias-authorization, cias-iam-keycloak
Was der Generator schreibtnichts davonnur den Eintrag in der .envdie Konfigurationsklassen und den ganzen codamai.cias-Block der application.yaml
Welche Umgebungsvariablen dazukommenkeineCODAMAI_CIAS_TENANCY_CLIENT_BASE_URLCIAS_IAM_PROVIDER, CIAS_USER, CIAS_AUTHORIZATION und die Zugangsdaten des Verwaltungs-Clients
Wer das Mandanten-Tor beantwortetniemand — es gibt keine Filterkette von CIASder CIAS-Dienst, über HTTPcias-tenancy im selben Prozess, als Methodenaufruf

Zwei Dinge daran sind leicht zu übersehen:

  • REMOTE ist der Wert, der gilt, wenn niemand etwas sagt. Sobald eine Anwendung über CIAS anmeldet, braucht sie eine Antwort auf die Frage des Mandanten-Tors, sonst startet sie nicht. Der Generator lässt diese Frage deshalb nie offen. REMOTE ist dabei die zurückhaltendere Wahl: ein Jar und zwei Einstellungen. EMBEDDED holt Mandanten, Benutzer und Rollenkatalog in die Anwendung, und das ist eine Entscheidung über die Installation, kein Standard.
  • Bei EMBEDDED kommt die Identitäts-Hälfte schlafend mit. Die Jars für Benutzer, Rollenkatalog und Keycloak-Zugriff liegen im Klassenpfad, aber CIAS_IAM_PROVIDER, CIAS_USER und CIAS_AUTHORIZATION stehen zunächst auf leer beziehungsweise false. Erst wer sie setzt, hat sie. Das ist genau der Punkt dieser Seite: was läuft, bestimmt die Konfiguration, nicht der Klassenpfad.

Ein System, das gar nicht über CIAS anmeldet, bekommt immer NONE — auch wenn im Feld etwas anderes steht. Ohne Filterkette gibt es kein Tor, das eine Antwort bräuchte.

Fallen

Weiter

Quellen im Code und in der Wissensdatenbank
  • CIAS/cias-spring-boot-starter – AutoConfiguration.imports (Registrierung statt Komponentenscan), CiasIamAutoConfiguration (iam-provider keycloak|memory, iamPorts), CiasSchemaAutoConfiguration (migration.enabled), CiasSecurityAutoConfiguration, CiasBootstrapAutoConfiguration, CiasProperties
  • CIAS/cias-tenancy – CiasTenancyConfiguration (enabled, persistence, lookup local, rest, lookup-rest); CIAS/cias-audit – CiasAuditConfiguration (enabled, persistence)
  • CIAS/cias-user, cias-authorization, cias-registration, cias-notification – Modulschalter zur Laufzeit gelesen (`${…:false}`), Disabled-Implementierungen, EndpointGuard
  • CIAS/cias-authentication – CiasTokenConfiguration (TenantLookupPort Pflicht-Bean, tenantGate, attributeLookup); cias-tenancy-client – CiasTenancyClientConfiguration (lookup remote, base-url, token)
  • CIAS/cias-runtime – application.yml; hub-backend – application.yaml, CiasEmbeddedConfiguration
  • CDMS/cdms-scaffold – CdmsSystemContext.getCiasTopology, cdms-version-registry.yaml (ciasDependencies), CdmsScaffoldService (EMBEDDED_CIAS_CLASSES, EMBEDDED_CIAS_YAML), CdmsReadmeWriter
  • hub-backend – structure/enumerations.yaml MODULE_CIAS (NONE, REMOTE, EMBEDDED), structure/system.yaml
  • commons-persistence – TenantProperties (codamai.persistence.tenant.mode, @NotNull), TenantProvisioningConfiguration
Suchen