Fine-Grained Authorization Made Easy: Modeling Google Drive in SpiceDB
December 10, 2023
Fine-Grained Authorization Made Easy: Modeling Google Drive in SpiceDB

Managing access control at a fine-grained level is a must-have for modern applications, but it's also one of the most challenging tasks in software engineering. Designing and implementing a robust, flexible, and scalable authorization system is a challenge many developers face. However, there are solutions to this problem: permission systems based on Google Zanzibar paper, such as SpiceDB. In this blog post, I will show you how to model an authorization system in SpiceDB, using Google Drive as an example.

Contents

Step 1. Describe the requirements

The first step towards building an authorization system is to describe the requirements in plain language. Try to make the sentences look like this:

As a subject, I can permission a resource if relations.

For example, we can define the Google Drive requirements as follows:

  1. A user or a group member can view a document if they are the owner, viewer, commenter, or editor or if they can view documents in the parent folder.
  2. A user or a group member can edit a document if they are the owner or editor or if they can edit documents in the parent folder.
  3. A user or a group member can comment on a document if they are the owner, editor, or commenter or if they can comment on documents in the parent folder.
  4. A user can create a document in a folder if they are the owner of the folder or if they can create a document in the parent folder.
  5. A user can delete a document if they are the owner or if they can delete documents in the parent folder.
  6. A user can share a document if they are the owner or if they can share documents in the parent folder.

Step 2. Define resources

The next step is to define the resources and their relations. Resources are the objects that the subjects can access. In Google Drive, we have two primary resources: folders and documents. Both of them might have a parent folder.

1definition folder {
2 relation parent: folder
3}
4
5definition document {
6 relation parent: folder
7}

Step 3. Define subjects

The subjects are the objects that can access the resources. In Google Drive, you can access a folder or a document by having explicit permission or being a group member.

1definition user {}
2
3definition group {
4 relation member: user
5}

Step 4. Define relations

Once we have the resources and subjects identified, we can connect them using relations. The relations will be used to finally build the permissions in the next step. You can think about relations as roles. For example, in our Google Drive example, we can define 4 relations in file and document resources:

  • Owner
  • Viewer
  • Commenter
  • Editor

Each relation can be assigned to either a user or a group. We can use subject relations to grant a role to all group members.

1definition folder {
2 relation parent: folder
3
4+ relation owner: user
5+ relation viewer: user | group#member
6+ relation commenter: user | group#member
7+ relation editor: user | group#member
8}
9
10definition document {
11 relation parent: folder
12
13+ relation owner: user
14+ relation viewer: user | group#member
15+ relation commenter: user | group#member
16+ relation editor: user | group#member
17}

Step 5. Define permissions

Now, we can use the relations to define the permissions. A rule of thumb is to have one permission for each API or action. For our example, let's define the following permissions:

  • View
  • Edit
  • Comment
  • Share
  • Delete

As the viewer of the parent folder should have access to all descendant documents, we are using the recursive permissions.

1definition folder {
2 relation parent: folder
3
4 relation owner: user
5 relation viewer: user | group#member
6 relation commenter: user | group#member
7 relation editor: user | group#member
8
9+ permission create = owner + parent->create
10+ permission share = owner + parent->share
11+ permission delete = owner + parent->delete
12
13+ permission view_documents = owner + viewer + commenter + editor + parent->view
14+ permission edit_documents = owner + editor + parent->edit
15+ permission comment_documents = owner + commenter + editor + parent->comment
16}
17
18definition document {
19 relation parent: folder
20
21 relation owner: user
22 relation viewer: user | group#member
23 relation commenter: user | group#member
24 relation editor: user | group#member
25
26+ permission view = owner + viewer + commenter + editor + parent->view_documents
27+ permission edit = owner + editor + parent->edit_documents
28+ permission comment = owner + commenter + editor + parent->comment_documents
29+ permission share = owner + parent->share
30+ permission delete = owner + parent->delete
31}

Step 6. Verify the model

The final step is to verify the model on some test data. Here is the overview of our test case:

  • The parent is the parent folder of the document document.
  • Alex is the owner of the parent folder.
  • Bob is the editor of the document file.
  • Charlie is the viewer of the document file.
  • Bob and Charlie are members of the group.
  • The group members are commenters on the document file.
1document:document#editor@user:bob
2document:document#viewer@user:charlie
3document:document#parent@folder:parent
4group:group#member@user:bob
5group:group#member@user:charlie
6document:document#commenter@group:group#member
7folder:parent#owner@user:alex

Running the expected relations on this test data gives the following results:

1document:document#comment:
2 - "[group:group#member] is <document:document#commenter>"
3 - "[user:alex] is <folder:parent#owner>"
4 - "[user:bob] is <document:document#editor>/<group:group#member>"
5 - "[user:charlie] is <group:group#member>"
6document:document#delete:
7 - "[user:alex] is <folder:parent#owner>"
8document:document#edit:
9 - "[user:alex] is <folder:parent#owner>"
10 - "[user:bob] is <document:document#editor>"
11document:document#view:
12 - "[group:group#member] is <document:document#commenter>"
13 - "[user:alex] is <folder:parent#owner>"
14 - "[user:bob] is <document:document#editor>/<group:group#member>"
15 - "[user:charlie] is <document:document#viewer>/<group:group#member>"

The following diagram visualizes who can comment on a document and why.

You can see the entire schema, with test relationships and expected relations, at https://play.authzed.com/s/yx7vtTs8YIvN/schema.