Ontoserver security model

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 authorizations 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 authorizations are managed by the scope field of the JWT Token that is provided by the Authorization 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) authorization.

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 Authorization server (or mapped-equivalent values in the authorities field). These authorizations are layered over the API (/fhir) authorizations and further restrict what an entity may do.

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

Resource-level authorizations 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 authorization 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 placeholder 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 authorization, 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 authorization, but no additional checks are made.

Authorization 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.



Clarifications / Discussion

  1. Do you need write perms on the resource you’re creating?

    e.g., want to create a with label:Foo.read – need both system/*.write and grouping/Foo.read (or system/*.read), but not grouping/Foo.write?

  2. Do you need read perms on the resource you’re creating? No.

  3. If a resource only has a Foo.read label, then what are the WRITE permissions? (requires grouping/*.write)
  4. Challenge of default permissions (what can someone do if no labels attached) and explicitly allowing all and only allowing “super entity”

Use Cases / Requirements

User

  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 Authorization 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.

Actions

  1. I want to make the foo Resource available for reading to community X

    * foo.meta.security.label = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read
    
  2. I want to make the foo Resource available for reading to all (both authenticated and non-authenticated)

    * foo.meta.security.label = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|anonymous.read
    
  3. I want to make the foo Resource available for reading only to authenticated entities (regardless of community membership)

    Not sure about this one (see also 6, below). As long as anon-read mode is off, this is effectively the default assuming all entities have system/*.read. Otherwise, I don’t think its a “real” requirement.

  4. 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 authorization constraints.

    * foo.meta.security.label = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.read
    
    /synd/setSyndicationStatus?resource=[Resource]/foo&status=true
    
  5. 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

    * foo.meta.security.label[0] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read
    * foo.meta.security.label[1] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.write
    * foo.meta.security.label[2] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.read
    
  6. I want to make the foo Resource available for reading to all and for writing to community Y only

    Not right yet

    * foo.meta.security.label[0] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|*.read
    * foo.meta.security.label[1] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.write
    * foo.meta.security.label[2] = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|Y.read
    
  7. I want to create a Resource only visible to community X

    * foo.meta.security.label = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read
    
    POST /[Resource]/foo
    
  8. My CodeSystem resource requires agreement to licence X (for read access) here and in all downstream Terminology Solutions

    Create and apply category permissions for licence X products.

    * foo.meta.security.label = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read