What this is about
CIAS can run next to CDMS in two ways. In the subject area, the result is always the same: same code, same rules, same rejections. The only difference is how CDMS and CIAS talk to each other.
The two pictures
flowchart LR
subgraph E["Embedded: one process"]
direction TB
E_CDMS["CDMS / hub backend"]
E_CIAS["CIAS modules<br/>(authentication, tenancy,<br/>user, authorization, …)"]
E_CDMS <-->|method call| E_CIAS
end
E_DB[("System DB<br/>CDMS + CIAS tables")]
E --> E_DB
E --> KC1[(Keycloak)]
flowchart LR
subgraph G1["Service 1"]
G_CDMS["CDMS<br/>+ cias-authentication<br/>+ cias-tenancy-client"]
end
subgraph G2["Service 2"]
G_CIAS["cias-runtime"]
end
G_CDMS -->|"HTTP: may tenant X<br/>be served?"| G_CIAS
G_CIAS -->|"HTTP: GET /cias/fetch<br/>(roles, attributes)"| G_CDMS
G_CDMS --> DB1[("System DB CDMS<br/>+ tenant DBs")]
G_CIAS --> DB2[("CIAS DB")]
G_CDMS --> KC2[(Keycloak)]
G_CIAS --> KC2
All differences in one table
| Embedded | Standalone | |
|---|---|---|
| Processes | one | two (or more) |
| What CDMS includes | the CIAS modules directly (with or without starter) | only cias-authentication + cias-tenancy-client |
| How CDMS asks: “May tenant X be served?” | method call LocalTenantLookupAdapter | HTTP GET /cias/lookup/tenants/{key}, timeout 2 s |
| Tenant-bound attributes | method call in cias-user | HTTP GET /cias/lookup/users/{id}/attributes?tenantKey=… |
| How CIAS learns the roles of CDMS | as a bean in the same process | CIAS calls GET /cias/fetch on CDMS, with a reader realm role of its own (preset declaration-reader) |
| Database of CIAS | the host's system DB; with the starter, one migration history per module | its own |
| Token CDMS uses to ask CIAS | none needed | a service token of its own, fetched by the service itself from Keycloak, never the user token |
| Token check of the user | cias-authentication in the same process | cias-authentication in the CDMS process, against Keycloak |
| CIAS goes down | goes down together with CDMS, there is no “half” state | known tenants keep running from the cache, unknown ones are rejected |
| Tenant is suspended | takes effect after 30 s at most (cache of the tenant gate) | takes effect after 30 s at most, from the point of view of each single service |
| Setting in the generator | cias: EMBEDDED in system.yaml | cias: REMOTE – derived when system.yaml says nothing |
One request in both operating modes
The same request “list of customers” in both worlds:
When: CDMS and CIAS run in the same process, for example the hub backend.
sequenceDiagram
participant B as Browser/BFF
participant F as Filter chain (CIAS)
participant T as Tenant gate (CIAS)
participant C as CDMS
participant DB as Tenant DB
B->>F: POST /crm/customer/query + token
F->>F: check token, exchange it, resolve tenant
F->>T: may "kunde-a" be served?
Note over F,T: method call in the same process
T-->>F: yes (remembered for 30 s)
F->>C: RequestContext filled
C->>DB: SELECT … (only allowed rows)
DB-->>C: rows
C-->>B: data + meta
Result: One process, no network call between CDMS and CIAS.
When: CIAS runs as a separate service (cias-runtime).
sequenceDiagram
participant B as Browser/BFF
participant F as Filter chain (in CDMS)
participant R as cias-tenancy-client
participant S as CIAS service
participant C as CDMS
participant DB as Tenant DB
B->>F: POST /crm/customer/query + token
F->>F: check token, exchange it, resolve tenant
F->>R: may "kunde-a" be served?
R->>S: GET /cias/lookup/tenants/kunde-a<br/>(service account token)
S-->>R: served: true
R-->>F: yes (remembered for 30 s)
F->>C: RequestContext filled
C->>DB: SELECT … (only allowed rows)
DB-->>C: rows
C-->>B: data + meta
Result: One extra HTTP call, but only when the tenant is not in the cache.
What happens when CIAS does not answer?
Only in standalone mode can CIAS go down on its own. Then the memory of the tenant gate decides:
| CIAS answers? | Tenant in cache? | Result for the request |
|---|---|---|
| yes | – | CIAS decides, the answer is remembered for 30 s |
| no | yes | the last known answer still applies |
| no | no | 403 tenant-not-served – when in doubt, reject |
A 403 from the lookup or a timeout counts as an error, not as a “no”. That is why the cache is an availability buffer, not a speed trick.
Why both modes must behave the same in the subject area
-
1CIASNo CIAS class activates itself. Every module sits behind a switch
codamai.cias.<modul>.enabledwith no default valueOtherwise CDMS, which scans allcom.codamaiclasses, would turn on CIAS in every application that only brings the jar along. -
2CIASEmbedded and standalone run the same code with the same rules and rejections
-
3CIASOnly the adapters are swapped – tenant lookup, attribute lookup and declaration, local or over HTTP, plus the adapter to the identity providerResult: A bug that shows up in only one operating mode is, by definition, a bug
Next
- CIAS embedded (a single unit): which modules a host includes and how it wires them
- CIAS as a separate service: which calls go over HTTP and with which token
- Why both operating modes behave the same
- What is configured and SINGLE or MULTI