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:
-
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 matchingscope
valuegrouping/[category].read
(or containsgrouping/*.read
). -
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. -
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 matchingscope
valuegrouping/[category].write
(or containsgrouping/*.write
). -
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.
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.
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.
Use Cases / Requirements
User
-
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 permissionsystem/*.read
but NOTsystem/*.write
. If the user also has permissionsgrouping/X.write
then this will not allow them WRITE access to any resources because they lack the basesystem/*.write
permission. -
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.
-
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. -
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
-
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
-
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|*.read
-
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 with work withontoserver.security.readOnly.fhir
set totrue
orfalse
. -
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
-
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
-
I want to make the foo Resource available for reading to all and for writing to community Y only
* 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
-
I want to create a Resource only visible to community X
* foo.meta.security.label = 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 Solutions
Create and apply category permissions for licence X products.
* foo.meta.security.label = http://ontoserver.csiro.au/CodeSystem/ontoserver-permissions|X.read