What this is about
Once the tenant of a request is resolved, it is clear which tenant is meant. Whether this tenant may work today is a second question. A customer can be suspended, their contract can have expired, or they do not exist at all.
The tenant gate asks this second question. It sits in the filter chain directly after the resolution, so before every module. The answer always comes from CIAS, because only CIAS manages the tenants.
The path through the filter chain
-
Filter chainCheck the tokenSignature and expiry valid?↳ no 401
-
Filter chainResolveexactly one tenant, or deliberately none?↳ no 403
cias.authentication.tenant-unresolved -
Tenant gateAdmitIs this tenant served today?↳ no 403
cias.authentication.tenant-not-served -
Filter chainSwitchDid the header
tenantswitch the tenant? Then ask the gate once more for the target↳ no 403cias.authentication.tenant-not-served - RequestContext with an admitted tenant
If a request has no tenant, the gate has nothing to ask and lets it pass. Whether a request without a tenant is allowed is decided by another rule, see The four results.
What “served” means
CIAS answers yes if the tenant has the standing ACTIVE and today’s date is within its validity window. All other cases are no. The details are in The lifecycle of a tenant.
Where the gate gets the answer
The gate asks through an interface, the TenantLookupPort. How the question reaches CIAS depends on whether CIAS runs in the same process:
sequenceDiagram
participant F as Filter chain
participant G as Tenant gate
participant L as CIAS in the same process
participant R as CIAS as a separate service
F->>G: Is nordbau served?
alt embedded (lookup: local)
G->>L: Method call
L-->>G: served: yes
else standalone (lookup: remote)
G->>R: GET /cias/lookup/tenants/nordbau (service token)
R-->>G: 200 {"key":"nordbau","served":true}
end
G-->>F: admitted
| embedded | standalone | |
|---|---|---|
| Setting on the asking side | codamai.cias.tenancy.lookup=local | codamai.cias.tenancy.lookup=remote plus codamai.cias.tenancy.client.base-url |
| Path | method call | HTTP request with a token of the service |
| If the tenant does not exist | empty answer | 404 |
| Waiting time | none | at most 2 seconds to connect and 2 seconds for the answer, then CIAS counts as unreachable |
| Setting on CIAS | – | codamai.cias.tenancy.lookup-rest=true and lookup-roles: which roles may ask |
lookup has no default. If the setting is missing, the application does not start. This is on purpose: a gate that lets everything pass without someone to answer would be a gap that a forgotten entry opens.
The endpoint for the standalone mode reveals only two things: the key and whether it is served. No display name, no data, no standing. It has its own roles, separate from the administration API. Otherwise every CDMS node would have a token it could use to close customers, just to ask a yes-no question.
The gate remembers answers
The question comes with every request, the answer rarely changes. So the gate remembers every answer, every no as well, for a short time: by default 30 seconds (codamai.cias.tenant-gate.ttl). It remembers at most 10,000 tenants (codamai.cias.tenant-gate.max-entries).
| Remembered answer | CIAS reachable | CIAS says | Result |
|---|---|---|---|
| younger than 30 s | – | – | the remembered answer, without asking |
| none or older | yes | served | admitted, remember |
| none or older | yes | not served | 403 tenant-not-served, remember |
| none or older | yes | unknown | 403 tenant-not-served, remember |
| present, no matter how old | no | – | the remembered answer, even if it was no |
| none | no | – | 403 tenant-not-served |
The rule for an outage in one sentence: An outage of CIAS does not throw out anyone who was already working, and does not let anyone new in. “Keep serving” means keeping the last answer, not assuming a favorable one. A tenant that was last suspended stays suspended during the outage.
Any error while asking counts as unreachable: a timeout, a refused connection, an answer with an error code, an unreadable answer. None of them is safer than the others, so all are treated the same.
Unknown and suspended look the same
When: CIAS knows nordbau but does not serve it.
The gate refuses.
Result: 403 cias.authentication.tenant-not-served
When: CIAS knows no tenant nordbau.
The gate refuses, with exactly the same answer.
Result: 403 cias.authentication.tenant-not-served
When: The token contains, for example, Nordbau with uppercase letters.
The gate does not even ask and treats it like an unknown tenant.
Result: 403 cias.authentication.tenant-not-served
When: The question fails, and there is no remembered answer for nordbau.
The gate refuses.
Result: 403 cias.authentication.tenant-not-served
When: The tenant is admitted, but the person's values in this tenant cannot be read.
The filter chain refuses instead of continuing with wrong or empty values. An empty value would be just one * away from switching off an attribute filter.
Result: 403 cias.authentication.tenant-not-served
All refusals carry the same key. This is on purpose: if the answer revealed whether a tenant exists, anyone with a valid token could try out company names and so query the customer list. You find the exact reason in the application log. More on this in Rejections that reveal nothing.
A suspension takes effect with a delay
sequenceDiagram
participant A as Admin
participant C as CIAS
participant G as Tenant gate
participant K as Client of nordbau
K->>G: Request (0 s)
G->>C: Is nordbau served?
C-->>G: yes, remembered for 30 s
A->>C: suspend nordbau (10 s)
K->>G: Request (20 s)
G-->>K: remembered: yes, continues
K->>G: Request (35 s)
G->>C: Is nordbau served?
C-->>G: no
G-->>K: 403 tenant-not-served
So a suspension takes effect at the latest after the configured time, in both operating modes. The same applies the other way round: if the gate has just remembered “unknown” and someone creates the tenant right now, it is admitted only after the time has passed.
The time is therefore a security setting, not only a question of performance. Longer means fewer lookups, but also suspended customers who keep working longer.
Pitfalls
Where to go next
- The CDMS view: Is the tenant served?
- Both operating modes side by side: The tenant check in both operating modes
- Outages as a whole: When CIAS or Keycloak fails