You are browsing the docs for Nexus v1.9.x, the latest release is available here
Access Control Lists
Access Control Lists are rooted in the /v1/acls
collection.
An ACL defines the applications’ data access restriction using the following three parameters:
- permission: the value used to limit a client (user, group) access to resources.
- identity: a client identity reference, e.g. a certain user, a group, an anonymous user or someone who is authenticated to a certain realm.
- path: the location where to apply the restrictions. Examples of paths are:
/
,/myorg
or/myorg/myproject
When modifying ACLs, the caller must have acls/write
permissions on the path where the ACLs are being modified or its ancestors.
When reading ACLs, the caller must have acls/read
permissions on the path where the ACLs are being modified or its ancestors.
Please visit Authentication & authorization section to learn more about it.
Default permissions
When the service starts for the first time, it applies the default permissions to /
. This gives all permissions to the anonymous user to enable setting up realms. It is recommended to replace these permissions once user has setup an authorization realm.
ACLs Hierarchy
It is important to know that ACLs are represented in a tree-like structure depending on their path. Imagine the following scenario:
Each block is identified by a path that contains a list of permissions for a certain identity (identities are color code divided).
There is a special set of permissions which restrict the use of the ACLs API:
- acls/read - an auth. token containing an identity with this permission is allowed to fetch a collection of ACL from any other identity.
- acls/write - an auth. token containing an identity with this permission is allowed to perform the call to the following endpoints: create ACLs, replace ACLs, subtract ACLs, append ACLs and delete ACLs.
Those permissions need to be present in the current {path}
where the API interaction occurs or in any parent path. In other words, they are inherited.
Let’s clarify this concept with an example from the previous diagram. identity 1
could call the create ACLs endpoint on any {path}
while identity 2
could only call the same endpoint for any path child of /myorg
(like /myorg/myproj
). At the same time, identity 3
could not perform any of the write operations.
Create
This operation creates a collection of ACL on the provided path.
PUT /v1/acls/{path}
{...}
…where {path}
is the target location for the ACL collection.
The json payload contains the collection of ACL to set.
Example
- Request
-
source
curl -XPUT \ -H "Content-Type: application/json" \ "http://localhost:8080/v1/acls/org1" -d \ '{ "acl": [ { "permissions": [ "projects/read" ], "identity": { "realm": "myrealm", "group": "a-group" } }, { "permissions": [ "projects/read", "projects/write" ], "identity": { "realm": "realm", "group": "some-group" } }, { "permissions": [ "acls/read", "acls/write" ], "identity": { "realm": "realm", "subject": "alice" } } ] }'
- Payload
-
source
{ "acl": [ { "permissions": [ "projects/read" ], "identity": { "realm": "myrealm", "group": "a-group" } }, { "permissions": [ "projects/read", "projects/write" ], "identity": { "realm": "myrealm", "group": "some-group" } }, { "permissions": [ "acls/read", "acls/write" ], "identity": { "realm": "myrealm", "subject": "alice" } } ] }
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/acls-metadata.json", "https://bluebrain.github.io/nexus/contexts/metadata.json" ], "@id": "http://localhost:8080/v1/acls/org1", "@type": "AccessControlList", "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2021-05-11T11:03:06.071Z", "_createdBy": "http://localhost:8080/v1/anonymous", "_deprecated": false, "_path": "/org1", "_rev": 1, "_self": "http://localhost:8080/v1/acls/org1", "_updatedAt": "2021-05-11T11:03:06.071Z", "_updatedBy": "http://localhost:8080/v1/anonymous" }
Replace
This operation overrides the collection of ACL on the provided path.
PUT /v1/acls/{path}?rev={previous_rev}
{...}
…where:
{previous_rev}
: Number - the last known revision for the ACL collection. Not required for replacing empty ACLs.{path}
: String - is the target location for the ACL collection.
The json payload contains the collection of ACL to set.
Example
- Request
-
source
curl -XPUT \ -H "Content-Type: application/json" "http://localhost:8080/v1/acls/org1?rev=1" -d \ '{ "acl": [ { "permissions": [ "projects/read" ], "identity": { "realm": "myrealm", "group": "a-group" } }, { "permissions": [ "projects/read", "projects/write" ], "identity": { "realm": "realm", "group": "some-group" } }, { "permissions": [ "acls/read", "acls/write" ], "identity": { "realm": "realm", "subject": "alice" } } ] }'
- Payload
-
source
{ "acl": [ { "permissions": [ "projects/read" ], "identity": { "realm": "myrealm", "group": "a-group" } }, { "permissions": [ "projects/read", "projects/write" ], "identity": { "realm": "myrealm", "group": "some-group" } }, { "permissions": [ "acls/read", "acls/write" ], "identity": { "realm": "myrealm", "subject": "alice" } } ] }
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/acls-metadata.json", "https://bluebrain.github.io/nexus/contexts/metadata.json" ], "@id": "http://localhost:8080/v1/acls/org1", "@type": "AccessControlList", "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2021-05-11T11:03:06.071Z", "_createdBy": "http://localhost:8080/v1/anonymous", "_deprecated": false, "_path": "/org1", "_rev": 2, "_self": "http://localhost:8080/v1/acls/org1", "_updatedAt": "2021-05-11T11:03:32.596Z", "_updatedBy": "http://localhost:8080/v1/anonymous" }
Subtract
This operation removes the provided ACL collection from the existing collection of ACL on the provided path.
PATCH /v1/acls/{path}?rev={previous_rev}
{...}
…where:
{previous_rev}
: Number - the last known revision for the ACL collection.{path}
: String - is the target location for the ACL collection.
The json payload contains the collection of ACL to remove.
Example
- Request
-
source
curl -XPATCH \ -H "Content-Type: application/json" \ "http://localhost:8080/v1/acls/org1?rev=2" -d \ '{ "@type": "Subtract", "acl": [ { "permissions": [ "projects/read" ], "identity": { "group": "a-group", "realm": "myrealm" } } ] }'
- Payload
-
source
{ "@type": "Subtract", "acl": [ { "permissions": [ "projects/read" ], "identity": { "realm": "myrealm", "group": "a-group" } } ] }
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/acls-metadata.json", "https://bluebrain.github.io/nexus/contexts/metadata.json" ], "@id": "http://localhost:8080/v1/acls/org1", "@type": "AccessControlList", "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2021-05-11T11:03:06.071Z", "_createdBy": "http://localhost:8080/v1/anonymous", "_deprecated": false, "_path": "/org1", "_rev": 3, "_self": "http://localhost:8080/v1/acls/org1", "_updatedAt": "2021-05-11T11:03:52.875Z", "_updatedBy": "http://localhost:8080/v1/anonymous" }
Append
This operation appends the provided ACL collection to the existing collection of ACL on the provided path.
PATCH /v1/acls/{path}?rev={previous_rev}
{...}
…where:
{previous_rev}
: Number - the last known revision for the ACL collection. Not required for appending to empty ACLs.{path}
: String - is the target location for the ACL collection.
The json payload contains the collection of ACL to add.
Example
- Request
-
source
curl -XPATCH \ -H "Content-Type: application/json" \ "http://localhost:8080/v1/acls/org1?rev=3" -d \ '{ "@type": "Append", "acl": [ { "permissions": [ "own", "other" ], "identity": { "realm": "myrealm", "group": "a-group" } } ] }'
- Payload
-
source
{ "@type": "Append", "acl": [ { "permissions": [ "own", "other" ], "identity": { "realm": "myrealm", "group": "a-group" } } ] }
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/acls-metadata.json", "https://bluebrain.github.io/nexus/contexts/metadata.json" ], "@id": "http://localhost:8080/v1/acls/org1", "@type": "AccessControlList", "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2021-05-11T11:03:06.071Z", "_createdBy": "http://localhost:8080/v1/anonymous", "_deprecated": false, "_path": "/org1", "_rev": 4, "_self": "http://localhost:8080/v1/acls/org1", "_updatedAt": "2021-05-11T11:04:54.614Z", "_updatedBy": "http://localhost:8080/v1/anonymous" }
Delete
This operation deletes the entire collection of ACL on the provided path.
DELETE /v1/acls/{path}?rev={previous_rev}
…where:
{previous_rev}
: Number - the last known revision for the ACL collection.{path}
: String - is the target location for the ACL collection.
- Request
-
source
curl -XDELETE "http://localhost:8080/v1/acls/org1?rev=4"
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/acls-metadata.json", "https://bluebrain.github.io/nexus/contexts/metadata.json" ], "@id": "http://localhost:8080/v1/acls/org1", "@type": "AccessControlList", "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2021-05-11T11:03:06.071Z", "_createdBy": "http://localhost:8080/v1/anonymous", "_deprecated": false, "_path": "/org1", "_rev": 5, "_self": "http://localhost:8080/v1/acls/org1", "_updatedAt": "2021-05-11T11:05:15.919Z", "_updatedBy": "http://localhost:8080/v1/anonymous" }
Fetch
GET /v1/acls/{path}?rev={rev}&self={self}
…where
{path}
: String - is the target location for the ACL collection.{rev}
: Number - the revision of the ACL to be retrieved. This parameter is optional and it defaults to the current revision.{self}
: Boolean - iftrue
, only the ACLs containing the identities found on the auth. token are included in the response. Iffalse
all the ACLs on the current{path}
are included. This parameter is optional and it defaults totrue
.
The ability to use the query parameter self=false
depends on whether or not any of the identities found on the auth. token contains the acls:read
permission on the provided {path}
or its ancestors. For further details, check ACLs hierarchy.
- Request
-
source
curl "http://localhost:8080/v1/acls/org1?rev=1&self=false"
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/metadata.json", "https://bluebrain.github.io/nexus/contexts/search.json", "https://bluebrain.github.io/nexus/contexts/acls.json" ], "_total": 1, "_results": [ { "@id": "http://localhost:8080/v1/acls/org1", "@type": "AccessControlList", "acl": [ { "identity": { "@id": "http://localhost:8080/v1/realms/myrealm/groups/a-group", "@type": "Group", "group": "a-group", "realm": "myrealm" }, "permissions": [ "projects/read" ] }, { "identity": { "@id": "http://localhost:8080/v1/realms/realm/groups/some-group", "@type": "Group", "group": "some-group", "realm": "realm" }, "permissions": [ "projects/read", "projects/write" ] }, { "identity": { "@id": "http://localhost:8080/v1/realms/realm/users/alice", "@type": "User", "realm": "realm", "subject": "alice" }, "permissions": [ "acls/read", "acls/write" ] } ], "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2021-05-11T11:03:06.071Z", "_createdBy": "http://localhost:8080/v1/anonymous", "_deprecated": false, "_path": "/org1", "_rev": 1, "_self": "http://localhost:8080/v1/acls/org1", "_updatedAt": "2021-05-11T11:03:06.071Z", "_updatedBy": "http://localhost:8080/v1/anonymous" } ] }
List
GET /v1/acls/{path}?ancestors={ancestors}&self={self}
…where
{path}
: String - is the target location for the ACL collection.{ancestors}
: Boolean - iftrue
, the ACLs of the parent{path}
are included in the response. Iffalse
only the ACLs on the current{path}
are included. This parameter is optional and it defaults tofalse
.{self}
: Boolean - iftrue
, only the ACLs containing the identities found on the auth. token are included in the response. Iffalse
all the ACLs on the current{path}
are included. This parameter is optional and it defaults totrue
.
The ability to use the query parameter self=false
and ancestors=true
depends on whether or not any of the identities found on the auth. token contains the acls:read
permission on the provided {path}
or its parents. For further details, check ACLs hierarchy.
The {path}
can contain the special character *
which can be read as any
.
Let’s imagine we have the ACLs from the following diagram in place. If we query this endpoint with the path /myorg/*
, we are selecting the ACLs defined in /myorg/myproj
and myorg/myproj2
. Likewise If we use the path /*
, we are selecting the ACLs defined in /myorg
and myorg2
.
The following examples illustrate listings from the diagram on the section ACLs hierarchy with the following considerations:
- identity 1: Is a group called
one
- identity 2: Is a group called
two
- identity 3: Is a user called
me
- The auth. token is linked to the
identity 1
.
- Request
-
source
curl "http://localhost:8080/v1/acls/*?ancestors=true&self=true"
- Response
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/metadata.json", "https://bluebrain.github.io/nexus/contexts/search.json", "https://bluebrain.github.io/nexus/contexts/acls.json" ], "_total": 2, "_results": [ { "@id": "http://localhost:8080/v1/acls/myorg/myproj", "@type": "AccessControlList", "acl": [ { "permissions": [ "read", "write" ], "identity": { "@id": "http://localhost:8080/v1/realm/groups/two", "@type": "Group", "realm": "myrealm", "group": "two" } } ], "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2018-09-17T14:55:42.939Z", "_createdBy": "http://localhost:8080/v1/realms/myrealm/users/john", "_deprecated": false, "_path": "/myorg/myproj", "_rev": 1, "_self": "http://localhost:8080/v1/acls/myorg/myproj", "_updatedAt": "2018-09-17T15:05:42.939Z", "_updatedBy": "http://localhost:8080/v1/realms/myrealm/users/john" }, { "@id": "http://localhost:8080/v1/acls/myorg/myproj2", "@type": "AccessControlList", "acl": [ { "permissions": [ "read" ], "identity": { "@id": "http://localhost:8080/v1/realms/myrealm/users/me", "@type": "User", "realm": "myrealm", "subject": "me" } } ], "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2018-09-17T14:00:42.939Z", "_createdBy": "http://localhost:8080/v1/realms/myrealm/users/alice", "_deprecated": false, "_path": "/myorg/myproj2", "_rev": 2, "_self": "http://localhost:8080/v1/acls/myorg/myproj2", "_updatedAt": "2018-09-17T14:05:42.939Z", "_updatedBy": "http://localhost:8080/v1/realms/myrealm/users/alice" } ] }
- Request (with ancestors)
-
source
curl "http://localhost:8080/v1/acls/myorg/*?ancestors=false&self=false"
- Response (with ancestors)
-
source
{ "@context": [ "https://bluebrain.github.io/nexus/contexts/resource.json", "https://bluebrain.github.io/nexus/contexts/iam.json", "https://bluebrain.github.io/nexus/contexts/search.json" ], "_total": 3, "_results": [ { "@id": "http://localhost:8080/v1/acls/", "@type": "AccessControlList", "acl": [ { "permissions": [ "acls/write" ], "identity": { "@id": "http://localhost:8080/v1/realms/myrealm/groups/one", "@type": "Group", "realm": "myrealm", "group": "one" } } ], "_createdAt": "2018-09-17T14:55:42.939Z", "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdBy": "http://localhost:8080/v1/realms/myrealm/users/john", "_deprecated": false, "_path": "/", "_rev": 1, "_self": "http://localhost:8080/v1/acls", "_updatedAt": "2018-09-17T15:05:42.939Z", "_updatedBy": "http://localhost:8080/v1/realms/myrealm/users/john" }, { "@id": "http://localhost:8080/v1/acls/myorg", "@type": "AccessControlList", "acl": [ { "permissions": [ "acls/write" ], "identity": { "@id": "http://localhost:8080/v1/realms/myrealm/groups/two", "@type": "Group", "realm": "myrealm", "group": "two" } } ], "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2018-09-17T14:00:42.939Z", "_createdBy": "http://localhost:8080/v1/realms/myrealm/users/alice", "_deprecated": false, "_path": "/myorg", "_rev": 2, "_self": "http://localhost:8080/v1/acls/myorg", "_updatedAt": "2018-09-17T14:05:42.939Z", "_updatedBy": "http://localhost:8080/v1/realms/myrealm/users/alice" }, { "@id": "http://localhost:8080/v1/acls/myorg2", "@type": "nxv:AccessControlList", "acl": [ { "permissions": [ "other" ], "identity": { "@id": "http://localhost:8080/v1/realms/myrealm/groups/one", "@type": "Group", "realm": "myrealm", "group": "one" } } ], "_constrainedBy": "https://bluebrain.github.io/nexus/schemas/acls.json", "_createdAt": "2018-09-17T14:00:42.939Z", "_deprecated": false, "_createdBy": "http://localhost:8080/v1/realms/myrealm/users/alice", "_path": "/myorg2", "_rev": 1, "_self": "http://localhost:8080/v1/acls/myorg2", "_updatedAt": "2018-09-17T14:05:42.939Z", "_updatedBy": "http://localhost:8080/v1/realms/myrealm/users/alice" } ] }
ACL Server Sent Events
This endpoint allows clients to receive automatic updates from the ACLs in a streaming fashion.
GET /v1/acls/events
where Last-Event-Id
is an optional HTTP Header that identifies the last consumed ACL event. It can be used for cases when a client does not want to retrieve the whole event stream, but to start after a specific event.
The response contains a series of ACL events, represented in the following way
data:{payload}
event:{type}
id:{id}
where…
{payload}
: Json - is the actual payload of the current ACL{type}
: String - is a type identifier for the current ACL. Possible types are: AclAppended, AclSubtracted, AclReplaced, AclDeleted{id}
: String - is the identifier of the ACL event. It can be used in theLast-Event-Id
HTTP Header
Example
- Request
-
source
curl "http://localhost:8080/v1/acls/events"
- Response
-
source
data:{"@context":["https://bluebrain.github.io/nexus/contexts/metadata.json","https://bluebrain.github.io/nexus/contexts/acls.json"],"@type":"AclReplaced","acl":[{"identity":{"@id":"http://localhost:8080/v1/realms/myrealm/groups/a-group","@type":"Group","group":"a-group","realm":"myrealm"},"permissions":["projects/read"]},{"identity":{"@id":"http://localhost:8080/v1/realms/realm/groups/some-group","@type":"Group","group":"some-group","realm":"realm"},"permissions":["projects/read","projects/write"]},{"identity":{"@id":"http://localhost:8080/v1/realms/realm/users/alice","@type":"User","realm":"realm","subject":"alice"},"permissions":["acls/read","acls/write"]}],"_aclId":"http://localhost:8080/v1/acls/org1","_instant":"2021-05-11T11:03:06.071Z","_path":"/org1","_rev":1,"_subject":"http://localhost:8080/v1/anonymous"} event:AclReplaced id:76848d80-b248-11eb-a0d9-6dedbaa155f8 data:{"@context":["https://bluebrain.github.io/nexus/contexts/metadata.json","https://bluebrain.github.io/nexus/contexts/acls.json"],"@type":"AclReplaced","acl":[{"identity":{"@id":"http://localhost:8080/v1/realms/myrealm/groups/a-group","@type":"Group","group":"a-group","realm":"myrealm"},"permissions":["projects/read"]},{"identity":{"@id":"http://localhost:8080/v1/realms/realm/groups/some-group","@type":"Group","group":"some-group","realm":"realm"},"permissions":["projects/read","projects/write"]},{"identity":{"@id":"http://localhost:8080/v1/realms/realm/users/alice","@type":"User","realm":"realm","subject":"alice"},"permissions":["acls/read","acls/write"]}],"_aclId":"http://localhost:8080/v1/acls/org1","_instant":"2021-05-11T11:03:32.596Z","_path":"/org1","_rev":2,"_subject":"http://localhost:8080/v1/anonymous"} event:AclReplaced id:8653f250-b248-11eb-a0d9-6dedbaa155f8 data:{"@context":["https://bluebrain.github.io/nexus/contexts/metadata.json","https://bluebrain.github.io/nexus/contexts/acls.json"],"@type":"AclSubtracted","acl":[{"identity":{"@id":"http://localhost:8080/v1/realms/myrealm/groups/a-group","@type":"Group","group":"a-group","realm":"myrealm"},"permissions":["projects/read"]}],"_aclId":"http://localhost:8080/v1/acls/org1","_instant":"2021-05-11T11:03:52.875Z","_path":"/org1","_rev":3,"_subject":"http://localhost:8080/v1/anonymous"} event:AclSubtracted id:926a46c0-b248-11eb-a0d9-6dedbaa155f8 data:{"@context":["https://bluebrain.github.io/nexus/contexts/metadata.json","https://bluebrain.github.io/nexus/contexts/acls.json"],"@type":"AclAppended","acl":[{"identity":{"@id":"http://localhost:8080/v1/realms/myrealm/groups/a-group","@type":"Group","group":"a-group","realm":"myrealm"},"permissions":["own","other"]}],"_aclId":"http://localhost:8080/v1/acls/org1","_instant":"2021-05-11T11:04:54.614Z","_path":"/org1","_rev":4,"_subject":"http://localhost:8080/v1/anonymous"} event:AclAppended id:b736bf60-b248-11eb-a0d9-6dedbaa155f8 data:{"@context":["https://bluebrain.github.io/nexus/contexts/metadata.json","https://bluebrain.github.io/nexus/contexts/acls.json"],"@type":"AclDeleted","_aclId":"http://localhost:8080/v1/acls/org1","_instant":"2021-05-11T11:05:15.919Z","_path":"/org1","_rev":5,"_subject":"http://localhost:8080/v1/anonymous"} event:AclDeleted id:c3e9c900-b248-11eb-a0d9-6dedbaa155f8