CodamAIDocs
Topicdone

The three levels at a glance

Model (may I run this operation?), relation (may I go through this field?) and row (may I access this object?). How the levels apply one after another.

Variants
Reading and searchingChanging and deletingCreatingnested request

What this is about

Every request to CDMS has to pass several questions before any data flows. The questions sit on three levels:

LevelQuestionHow CDMS answers it
ModelMay you run this operation on this model?with a role in the token, e.g. hr-employee-read
RelationMay you go through this field into another model?with the role of the other model or a field role on the relation
RowMay you see or change exactly this object?with filters: own data, attribute filters, custom filters of the project

A role is a name like hr-employee-read that is in the person’s token. A filter is a condition that CDMS invisibly adds to every query, for example “only rows of this person”.

The funnel

Before the three levels comes the tenant. It is not a check inside CDMS. It decides which database CDMS searches in the first place.

flowchart TB
    T["Token and tenant<br/>CIAS checks the token, picks the tenant"] --> M
    M["Model<br/>role for the operation?"] --> B
    B["Relation<br/>role of the target model or field role?"] --> Z
    Z["Row<br/>own data, attribute filters, custom filters"] --> D["Data"]
    T -. "no token or invalid token" .-> E1["401 / 403"]
    M -. "role missing" .-> E2["403"]
    B -. "role missing" .-> E3["403"]
    Z -. "row invisible" .-> E4["404 or missing from the list"]

What happens before CDMS, meaning checking the token and picking the tenant, is described in Access without a token and Tenants.

The levels when reading

POST /hr/employee/read/{id} with the company in the response
  1. CDMS
    Model
    Do you have the read role of employee?
    ↳ no 403 missing-permission|<read role>
  2. CDMS
    Row
    Do the filters of employee let this row through?
    ↳ no 404 not-found
  3. CDMS
    Relation
    The response names company. Do you have the read role of company or the field role on employee.company?
    ↳ no 403 missing-permission|<role>
  4. CDMS
    Row of the company
    Do the filters of company let the company through?
    ↳ no company is null, no error
  5. 200 with employee and company

Searching works the same way, except that invisible rows are simply missing from the list. See Filters that always run along.

The levels when changing and deleting

When writing, the order is different: CDMS checks the row first, then the role.

PATCH /hr/employee/update/{id}
  1. CDMS
    Row
    Does the row exist, and do the filters let it through? The same filters as for reading.
    ↳ no 404 not-found|<Dto>|<id>
  2. CDMS
    Model
    Do you have the update role of employee?
    ↳ no 403 missing-permission|<update role>
  3. CDMS
    Relation
    Does the request also change a child? Then you need its role or the field role.
    ↳ no 403 missing-permission|<role>
  4. 200, changed and read back

This way CDMS does not reveal whether someone else’s object exists: whoever may not see it gets 404, no matter which roles they have. See Why invisible objects return 404.

The levels compared

What each level decides
Model
role per operation
  • applies to all rows of the model
  • missing → 403
  • Details: Model roles
Relation
role of the target model or field role
  • applies only to the path through this field
  • missing → 403
  • Details: Field roles
Row
filters

Simple fields have no level of their own. Whoever may read a model may read its simple fields, unless a field carries a role of its own. Then they also need this role, otherwise the field is missing from the response. See Protected values.

Variants

Which levels a request goes through

When: read, query

  1. 1
    CDMS
    checks the read role of the model
  2. 2
    CDMS→Database
    reads only rows that pass all filters
  3. 3
    CDMS
    checks, for each relation in the response, the role of the target model or the field role

Result: Role missing → 403. Invisible → 404 when reading by id; in a search the row is missing.

When: PUT, PATCH, DELETE, rollback

  1. 1
    CDMS→Database
    counts the row with the filters used for reading
  2. 2
    CDMS
    checks the role of the model for the operation
  3. 3
    CDMS
    checks, for each child that is changed or deleted along with it, its role or the field role

Result: First 404, then 403. You do not need a read role for this.

When: create

  1. 1
    CDMS
    checks the create role of the model
  2. 2
    CDMS
    checks, for each child created along with it, its role or the field role
  3. 3
    CDMS
    reads the new object back, which needs the read role

Result: The row level only checks during the read-back here. For user models CDMS sets the owner itself, see Own data.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-authorization – AbstractAuthorizationLayer (classAccess, accessGrantedByField)
  • CDMS/cdms-system-layer – AbstractLayer (recursiveRead, recursiveQuery, recursivePrepare, enterField, addSecurityFilters, buildSearchRoot, assertVisibleForWrite), AbstractSystemLayer
  • CIAS/cias-authentication – JwtSessionFilter, TokenParser
  • CDMS/cdms-integrationtest – AbstractRoleDenialTest, AbstractFieldRoleTest, AbstractDataFilterTest
  • documentation/40-sicherheit
Search