Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
Signed-off-by: Shaobo He <[email protected]>
  • Loading branch information
shaobo-he-aws committed Aug 1, 2024
1 parent 6976ad9 commit f64e143
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 244 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"principal": "User::\"alice\"",
"action": "Action::\"CreateDocument\"",
"action": "Action::\"createDocument\"",
"resource": "Drive::\"drive\"",
"context": {"is_authenticated": true}
"context": {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"principal": "User::\"alice\"",
"action": "Action::\"ViewDocument\"",
"action": "Action::\"viewDocument\"",
"resource": "Document::\"alice_public\"",
"context": {"is_authenticated": true}
"context": {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"principal": "User::\"charlie\"",
"action": "Action::\"ViewDocument\"",
"action": "Action::\"viewDocument\"",
"resource": "Document::\"alice_public\"",
"context": {"is_authenticated": true}
"context": {}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"principal": "User::\"bob\"",
"action": "Action::\"ViewDocument\"",
"action": "Action::\"viewDocument\"",
"resource": "Document::\"alice_public\"",
"context": {"is_authenticated": true}
"context": {}
}
200 changes: 70 additions & 130 deletions cedar-example-use-cases/document_cloud/README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,37 @@
# Document Cloud Drive Use-Case

Envision a cloud-based document sharing system, like Google Drive or Dropbox. This system can be used by a single user, who is working on documents across multiple of their personal computers, by multiple users, who are collaborating on a shared set of documents, or by the public as a hosting solution. Users need to be able upload, delete, and modify the sharing permissions on their documents. Users also need to be able to view, comment on, and and modify documents that they have access to, while the system enforces correct access control logic. Since this is a multi-tenant system, it must be robust to cross-user abuse. This system includes a blocklist feature to prevent that.
Envision a cloud-based document sharing system, like Google Drive or Dropbox. This system can be used by a single user, who is working on documents across multiple of their personal computers, by multiple users, who are collaborating on a shared set of documents, or by the public as a hosting solution. Users need to be able upload, delete, and modify the sharing permissions on their documents. Users also need to be able to view, comment on, and and modify documents that they have access to, while the system enforces correct access control logic. Since this is a multi-tenant system, it must be robust to cross-user abuse. This system includes a block list feature to prevent that.

We first define the entities involved in this system.
## Entities

### `User`
`User`s are the main principals of the system. They are the ones who view/edit/delete documents, as well as the ones who control sharing permissions on documents. `User`s may also block other users. For instance, if Alice blocks Bob, then Bob should not be able to view any documents Alice owns, or share anything with Alice.

We assume that all `User`s are authenticated before requesting any authorization.

### `Group`
For convenience, `User`s can be organized into `Group`s. Documents can be shared with entire `Group`s at once. We’ll borrow from Unix and say that every `User` also has a `Group` containing only them.

### `Public`
A principal that represents an un-authenticated user.

### `Document`

`Document`s are the core resource of the system. Every document has an owner, which is the `User` who created it. Documents have 3 axis of sharing

* Private: only the owner can view/edit/comment/delete the document
* ACL: List of users/groups that are allowed view, groups allowed to comment, groups allowed to edit, groups allowed to manage.
* Public: Can the public view/edit/comment on the document
`Document`s are the core resource of the system. Every document has an owner, which is the `User` who created it. `Document` uses access control lists (ACLs) to manage permissions for action types such as view, edit, and manage.
An ACL is modeled as a `Group`.

It is always enforced that only the owner can delete or edit the sharing state of a document

Next we define the actions that principals can perform.

## Actions

* `CreateDocument`: Create a new document in the system. Any authenticated user can do this.
* `ViewDocument`: Must pass ACL check
* `DeleteDocument`: Only the owner should be able do this.
* `CommentOnDocument`: Must pass ACL check
* `ModifyDocument`: Must pass ACL check
* `EditIsPrivate`: Only the owner can do this
* `AddToShareACL`: Anyone who has manage access can do this. The owner can never have their access be revoked.
* `EditPublic`: Anyone who has edit access can do this.
* `CreateGroup`: Any authenticated user can do this
* `ModifyGroup`: Only the owner of the group can do this
* `DeleteGroup`: Only the owner of the group can do this
* `createDocument`: Create a new document in the system.
* `viewDocument`: View a document.
* `deleteDocument`: Delete a document.
* `modifyDocument`: Modify a document.
* `addToShareACL`: Share a document.
* `createGroup`: Create a group.
* `modifyGroup`: Modify a group.
* `deleteGroup`: Delete a group.


Let’s take this and turn it into a concrete schema:
Expand All @@ -47,70 +40,48 @@ Let’s take this and turn it into a concrete schema:

* `User`
* attributes
* `personalGroup` a EUID of type `Group`, links to the group containing exactly this user
* `blocked` a set of EUIDs of type `User`.
* memberOf: `Group`, can be a member of any group.
* Invariants:
* for any `User` `u`, `u in u.personalGroup` should always be true
* as well as `u == u.personalGroup.owner`
* `Group`
* attributes:
* `owner`: a EUID of type `User`, denoting who can manage this group
* memberOf: `DocumentShare`
* `Document`
* attributes:
* `owner` an EUID of type `User`
* `isPrivate` a boolean
* `publicAccess` a string, one of: `none`, `view`, or `edit`
* `viewACL` an EUID of type `DocumentShare`
* `modifyACL` an EUID of type `DocumentShare`
* `manageACL` an EUID of type `DocumentShare`
* `DocumentShare`
* A group-entity. All children of this entity are `group`s that are allowed to perform some action on a document
* `Public`
* There is exactly one instance of `public` that represents the un-authenticated user.
* memberOf: `DocumentShare`
* `viewACL` an EUID of type `Group`
* `modifyACL` an EUID of type `Group`
* `manageACL` an EUID of type `Group`
* `Drive`
* A “container entity” that represents the entire application.

### Action Types

* `CreateDocument`: Create a new document in the system. Any authenticated user can do this.
* `createDocument`: Create a new document in the system. Any authenticated user can do this.
* principals: `User`
* resources: `Drive`
* `ViewDocument`: Must pass ACL check
* principals: `User`
* resources: `Document`
* `DeleteDocument`: Only the owner should be able do this.
* principals: `User`
* resources: `Document`
* `ModifyDocument`: Must pass ACL check
* `viewDocument`: Must pass ACL check
* principals: `User`
* resources: `Document`
* `EditIsPrivate`: Only the owner can do this
* `deleteDocument`: Only the owner should be able do this.
* principals: `User`
* resources: `Document`
* `AddToShareACL`: Anyone who has manage access can do this. The owner can never have their access be revoked.
* `modifyDocument`: Must pass ACL check
* principals: `User`
* resources: `Document`
* `EditPublicAccess`: Anyone who has manage access can do this.
* `addToShareACL`: Anyone who has manage access can do this. The owner can never have their access be revoked.
* principals: `User`
* resources: `Document`
* `CreateGroup`: Any authenticated user can do this
* `createGroup`: Any authenticated user can do this
* principals: `User`
* resources: `Drive`
* `ModifyGroup`: Only the owner of the group can do this
* `modifyGroup`: Only the owner of the group can do this
* principals: `User`
* resources: `Group`
* `DeleteGroup`: Only the owner of the group can do this
* `deleteGroup`: Only the owner of the group can do this
* principals: `User`
* resources: `Group`

## Context

* `is_authenticated`: Whether or not the request is from an authenticated user
* type: `Boolean`


Finally, let's look at the policies for permission management.
## Policies
Expand All @@ -119,135 +90,104 @@ Finally, let's look at the policies for permission management.


```
@id("drive-owner")
permit (
principal,
action == Action::"CreateDocument",
resource == Drive::"drive"
);
principal,
action,
resource is Drive
)
when { resource.owner == principal };
```

Any authenticated user should be able to make a document. Since the only valid principal-type here is `User`, this accomplishes that. However, the “authenticated” part isn’t anywhere *in* the policy, and isn’t checked at runtime.
There are a couple of solutions here:

1. Create an entity `Users::"AllUsers"` that every user is a part of. This makes the graph rather big, but maybe we don’t care.
2. An `is` operator, ex: `principal is User`
3. Runtime enforcement of action types.
Any `User` should be able to perform any action on a `Drive`, including `createDocument`.

### Viewing Documents

The owner should always be able to view the document.

The owner should always be able to perform any action on a `Document`, including `viewDocument`.
```
@id("document-owner")
permit (
principal,
action == Action::"ViewDocument",
resource
principal,
action,
resource is Document
)
when { principal == resource.owner };
```

Anyone who is in the view ACL should be able to view the document, when it’s not private
Anyone who is in the view ACL should be able to view the document

```
@id("viewACL")
permit (
principal,
action == Action::"ViewDocument",
resource
principal,
action == Action::"viewDocument",
resource
)
when { principal in resource.viewACL }
unless { resource.isPrivate };
when { principal in resource.viewACL };
```

An un-authenticated principal can view only when explicitly permitted
Any `User` can view a `Document` when it's publicly readable and editable.

```
@id("public-view")
permit (
principal == Public::"public",
action == Action::"ViewDocument",
resource
principal,
action == Action::"viewDocument",
resource
)
when { resource.publicAccess == "view" || resource.publicAccess == "edit" }
unless { resource.isPrivate };
when { resource.publicAccess == "view" || resource.publicAccess == "edit" };
```

### Delete Document

Simiarly, only the owner can do this

```
permit (
principal,
action == Action::"deleteDocument",
resource
)
when { principal == resource.owner };
```
Only the owner can perform this action, indicated by the policy with annotation `id@("document-owner")`.

### Modify Document

Very similar to viewing, just different ACL:

```
@id("modifyACL")
permit (
principal,
action == Action::"ModifyDocument",
resource
principal,
action == Action::"modifyDocument",
resource
)
when { principal == resource.owner };
when { principal in resource.modifyACL };
@id("public-edit")
permit (
principal,
action == Action::"ModifyDocument",
resource
principal,
action == Action::"modifyDocument",
resource
)
when { principal in resource.modifyACL }
unless { resource.isPrivate };
permit (
principal == Public::"public",
action == Action::"ViewDocument",
resource
)
when { resource.publicAccess == "edit" }
unless { resource.isPrivate };
when { resource.publicAccess == "edit" };
```

### Document Management

A `User` can share a `Document` if they are in the `manageACL` group.
```
@id("manageACL")
permit (
principal,
action in
[Action::"EditIsPrivate",
Action::"AddToShareACL",
Action::"EditPublicAccess"],
resource
)
when { principal == resource.owner };
permit (
principal,
action in [Action::"AddToShareACL", Action::"EditPublicAccess"],
resource
principal,
action in Action::"addToShareACL",
resource
)
when { principal in resource.manageACL };
```

### Group Management

Similar to `createDocument`, any `User` can perform group management actions as long as they own the group.
```
@id("group-owner")
permit (
principal,
action == Action::"CreateGroup",
resource == Drive::"drive"
);
permit (
principal,
action in [Action::"ModifyGroup", Action::"DeleteGroup"],
resource
principal,
action,
resource is Group
)
when { principal == resource.owner };
when { resource has owner && principal == resource.owner };
```

### Blocking
Expand Down
Loading

0 comments on commit f64e143

Please sign in to comment.