From f64e143862d485a3adc2ab3770aced90a2fe0d8d Mon Sep 17 00:00:00 2001 From: Shaobo He Date: Thu, 1 Aug 2024 13:00:37 -0700 Subject: [PATCH] updates Signed-off-by: Shaobo He --- .../ALLOW/alice_create_authenticated.json | 4 +- .../ALLOW/alice_view_alice_public.json | 4 +- .../ALLOW/charlie_view_alice_public.json | 4 +- .../DENY/alice_create_unauthenticated.json | 6 - .../DENY/bob_view_alice_public.json | 4 +- .../document_cloud/README.md | 200 ++++++------------ .../document_cloud/entities.json | 122 ++--------- 7 files changed, 100 insertions(+), 244 deletions(-) delete mode 100644 cedar-example-use-cases/document_cloud/DENY/alice_create_unauthenticated.json diff --git a/cedar-example-use-cases/document_cloud/ALLOW/alice_create_authenticated.json b/cedar-example-use-cases/document_cloud/ALLOW/alice_create_authenticated.json index 4a53cd2..bcdd6d3 100644 --- a/cedar-example-use-cases/document_cloud/ALLOW/alice_create_authenticated.json +++ b/cedar-example-use-cases/document_cloud/ALLOW/alice_create_authenticated.json @@ -1,6 +1,6 @@ { "principal": "User::\"alice\"", - "action": "Action::\"CreateDocument\"", + "action": "Action::\"createDocument\"", "resource": "Drive::\"drive\"", - "context": {"is_authenticated": true} + "context": {} } \ No newline at end of file diff --git a/cedar-example-use-cases/document_cloud/ALLOW/alice_view_alice_public.json b/cedar-example-use-cases/document_cloud/ALLOW/alice_view_alice_public.json index 5f0251a..540cbed 100644 --- a/cedar-example-use-cases/document_cloud/ALLOW/alice_view_alice_public.json +++ b/cedar-example-use-cases/document_cloud/ALLOW/alice_view_alice_public.json @@ -1,6 +1,6 @@ { "principal": "User::\"alice\"", - "action": "Action::\"ViewDocument\"", + "action": "Action::\"viewDocument\"", "resource": "Document::\"alice_public\"", - "context": {"is_authenticated": true} + "context": {} } \ No newline at end of file diff --git a/cedar-example-use-cases/document_cloud/ALLOW/charlie_view_alice_public.json b/cedar-example-use-cases/document_cloud/ALLOW/charlie_view_alice_public.json index 4a92983..aa82efa 100644 --- a/cedar-example-use-cases/document_cloud/ALLOW/charlie_view_alice_public.json +++ b/cedar-example-use-cases/document_cloud/ALLOW/charlie_view_alice_public.json @@ -1,6 +1,6 @@ { "principal": "User::\"charlie\"", - "action": "Action::\"ViewDocument\"", + "action": "Action::\"viewDocument\"", "resource": "Document::\"alice_public\"", - "context": {"is_authenticated": true} + "context": {} } \ No newline at end of file diff --git a/cedar-example-use-cases/document_cloud/DENY/alice_create_unauthenticated.json b/cedar-example-use-cases/document_cloud/DENY/alice_create_unauthenticated.json deleted file mode 100644 index 099b531..0000000 --- a/cedar-example-use-cases/document_cloud/DENY/alice_create_unauthenticated.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "principal": "User::\"alice\"", - "action": "Action::\"CreateDocument\"", - "resource": "Drive::\"drive\"", - "context": {"is_authenticated": false} -} \ No newline at end of file diff --git a/cedar-example-use-cases/document_cloud/DENY/bob_view_alice_public.json b/cedar-example-use-cases/document_cloud/DENY/bob_view_alice_public.json index e27317b..e975cd4 100644 --- a/cedar-example-use-cases/document_cloud/DENY/bob_view_alice_public.json +++ b/cedar-example-use-cases/document_cloud/DENY/bob_view_alice_public.json @@ -1,6 +1,6 @@ { "principal": "User::\"bob\"", - "action": "Action::\"ViewDocument\"", + "action": "Action::\"viewDocument\"", "resource": "Document::\"alice_public\"", - "context": {"is_authenticated": true} + "context": {} } diff --git a/cedar-example-use-cases/document_cloud/README.md b/cedar-example-use-cases/document_cloud/README.md index 7d34efb..bcfece6 100644 --- a/cedar-example-use-cases/document_cloud/README.md +++ b/cedar-example-use-cases/document_cloud/README.md @@ -1,6 +1,6 @@ # 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 @@ -8,19 +8,15 @@ We first define the entities involved in this system. ### `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 @@ -28,17 +24,14 @@ 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: @@ -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 @@ -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 diff --git a/cedar-example-use-cases/document_cloud/entities.json b/cedar-example-use-cases/document_cloud/entities.json index 8aeae7b..e46aab9 100644 --- a/cedar-example-use-cases/document_cloud/entities.json +++ b/cedar-example-use-cases/document_cloud/entities.json @@ -5,12 +5,6 @@ "id": "alice" }, "attrs": { - "personalGroup": { - "__entity": { - "type": "Group", - "id": "alice_personal" - } - }, "blocked": [ { "__entity": { @@ -33,12 +27,6 @@ "id": "bob" }, "attrs": { - "personalGroup": { - "__entity": { - "type": "Group", - "id": "bob_personal" - } - }, "blocked": [] }, "parents": [ @@ -54,12 +42,6 @@ "id": "charlie" }, "attrs": { - "personalGroup": { - "__entity": { - "type": "Group", - "id": "charlie_personal" - } - }, "blocked": [] }, "parents": [ @@ -75,12 +57,6 @@ "id": "alice_personal" }, "attrs": { - "owner": { - "__entity": { - "type": "User", - "id": "alice" - } - } }, "parents": [] }, @@ -90,19 +66,8 @@ "id": "bob_personal" }, "attrs": { - "owner": { - "__entity": { - "type": "User", - "id": "bob" - } - } }, - "parents": [ - { - "type": "DocumentShare", - "id": "alice_public_view" - } - ] + "parents": [] }, { "uid": { @@ -110,19 +75,8 @@ "id": "charlie_personal" }, "attrs": { - "owner": { - "__entity": { - "type": "User", - "id": "charlie" - } - } }, - "parents": [ - { - "type": "DocumentShare", - "id": "alice_public_view" - } - ] + "parents": [] }, { "uid": { @@ -136,59 +90,20 @@ "id": "alice" } }, - "isPrivate": false, "publicAccess": "view", - "viewACL": { - "__entity": { - "type": "DocumentShare", - "id": "alice_public_view" - } - }, - "modifyACL": { - "__entity": { - "type": "Document", - "id": "alice_public_modify" - } - }, - "manageACL": { - "__entity": { - "type": "Document", - "id": "alice_public_manage" - } - } - }, - "parents": [] - }, - { - "uid": { - "type": "DocumentShare", - "id": "alice_public_view" - }, - "attrs": {}, - "parents": [] - }, - { - "uid": { - "type": "DocumentShare", - "id": "alice_public_modify" - }, - "attrs": {}, - "parents": [] - }, - { - "uid": { - "type": "DocumentShare", - "id": "alice_public_manage" - }, - "attrs": {}, - "parents": [] - }, - { - "uid": { - "type": "Public", - "id": "unauthenticated" + "viewACL": [ + {"__entity": { + "type": "Group", + "id": "bob_personal" + }}, + {"__entity": { + "type": "Group", + "id": "charlie_personal" + }} + ], + "modifyACL": [], + "manageACL": [] }, - "attrs": {}, "parents": [] }, { @@ -196,7 +111,14 @@ "type": "Drive", "id": "drive" }, - "attrs": {}, + "attrs": { + "owner": { + "__entity": { + "type":"User", + "id":"alice" + } + } + }, "parents": [] } ] \ No newline at end of file