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:
-
1Buildlegt das Jar in den KlassenpfadKeine Klasse darin trägt
@Service,@Repositoryoder@Component. Der Komponentenscan findet nichts. -
2CIASeine Konfigurationsklasse je Modul registriert die Objekte ausdrücklichDer 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.
-
3CIASliest den Schalter des Moduls
-
4CIASSchalter steht nicht auf
true→ das Modul arbeitet nicht -
5CIASSchalter steht auf
true→ das Modul arbeitetErgebnis: 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["Filterkette, Mandanten-Tor<br/><i>kein Schalter: da oder nicht da</i>"]
L{"codamai.cias.tenancy.lookup"}
A --> L
L -->|local| T["Mandantenverwaltung<br/>codamai.cias.tenancy.enabled"]
L -->|remote| C["Mandanten-Client<br/>+ client.base-url, client.credentials"]
A -.-> U["Benutzerverwaltung<br/>codamai.cias.user.enabled"]
A -.-> Z["Rollenverwaltung<br/>codamai.cias.authorization.enabled"]
A -.-> R["Registrierung<br/>codamai.cias.registration.enabled"]
A -.-> N["Mailversand<br/>codamai.cias.notification.enabled"]
A -.-> AU["Audit<br/>codamai.cias.audit.enabled"]
end
IP{"codamai.cias.iam-provider"}
Z --> IP
U --> IP
IP -->|keycloak| K[(Keycloak)]
Die vollständige Liste:
| Schalter | Wofür | Werte |
|---|---|---|
codamai.cias.tenancy.enabled | Mandanten führen: anlegen, sperren, schließen | true |
codamai.cias.tenancy.lookup | woher das Mandanten-Tor seine Antwort holt | local oder remote |
codamai.cias.tenancy.client.base-url | wo CIAS erreichbar ist | nur 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 .token | nur bei lookup: remote |
codamai.cias.tenancy.rest | die Verwaltungs-API /cias/admin/tenants | true / false |
codamai.cias.tenancy.lookup-rest | der Endpunkt, den andere Dienste fragen | true / false; im eigenständigen CIAS-Dienst true |
codamai.cias.tenancy.lookup-roles | wer diesen Endpunkt fragen darf | Rollennamen |
codamai.cias.user.enabled, .rest | der Benutzerdatensatz und seine API | true / false |
codamai.cias.user.lookup-rest, .lookup-roles | Attributwerte pro Mandant für andere Dienste | true / false (im eigenständigen CIAS-Dienst true), Rollennamen |
codamai.cias.authorization.enabled, .rest | Rollenkatalog, Vergaben, Abgleich mit Keycloak | true / false |
codamai.cias.registration.enabled, .rest | Registrierung und Einladung | true / false |
codamai.cias.notification.enabled, .rest | Mailvorlagen und ihre Bearbeitung | true / false |
codamai.cias.notification.editor-roles | wer jede Mailvorlage ändern darf, auch per CIAS_NOTIFICATION_EDITOR_ROLES | Standard platform-admin,mail-template-admin |
codamai.cias.notification.mail, .mail.from | wie Mails das Haus verlassen | smtp oder log |
codamai.cias.audit.enabled | die Audit-Spur | true / false |
codamai.cias.<modul>.persistence | wie das Modul an die Datenbank kommt | jpa |
codamai.cias.iam-provider | mit welchem Identity Provider CIAS spricht | keycloak oder memory |
codamai.cias.migration.enabled | legt die Tabellen von CIAS an und hebt sie an | true / false |
codamai.cias.platform-administrator-roles | welche Rollen die Plattform verwalten | Rollennamen, leer heißt niemand |
codamai.cdms.cias.reader-roles | wer in CDMS GET /cias/fetch lesen darf | Rollennamen |
codamai.persistence.tenant.mode | die Betriebsart der Datenhaltung | SINGLE oder MULTI |
Die Filterkette hat keinen eigenen Schalter. Sie prüft jedes Token, und sie arbeitet, sobald ihr 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
Wann: Der Schalter steht auf true.
-
1CIASbaut die Objekte des Moduls zusammen
-
2CIASdie 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.
-
1CIASfindet die Angabe nicht; einen Standardwert gibt es absichtlich nicht
-
2CIASbricht 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:
| Was fehlt | Folge |
|---|---|
codamai.cias.tenancy.lookup | Start 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: remote | Start scheitert. Eine erfundene Adresse wäre schlimmer als keine. |
codamai.cias.iam-provider, wo die Module ihn brauchen | Start scheitert. Ein CIAS ohne Identity Provider nähme Registrierungen an, die es nie ausführen kann. |
codamai.persistence.tenant.mode, wo es CDMS-Persistenz gibt | Start scheitert. Ein Standardwert würde still eine Mandantentrennung abschalten oder eine erfinden. |
codamai.cias.notification.mail, wenn das Mailmodul an ist | Start scheitert. Der Standard log würde jede Mail als verschickt melden und keine zustellen. |
codamai.cias.user.enabled | Kein Fehler. Das Modul ist aus, und eine Installation ohne Benutzerverwaltung ist ein gültiger Zustand. |
codamai.cias.tenant-gate.ttl und andere Zeiten | Kein 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.
| Bean | Was sie entscheidet | Liefert CIAS eine mit? |
|---|---|---|
PlatformAdministrators | welche Rollen die Plattform verwalten | nein, und das bleibt so: eine Bibliothek darf keine Administratorrolle erfinden |
RegistrationRoles | welche Rollen eine Registrierung vergibt | nein |
MailTemplateEditPolicy | welche Mails Mandanten-Administratoren umschreiben dürfen; die Editor-Rollen liest sie aus CIAS_NOTIFICATION_EDITOR_ROLES | nein |
ManagedTypesContribution | dass die Tabellen von CIAS in der Persistenz des Gastgebers bekannt sind | nein, das weiß nur der Gastgeber |
CallerContextProvider | woher CIAS erfährt, wer gerade handelt | der Starter bringt eine mit, die auf den RequestContext schaut; ohne Starter legst du sie selbst an |
Clock | die Zeitquelle | wie 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. Ein Feld dafür gibt es nicht. Der Generator leitet die Einbindung aus zwei Angaben im Hub ab: ob das System über CIAS anmeldet (authentication) und in welcher Runtime das CIAS-Modul des Projekts läuft.
authentication | CIAS-Modul des Projekts | Ergebnis |
|---|---|---|
NONE | wird nicht angesehen | NONE, öffentliches System |
OIDC | läuft in der Runtime dieses Systems | EMBEDDED |
OIDC | läuft in einer anderen Runtime, als eigener Dienst oder eingebettet in ein anderes CDMS-Modul des Projekts | REMOTE, dieses System ist Client |
OIDC | ist keiner Runtime zugeordnet | der Build wird abgelehnt |
OIDC | das Projekt hat keins | der Build wird abgelehnt |
Ein abgelehnter Build antwortet mit 400, und die Meldung nennt, was zu modellieren ist: dem Projekt ein CIAS-Modul geben, es in eine Runtime setzen oder authentication auf NONE stellen.
| NONE | REMOTE | EMBEDDED | |
|---|---|---|---|
| Was sie bedeutet | Die Anwendung meldet niemanden über CIAS an. | CIAS läuft in einer anderen Runtime. | CIAS läuft in diesem Prozess. |
| Welche Jars dazukommen | der Baustein für den offenen Zugang von CDMS, kein CIAS-Jar | die Filterkette und der Mandanten-Client von CIAS | die Filterkette, die Mandanten-, Benutzer- und Rollenverwaltung von CIAS, der Keycloak-Adapter, der Starter |
| Was der Generator schreibt | den Schalter für den offenen Zugang | codamai.cias.tenancy.lookup: remote in der application.yaml | die Konfigurationsklassen, den codamai.cias-Block der application.yaml und bei jedem Build die cias-configuration.yaml aus dem CIAS-Modul |
| Welche Umgebungsvariablen dazukommen | CODAMAI_CDMS_OPEN_ACCESS_ALLOWED_NETWORKS | die Anmelde-Variablen (CIAS_ISSUER, CIAS_CLIENT …) und CODAMAI_CIAS_TENANCY_CLIENT_BASE_URL mit den Zugangsdaten des Clients | die Anmelde-Variablen und die des eingebetteten CIAS: Verwaltungs-Client, Benutzer, Rollen, Registrierung, Mail, Audit |
| Wer das Mandanten-Tor beantwortet | niemand, es gibt keine Filterkette von CIAS | der CIAS-Dienst, über HTTP | die Mandantenverwaltung von CIAS im selben Prozess, als Methodenaufruf |
Zwei Dinge daran sind leicht zu übersehen:
- Die Einbindung kann für zwei CDMS-Module desselben Projekts verschieden sein. Läuft das CIAS-Modul in der Runtime des einen, ist es dort eingebettet, und das andere in seiner eigenen Runtime ist sein Client. Einen eigenen CIAS-Dienst braucht das zweite dafür nicht.
- Bei
EMBEDDEDentscheidet das CIAS-Modul, was eingeschaltet ist. Dieapplication.yamldes Rahmens lässt Benutzer, Rollen und Keycloak-Zugriff aus. Die erzeugtecias-configuration.yamlsetzt sie auf das, was am CIAS-Modul im Hub eingestellt ist. Eine Umgebungsvariable wieCIAS_USERüberschreibt beides. Auch hier gilt: Was läuft, bestimmt die Konfiguration, nicht der Klassenpfad.