Restrict documents access
Document Access Control describes who should be allowed to do what on the documents in a collection. At a high level, these are the steps to set it up:
- Create a policy – Describe the set of rules that will apply to some documents.
- Register a policy – Upload the policy into DefraDB.
- Create a permissioned collection – Attach the policy to a collection.
- Grant permissions to other actors – Create relations between an identity and a document.
When access control is configured, each actor should authenticate with their private key. An actor that creates a document in a permissioned collection owns the document. Authenticated requests can see public documents and the private documents they have permission to; unauthenticated requests can access only public documents.
Create policies
A policy is the set of rules to enforce on the documents it will be applied to.
name: A basic policy
description: Thou shall read but not pass
resources:
- name: books
relations:
- name: reader
- name: updater
- name: deleter
permissions:
- name: read
expr: reader
- name: update
expr: updater + deleter
- name: delete
expr: deleter
name– Policy name.description(optional) – Policy description.resources– List of permissions definitions.name– Permission object name (refer to this when creating a permissioned collection).relations– List of relations that actors may be given to act on documents (similar to user roles).name– Relation name.
permissions– List specifying which relation will get which permission.name– Permission name (read,update,delete).expr(optional) – Expression involvingrelationsnames. Actors who fulfill the expression get the permission. Supported operators are union+and subtraction-.
- The
permissionslist must include all ofread,update,delete, even ifexpris not specified. You can include more permissions: DefraDB will ignore them, but other applications may use them.
- The document creator gets all permissions, even if you omit a permission expression. For example, this policy grants read permission to
readeractors and write permissions only to the document creator:- name: readexpr: reader- name: update- name: delete - Relations allowed to update or delete automatically get permission to read. Subtract those relations if you don't want that:
name: readexpr: reader - updater - deleter
Relation managers
The owner of a document has always the privilege to grant permissions to other actors.
The relation type manages gives other actors the permission to grant permissions (i.e. create relations) of the specified type. They become managers of the relations given in the manages list.
relations:
- name: reader
- name: admin
manages:
- reader
Register policies
A policy doesn't do anything until it's added into DefraDB. The request to register a policy must be authenticated. The returned PolicyID allows you to attach the policy to a collection.
- CLI
- HTTP API
Register a policy via the CLI command defradb client acp document policy add. The example sources the policy from file, but argument string and stdin are supported too.
defradb client acp document policy add -f policy.yml \
--identity b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f
{
"PolicyID": "9528839e7dac8d2c236ced23d49dcfb1cc1ece86a1329c7c512755ba1f56ca37"
}
Register a policy by submitting a POST request to the HTTP endpoint /api/v1/acp/document/policy. The request body should contain the policy content in YAML format.
POST http://localhost:9181/api/v1/acp/document/policy HTTP/2
accept: application/json
authorization: Bearer <jwtToken>
content-type: text/plain
name: A basic policy
description: Thou shall read but not pass
resources:
- name: books
relations:
- name: reader
- name: updater
- name: deleter
permissions:
- name: read
expr: reader
- name: update
expr: updater + deleter
- name: delete
expr: deleter
{
"PolicyID": "9528839e7dac8d2c236ced23d49dcfb1cc1ece86a1329c7c512755ba1f56ca37"
}
Create permissioned collections
For a policy to apply to some documents, the policy needs to be registered with the collection holding such documents. Use the @policy directive to attach a policy to a collection, providing the policy ID and the name of the resource to attach. The result (and further calls to defradb client collection describe) shows the details under the Policy key.
type Book @policy(
id: "9528839e7dac8d2c236ced23d49dcfb1cc1ece86a1329c7c512755ba1f56ca37",
resource: "books"
) {
title: String
}
[
{
"Name": "Book",
"VersionID": "bafyreihfhq442e6dand4n35dkwmaiwsmoiqytp2prz7eqzrikpgupwpj5u",
"CollectionID": "bafyreihfhq442e6dand4n35dkwmaiwsmoiqytp2prz7eqzrikpgupwpj5u",
"CollectionSet": null,
"Query": null,
"PreviousVersion": null,
"Fields": [
{
"FieldID": "bafyreihqzhiz3iwro4jozp6kphq4sosg6ccoqcbiaf7rg5dmvea7aux55a",
"Name": "_docID",
"Kind": 1,
"Typ": 0,
"RelationName": null,
"IsPrimary": false,
"DefaultValue": null,
"Size": 0
},
{
"FieldID": "bafyreihfb2izf5akjuua5jkijrgsgievsspboopupjq2its25owgle5pzm",
"Name": "title",
"Kind": 11,
"Typ": 1,
"RelationName": null,
"IsPrimary": false,
"DefaultValue": null,
"Size": 0
}
],
"Indexes": [],
"EncryptedIndexes": [],
"Policy": {
"ID": "9528839e7dac8d2c236ced23d49dcfb1cc1ece86a1329c7c512755ba1f56ca37",
"ResourceName": "book"
},
"IsActive": true,
"IsMaterialized": true,
"IsBranchable": false,
"IsEmbeddedOnly": false,
"IsPlaceholder": false,
"VectorEmbeddings": []
}
]
Private and public documents
Permissioned collections can contain both private and public documents. Documents created without an identity are visible to all actors; documents created with an identity are subject to the permission rules of the policy attached to the collection. For information on how to authenticate with an identity, see Authentication.
defradb client query '
mutation {
add_Book(input: {
title: "1984",
}) {
_docID
title
}
}
defradb client query --identity b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f '
mutation {
add_Book(input: {
title: "Animal Farm",
}) {
_docID
title
}
}
defradb client query '
{
Book {
_docID
title
}
}
'
{
"data": {
"Book": [
{
"_docID": "bae-72bb6e1c-479f-584c-8f63-2756c3bd63ca",
"title": "1984"
}
]
}
}
Private documents get synced to other nodes only if their identities have the appropriate permissions in the node serving the documents. However, local policies don't get synced together with the private documents they are attached to. For more information, see P2P and private documents.
Grant permissions to other actors
To give another actor permission to access or alter a document, create a relation between the actor and the document ID. The relation defines what type of permission (according to the collection's policy) the actor will get. You can think that the relation assigns the identity a role (ex. reader) with respect to a specific document. Target actors are identified by their DID key.
The only actors allowed to grant permissions to others are the policy creator and the identities with the appropriate manage relation. The request to create a relation must be authenticated.
You can only create relations to private documents (i.e. documents created with an identity). Public documents are not registered in the DAC system and cannot be permissioned.
- CLI
- HTTP API
Give an actor permissions to a given document via the CLI command defradb client acp document relationship add
defradb client acp document relationship add \
--collection Book \
--docID bae-04ba3b88-1ac9-54f0-89b5-6abedff7201f \
--relation reader \
--actor did:key:z7r8osuVyok8SVnHH5tsyNDRGyniu9pQoqBt7misXTEJAon5vYCt72NmFpya4NUiLjPfyDvvayNMbYRrnqLMYjpD1cAgp \
--identity b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f
{
"ExistedAlready": false
}
Give an actor permissions to a given document by submitting a POST request to the HTTP endpoint /api/v1/acp/document/relationship.
POST http://localhost:9181/api/v1/acp/document/relationship HTTP/2
accept: application/json
authorization: Bearer <jwtToken>
content-type: application/json
{
"CollectionName": "Book",
"DocID": "bae-04ba3b88-1ac9-54f0-89b5-6abedff7201f",
"Relation": "reader",
"TargetActor": "did:key:z7r8osuVyok8SVnHH5tsyNDRGyniu9pQoqBt7misXTEJAon5vYCt72NmFpya4NUiLjPfyDvvayNMbYRrnqLMYjpD1cAgp"
}
{
"ExistedAlready": false
}
Adding an already-existing relation doesn't result in an error: the return value ExistedAlready shows whether the relation is new or was already in place.
Grant permissions to everybody
To grant a specific permission to any actor, use the wildcard "*" as value for the actor's identity.
- CLI
- HTTP API
defradb client acp document relationship add \
--collection Book \
--docID bae-04ba3b88-1ac9-54f0-89b5-6abedff7201f \
--relation reader \
--actor "*" \
--identity b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f
POST http://localhost:9181/api/v1/acp/document/relationship HTTP/2
accept: application/json
authorization: Bearer <jwtToken>
content-type: application/json
{
"CollectionName": "Book",
"DocID": "bae-04ba3b88-1ac9-54f0-89b5-6abedff7201f",
"Relation": "reader",
"TargetActor": "*"
}
Revoke permissions
To revoke an actor's document permissions, delete their relation with the given document ID. Revoking relations granted to any actor with "*" only revokes that individual relation: it doesn't revoke all relations registered for any actor.
The only actors allowed to revoke permissions are the policy creator and the identities with the appropriate manage relation. The request to delete a relation must be authenticated.
- CLI
- HTTP API
Revoke an actor's permissions to a given document via the CLI command defradb client acp document relationship delete
defradb client acp document relationship delete \
--collection Book \
--docID bae-04ba3b88-1ac9-54f0-89b5-6abedff7201f \
--relation reader \
--actor did:key:z7r8osuVyok8SVnHH5tsyNDRGyniu9pQoqBt7misXTEJAon5vYCt72NmFpya4NUiLjPfyDvvayNMbYRrnqLMYjpD1cAgp \
--identity b17a7b973f629b900cf23654db9c4be935f90281707dd3e2cd7a56bdd2c1bf4f
{
"RecordFound": true
}
Revoke an actor's permissions to a given document by submitting a DELETE request to the HTTP endpoint /api/v1/acp/document/relationship.
DELETE http://localhost:9181/api/v1/acp/document/relationship HTTP/2
accept: application/json
authorization: Bearer <jwtToken>
content-type: application/json
{
"CollectionName": "Book",
"DocID": "bae-04ba3b88-1ac9-54f0-89b5-6abedff7201f",
"Relation": "reader",
"TargetActor": "did:key:z7r8osuVyok8SVnHH5tsyNDRGyniu9pQoqBt7misXTEJAon5vYCt72NmFpya4NUiLjPfyDvvayNMbYRrnqLMYjpD1cAgp"
}
{
"RecordFound": true
}
Deleting a non-existing relation doesn't result in an error: the return value RecordFound shows whether the relation existed or not prior to deletion.