CodamAIDocs
Topicdone

Is the tenant served?

Before every access the filter chain asks CIAS whether the tenant is active. This page gives the CDMS view; the details are in the CIAS section.

Variants
activesuspended, closed or outside the validity periodunknownCIAS not reachableafter a tenant switchrequest without a tenantoperating mode SINGLE

What this is about

A tenant being in the token does not yet mean that it may work. A customer can be suspended, their contract can have expired, or they may not exist at all. That is why the filter chain asks a second question on every request: Is this tenant served?

The place that asks this question is called the tenant gate. CIAS gives the answer, because that is where it is recorded which customers exist and what state they are in. CDMS keeps no list of its own for this.

The gate on the path of the request

The path of a request to the tenant's database
  1. CIAS
    Check token
    Is the token valid?
    ↳ no 401
  2. CIAS
    Determine tenant
    Does the token name exactly one tenant?
    ↳ no 403 cias.authentication.tenant-unresolved or tenant-required
  3. CIAS
    Tenant gate
    Is this tenant served?
    ↳ no 403 cias.authentication.tenant-not-served
  4. CIAS
    Tenant switch
    tenant header set and allowed? Then ask the gate again for the target
    ↳ no 403 cias.authentication.tenant-not-served if the target is not served
  5. CDMS
    Persistence target
    Tenant in the list of allowed tenants?
    ↳ no 403 CDMS_TENANT_SWITCH_NOT_AUTHORIZED
  6. Access to the tenant's database

The gate stands in front of CDMS. So it also protects requests that do not touch any database, for example a request that only reads system models.

When a tenant is served

CIAS answers yes when both are true:

  • The tenant is in the state active.
  • Today’s date lies within its validity period (start and end, both optional, both inclusive).
What the gate answers
Tenant in CIASStatetoday within the validity periodCIAS reachableResult
knownactiveyesyesserved, the request continues
knownactivenoyes403 tenant-not-served
knownbeing provisioned, suspended or closed–yes403 tenant-not-served
unknown––yes403 tenant-not-served
–––no, but answer rememberedthe remembered answer applies, a refusal too
–––no, nothing remembered403 tenant-not-served

All refusals look the same to the client. That is deliberate: if the response revealed whether a tenant exists, anyone with a valid token could query the customer list. You find the exact reason in the CDMS log.

The states and how a tenant moves between them are described in The life cycle of a tenant and Suspending and closing tenants, validity.

The gate remembers answers

The question comes on every request, the answer rarely changes. The gate therefore remembers each answer for a short time, 30 seconds by default. This can be set with codamai.cias.tenant-gate.ttl.

Where the answer comes from

When: The last answer for this tenant is younger than 30 seconds.

The gate takes the remembered answer and does not ask CIAS.

Result: Most requests cost no round trip.

When: No answer remembered, or the remembered one is older.

  1. 1
    CIAS
    gate asks CIAS: is acme served?
  2. 2
    CIAS
    remembers the answer for the next 30 seconds

Result: If CIAS runs in the same application, this is a method call. If CIAS runs as a separate service, an HTTP request.

When: The question fails: timeout, connection error, unreadable response.

  1. 1
    CIAS
    gate has a remembered answer, however old → takes it
  2. 2
    CIAS→Client
    no remembered answer → 403 tenant-not-served

Result: A CIAS outage throws out nobody who was already working, and lets nobody new in.

The details of an outage are in When CIAS is not reachable.

A suspension takes effect with a delay

sequenceDiagram
    participant A as Admin
    participant CIAS as CIAS
    participant G as Tenant gate
    participant C as Client of acme
    C->>G: Request (0 s)
    G->>CIAS: Is acme served?
    CIAS-->>G: yes, remembered for 30 s
    A->>CIAS: suspend acme (10 s)
    C->>G: Request (20 s)
    G-->>C: remembered: yes, continues
    C->>G: Request (35 s)
    G->>CIAS: Is acme served?
    CIAS-->>G: no
    G-->>C: 403 tenant-not-served

So a suspension takes effect at the latest after the configured time. Choosing a longer time saves round trips, but also extends the time a suspended customer keeps working.

Special cases

When the gate does not ask, or asks twice

When: The tenant header has changed the tenant of the request.

The gate asks a second time, now for the target. A suspended tenant stays suspended for everyone, including administrators who switch into it.

Result: See Tenant switch by header.

When: The token names no tenant.

The gate has no question to ask and lets the request through. In MULTI the filter chain still refuses it because the tenant is missing, see Where the tenant of a request comes from.

Result: The gate does not ask for requests without login either.

When: The tenant in the token is not a valid tenant key, for example with uppercase letters.

The gate treats it like an unknown tenant, without asking CIAS.

Result: 403 tenant-not-served

When: CODAMAI_PERSISTENCE_TENANT_MODE=SINGLE

CIAS determines no tenant, so the gate never asks. A tenant in the token is neither checked nor refused.

Result: See In SINGLE the tenant in the token does not count.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CIAS/cias-authentication – TokenParser.admit (gate after resolution and after the switch), TenantGate (cache, TTL, outage rule), TenantGateProperties (codamai.cias.tenant-gate.ttl 30s, max-entries 10000), TenantAdmission, RequestAdmission.TENANT_NOT_SERVED, JwtSessionFilter.refuse
  • CIAS/cias-kernel – TenantStanding, TenantKey; CIAS/cias-tenancy – Tenant.isServedOn, TenantStatus, LocalTenantLookupAdapter; CIAS/cias-tenancy-client – RemoteTenantLookupAdapter
  • commons-persistence – DatabaseRequestContext.resolveTenant (no own check any more), PersistenceErrorCode.CDMS_TENANT_NOT_SERVED
Search