Security

  1. API-level policies
  2. Resource-level policies
  3. Authorisation process
  4. Use cases

Ontoserver’s security model has two layers – API-level policies and Resource-level policies.

The policies themselves consist of the required permissions for an API request or a Resource, and the API and Resource-level authorisations granted to an entity.

Furthermore, Ontoserver can be operated at different enforcement levels via the configuration properties:

Property Options
ontoserver.security.enabled false, true, fine
ontoserver.security.readOnly.fhir false, true
ontoserver.security.readOnly.api false, true
ontoserver.security.readOnly.synd false, true

API-level policies

Ontoserver can be configured to enforce role-based access control (RBAC) permissions with ontoserver.security.enabled equal to either true or fine.

Ontoserver provides three endpoint API families: /api (Admin), /fhir (FHIR), and /synd (Syndication). Within each of these familes there are two role types: READ and WRITE, corresponding to whether the operation can change the state of the server (WRITE) or not (READ).

Additionally, there is one operation-specific permission for [base]/CodeSystem/$x-upload-external.

These authorisations are managed by the scope field of the JWT Token that is provided by the Authorisation server. Ontoserver understands the following scopes:

  • system/*.read
  • system/*.write
  • system/CodeSystem.x-upload-external
  • onto/api.read
  • onto/api.write
  • onto/synd.read
  • onto/synd.write

Equivalently the authorities field can be used with the following corresponding values:

  • FHIR_READ
  • FHIR_WRITE
  • FHIR_CS_X_UE
  • API_READ
  • API_WRITE
  • SYND_READ
  • SYND_WRITE

If the Ontoserver is operating in “anonymous read” mode (i.e., ontoserver.security.readOnly.fhir=true), then all entities, whether authenticated or not, are deemed to have system/*.read (equivalently, FHIR_READ) authorisation.

Resource-level policies

Ontoserver can be configured to enforce Resource-level access control with ontoserver.security.enabled equal to fine.

Resource instance level authorizations are also managed by the scope field of the JWT Token that is provided by the Authorisation server (or mapped-equivalent values in the authorities field). These authorisations are layered over the API (/fhir) authorisations and further restrict what an entity may do.

This means an entity’s API-level authorisations cannot be increased via this mechanism, but only reduced.

Resource-level authorisations are managed through FHIR’s security labels model. Security labels are attached to a Resource’s meta element.

Ontoserver uses codes from the CodeSystem http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions to manage access to resources. This CodeSystem is open-ended and has codes of the form: [category].read and [category].write, where [category] names an authorisation category, and is a non-empty sequence of the characters conforming to the regular expression [_a-zA-Z0-9].

Ontoserver understands the following scopes (where [category] is a place holder described below):

  • grouping/*.read
  • grouping/*.write
  • grouping/[category].read
  • grouping/[category].write

or equivalent authorities values:

  • PERM_READ
  • PERM_WRITE
  • PERM_[category]_READ
  • PERM_[category]_WRITE

If a resource has any security labels from this CodeSystem then the following rules are applied:

  1. For READ access to any given Resource with a security label from the above CodeSystem and of the form [category].read, Ontoserver will check that the entity’s JWT Token contains a matching scope value grouping/[category].read (or contains grouping/*.read).
  2. For READ access to any given Resource with a security label from the above CodeSystem and of the form *.read, the entity must have API (/fhir) READ authorisation, but no additional checks are made.
  3. For WRITE access to any given Resource with a security label from the above CodeSystem and of the form [category].write, Ontoserver will check that the entity’s JWT Token contains a matching scope value grouping/[category].write (or contains grouping/*.write).
  4. For WRITE access to any given Resource with a security label from the above CodeSystem and of the form *.write, the entity must have API (/fhir) WRITE authorisation, but no additional checks are made.

Notes

A user only requires write permission to a resource to add security labels, and does not need read or write permission for the labels they are adding. So a user may add foo.read without having read access to the foo category themselves. This enables those with write access to resources to grant permissions to categories they may not themselves have rights to.

This does mean that users are able to modify security labels on a resource such that they no longer have read and/or write access themselves. This may be intentional, however if this occurs accidentally the grouping/*.write scope (PERM_WRITE authority) will allow a user to write to any resource regardless of its other security labels. Typically this scope is given to highly trusted users or administrators and allows them to correct security labels in this scenario.

When creating a resource only the system/*.write scope (FHIR_WRITE authority) is required – no security labels are in play on the server as the resource does not yet exist on the server. Similar to a resource update scenario, a user creating a resource can specify security labels in the resource meta on creation and need not have permission for these labels themselves in order to add these labels in resource creation.

If a resource is created with no security labels on a server with resource-level access control enabled, any user with the system/*.read (FHIR_READ authority) and/or system/*.write scope (FHIR_WRITE authority) will be able to read and/or modify the resource. I.e. no security labels on a resource implies no resource-level authority is necessary and only API-level authority is required for that resource until a security label is added.

Write permissions do not imply read permissions – i.e. adding the label foo.write does not imply foo.read which must additionally be explicitly added if the foo category requires both read and write permission.

Authorisation process

When an entity requests authorization, it can ask for grouping/*.read and grouping/*.write. The authorization server will either return a set of scopes specific to appropriate permissions categories of the entity, or the all categories scopes grouping/*.read and grouping/*.write, if appropriately authorised.

Note that these all categories scopes grouping/*.read (grouping/*.write) convey READ (WRITE) access to all resources, regardless of their security label(s).

Note, a scope conveying WRITE permissions does not also convey READ permissions.

Use cases and requirements

  1. A user U has a maximum level of permission that cannot be increased through granting of category permissions. e.g., They only have READ access and this cannot be changed. User U would have permission system/*.read but NOT system/*.write. If the user also has permissions grouping/X.write then this will not allow them WRITE access to any resources because they lack the base system/*.write permission.
  2. User U belongs to communities X and Y. This would be managed in the Authorisation server. Ontoserver knows nothing about group membership and it does not need to be included in the JWT Token.
  3. Members of X can write some resources but only read others; need to be able to specify read/write permissions for a community separately. This is supported by the separate .read and .write forms of the security labels.
  4. You must have write permissions on an existing resource in order to set/update its permissions. For any WRITE action there are either one or two resource instances involved, the latest (active) instance in the the server at the time of the action, and the desired instance in the server following successful execution of the action. Permissions are checked against the existing instance only, not the new instance.
  5. I want to make the foo Resource available for reading only to authenticated entities (regardless of community membership)
    • This can be achieved by running Ontoserver NOT in “anonymous read” mode (i.e., ontoserver.security.readOnly.fhir=false) and not specifying any security labels on the resource.
    • If security labels must be used on the resource (for example to control write access) then a default.read (any term can be used, default is simply an example) security label can be added to the resource and configured into the authorisation server to be added by default to all authenticated users. This second approach will work with ontoserver.security.readOnly.fhir set to true or false.
Action foo.meta.security.label setting
I want to make the foo Resource available for reading to community X http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read
I want to make the foo Resource available for reading to all (both authenticated and non-authenticated) http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|*.read
I want to make the foo Resource available in the syndication feed to community Y.
FHIR Resources in the syndication feed use the normal FHIR read instance URL and are thus subject to normal authorisation constraints.
http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.read
/synd/setSyndicationStatus?resource=[Resource]/foo&status=true
I want to make the foo Resource available for reading to community X and for writing to community Y.
Note that community Y is also given READ permission in the following as would normally be expected
label[0] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read
label[1] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.write
label[2] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.read
I want to make the foo Resource available for reading to all and for writing to community Y only
label[0] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|*.read
label[1] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.write
label[2] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.read
I want to create a Resource only visible to community X
http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read
My CodeSystem resource requires agreement to licence X (for read access) here and in all downstream Terminology SolutionsCreate and apply category permissions for licence X products. http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read