CodamAIDocs
Topicdone

Effective roles: global or in the tenant

How CIAS builds the valid roles from global roles and roles of the organization, and why globally granted roles can drop away under a dynamic tenant.

Variants
global roles onlyOrganization without its own rolesOrganization with its own roles (replaces)Realm roles (always)user switch with the target person's roles

What this is about

In a person’s token, roles can be in two places:

  • global under resource_access.<client>.roles: these roles apply everywhere.
  • in the tenant in the organization claim under organization.<alias>.resource_access.<client>.roles: these roles only apply when the request runs in this tenant.

On every request, CIAS builds the effective roles from this: the roles that apply to exactly this request. CDMS checks only against these.

Why replace instead of add? Nobody granted a globally granted role for this one tenant. If it applied too, a permission could “leak” from one context into a tenant it was never meant for. A tenant that has its own roles therefore decides alone which business roles apply in it.

The decision

Which business roles apply to the request?
Is the tenant of the request dynamic?Does the person have roles there, for any client?effectiveUserRoles
no–the global client roles
yesnothe global client roles
yesyesonly the roles in the tenant, for its own client, plus the realm roles the organization grants

The realm roles from realm_access.roles are always in effectiveUserRealmRoles, unchanged.

Before and after

flowchart LR
    subgraph V["In the token"]
      direction TB
      G1["global:<br/>hr-employee-read<br/>report-read"]
      O1["in tenant nordbau:<br/>hr-employee-edit"]
      R1["Realm:<br/>allowed-tenant-context-switch"]
    end
    subgraph N["Effective in nordbau"]
      direction TB
      E1["Business roles:<br/>hr-employee-edit"]
      E2["Realm roles:<br/>allowed-tenant-context-switch"]
    end
    O1 --> E1
    R1 --> E2
    G1 -. "drop away" .-> N

The four variants

Four cases

When: Static tenant, SINGLE, or the person belongs to no organization.

The business roles are the global client roles of its own client. There is no organization claim, or it does not count.

Result: effectiveUserRoles = resource_access.<client>.roles

When: Dynamic tenant, but the person has no roles in the organization.

The organization only determines the tenant, not the roles. The global client roles apply. That is why simply switching on organizations in Keycloak takes nobody's permissions away.

Result: effectiveUserRoles = global client roles

When: Dynamic tenant, and the person has roles in the organization.

The roles in the tenant replace the global ones. From the organization claim, only the own client counts: the claim contains the tenant roles of all clients, and the others are none of this deployment's business.

Result: effectiveUserRoles = roles in the tenant for its own client

When: always

Realm roles like platform-admin, allowed-tenant-context-switch or allowed-user-context-switch always apply, in every tenant. An organization cannot add to them. Otherwise, whoever manages a tenant could give themselves platform permissions.

Result: effectiveUserRealmRoles = realm_access.roles

And the attributes?

The same pattern applies to attributes. If an attribute is registered per tenant, CIAS fetches the value for the active tenant and replaces the value from the token with it. If CIAS cannot fetch the value, it refuses the request instead of falling back to the value in the token. See One value per person or per tenant.

And after a user switch?

After a user switch with the header user-roles: target, CIAS builds the effective roles for the target person, following the same rules as above. If they are a member of the tenant’s organization and the membership carries roles, these replace their global client roles. Their realm roles apply as always. Without user-roles: target, the effective roles stay those of the logged-in person.

Next

Sources in the code and the knowledge base
  • CIAS/cias-authentication – EffectiveRoles.resolve, EffectiveAttributes.resolve, TokenParser.admit, TokenParser.switchUser, KeycloakOrganizationClaimReader
  • CIAS/cias-iam-keycloak – KeycloakRepresentedIdentityAdapter (roles and organizations of the target person of a user switch)
  • CIAS/cias-authorization – RoleAssignmentService (pushGrant, refuseAnInvisibleGlobalGrant)
  • CIAS/cias-authorization/docs/adr – ADR-023, ADR-031, ADR-034
  • CIAS/CLAUDE.md – §13.1, §13.2
Search