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.
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
-
Do you need write perms on the resource you’re creating?
e.g., want to create
a
withlabel:Foo.read
– need bothsystem/*.write
andgrouping/Foo.read
(orsystem/*.read
), but notgrouping/Foo.write
? -
Do you need read perms on the resource you’re creating? No.
- If a resource only has a
Foo.read
label, then what are the WRITE permissions? (requiresgrouping/*.write
) - 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
-
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|anonymous.read
-
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. -
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
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
-
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
-
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