What this is about
Above every path on which CIAS grants permissions stands one rule:
The ceiling is not a setting. There is no switch, no role and no entry in the role catalog that turns it off.
Why is it needed? Without a ceiling, a tenant administrator could give a new colleague, or themselves, a role they never had. A single careless entry in the catalog would then be a path to every permission in the installation.
The set diagram
Picture a person’s permissions as a set. What they grant must lie entirely inside this set.
flowchart LR
subgraph H["What Anna holds in tenant nordbau"]
direction TB
R1["hr-employee-read"]
R2["hr-employee-edit"]
A1["attribute projects = alpha, beta"]
end
V1["grants hr-employee-read"] -- "contained ✔" --> R1
V2["grants projects = alpha"] -- "contained ✔" --> A1
V3["grants hr-salary-read"] -. "not contained ✘" .-> H
V4["grants projects = gamma"] -. "not contained ✘" .-> H
Anna may pass on what is in the box, and nothing beyond it. Whether Anna may pass it on at all is decided by delegation as well.
Delegation and ceiling are two questions
Easily confused:
- a list in the role catalog: who may grant the role
- configurable per installation
- protects against everyone handing out permissions
- compares with what you hold yourself
- not configurable
- protects against someone making an account stronger than themselves
Both have to agree. Neither replaces the other: having a role does not mean you may pass it on. And being on the delegation list only lets you grant what you hold yourself.
| Delegation allows it? | In their own tenant? | Do they hold the role themselves? | Result |
|---|---|---|---|
| no | – | – | 403 |
| yes | no | – | 403 |
| yes | yes | no | 403, the ceiling applies |
| yes | yes | yes | role is granted |
For a role grant, all refusals look the same: 403 with the text not permitted, without a reason. That way nobody can find out the installation’s rules by trial and error. CIAS writes the exact reason to the log. See Refusals that reveal nothing.
CIAS decides what you hold
The obvious idea would be to compare the roles in the caller’s token. That does not work. The token only contains the client of this deployment, and the role names appear there without their client. cdms-backend / model-editor and crms-backend / model-editor would look the same.
So CIAS calculates what you hold from its own records:
-
CIASPersonDoes the token belong to a person CIAS knows?↳ no you hold nothing
-
CIASGrantsWhich of your role grants are active now and apply globally or in exactly this tenant?
-
CIASGroupsWhich groups are you a member of? Their roles count too
-
CIASAttributesWhich attribute values do you have in exactly this tenant?
- Your ceiling, exact down to client and key
It follows that:
- A grant that starts later or has expired does not count.
- A role you have in another tenant does not count here.
- A role that someone granted by hand in the Keycloak console does not count. CIAS does not know it. You can then pass on less than you actually have. That is the safe direction.
This only works because only CIAS writes permissions into Keycloak. See The write direction.
Each variant
When: Someone grants a role by hand.
-
1Admin→CIASgrants
cdms-backend/hr-employee-editto a person in tenantnordbau -
2CIASIs the role a platform role? Then only a platform administrator may
-
3CIASIs the caller on the role's delegation list?
-
4CIASIs
nordbauthe tenant from their token? -
5CIASDo they hold
cdms-backend/hr-employee-editthemselves innordbau? -
6CIAS→Keycloakwrites the grant
Result: Granted, or 403 at the first check that fails.
When: It is about groups, as the source of your permissions or as something being granted.
For your ceiling, the roles of your groups count, not the membership. Being a member of a group is not a permission of its own. Whoever adds a person to a group gives them all roles of the group at once. Groups and members are managed only by a platform administrator, who holds every permission.
Result: Group roles count towards what you hold.
When: Someone writes an attribute value per tenant, for example projects for a person in nordbau.
-
1CIASIs the attribute registered in the catalog? If not, nobody may write it
-
2CIASDoes the attribute's delegation allow the caller to write?
-
3CIASIs every written value contained in their own value in this tenant?
-
4CIASstores the values, all or none
Result: Written, or 403. If one value fails, nothing is written at all.
When: The caller has the role platform-admin.
A platform administrator creates roles, maintains the delegation and can therefore reach every permission anyway. Their ceiling is therefore every permission. This is not an exception to the rule but its application: they hold everything, so they may grant everything. Without this, a fresh installation could never go live, because the first administrator could give nobody anything.
Result: Always passes the ceiling.
Attributes: when a value is “contained”
In CDMS an attribute value narrows down rows. One more value is more reach, and * turns the filter off. CIAS therefore compares exactly the way the filter reads the values: split at commas, spaces trimmed, * as “everything”.
| own value | written value | Result |
|---|---|---|
alpha, beta | alpha | allowed, alpha is contained |
alpha, beta | beta, alpha | allowed, order does not matter |
alpha, beta | gamma | refused |
alpha, beta | * | refused, * is more than any single value |
* | anything | allowed |
| none | alpha | refused, whoever has nothing gives nothing |
| – | empty | allowed: clearing takes reach away. Delegation still has to agree |
Where the ceiling applies
| Path | Who may take it | Ceiling |
|---|---|---|
| grant a role by hand | per delegation, in their own tenant | yes, as the last check |
| write a rule for the registration’s initial roles | per delegation | yes: whoever writes a rule must hold every role in it |
| write an attribute value per tenant | per the attribute’s delegation | yes, with the value comparison above |
| create and change groups, add members | platform administrator | always passes |
| write an attribute value on the person (profile in Keycloak) | platform administrator | always passes |
Next
- Grant a role
- Who may write an attribute
- The two permission matrices: how a permission is carried