From 3db31f5e8fd276560a736aff240b23916577a6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Aguiar?= Date: Mon, 9 Sep 2024 10:21:02 -0700 Subject: [PATCH] chore: improved scenarios descriptions, added listusers/objects tests (#35) * chore: improved scenarios descriptions, added listusers/objects tests * chore: removed comments --- README.md | 2 + stores/advanced-entitlements/README.md | 6 +- stores/banking/README.md | 4 +- stores/condition-data-types/README.md | 4 +- stores/custom-roles/store.fga.yaml | 24 ++++- stores/developer-portal/README.md | 14 ++- stores/developer-portal/store.fga.yaml | 23 +++- stores/entitlements/store.fga.yaml | 24 ++++- stores/expenses/store.fga.yaml | 25 ++++- stores/gdrive/store.fga.yaml | 25 ++++- stores/github/store.fga.yaml | 25 ++++- stores/github/tuples.yaml | 0 stores/groups-resource-attributes/README.md | 4 +- stores/iot/store.fga.yaml | 23 +++- stores/ip-based-access/README.md | 6 +- stores/ip-based-access/store.fga.yaml | 5 + stores/modular/README.md | 54 +++++++++- stores/modular/wiki.fga | 1 - stores/slack/store.fga.yaml | 23 ++++ stores/superadmin/README.md | 6 +- stores/superadmin/store.fga.yaml | 113 +++++++++++++------- stores/temporal-access/README.md | 8 +- stores/temporal-access/store.fga.yaml | 29 ++++- 23 files changed, 371 insertions(+), 77 deletions(-) delete mode 100644 stores/github/tuples.yaml diff --git a/README.md b/README.md index faa1647..e7623e2 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ The OpenFGA [Getting Started](https://openfga.dev/docs/modeling/getting-started) - [Implementing Multi-Tenancy in Chroma: Part 2 - Authorization Model with OpenFGA](https://cookbook.chromadb.dev/strategies/multi-tenancy/authorization-model-with-openfga/) - [Introduction into OpenFGA](https://www.ericksegaar.com/2024/03/04/introduction-into-openfga/) +- ## OpenFGA models in open source projects @@ -69,6 +70,7 @@ The OpenFGA [Getting Started](https://openfga.dev/docs/modeling/getting-started) - [sourcegraph/sourcegraph-public-snapshot](https://github.com/sourcegraph/sourcegraph-public-snapshot/blob/main/cmd/enterprise-portal/service/iam_model.fga) - [klothoplatform/infracopilot](https://github.com/klothoplatform/infracopilot/blob/main/src/auth_service/model.fga) + If you are using OpenFGA in your open source project, please let us know by opening a PR to add your model to this list. ## Resources diff --git a/stores/advanced-entitlements/README.md b/stores/advanced-entitlements/README.md index e4e2c0c..9df4c96 100644 --- a/stores/advanced-entitlements/README.md +++ b/stores/advanced-entitlements/README.md @@ -1,11 +1,13 @@ # OpenFGA Advanced Entitlements Sample Store -* **Title**: **Advanced Entitlements** - ## Use-Case This entitlements model is inspired on [Notion's subscription plans](https://www.notion.so/pricing). +Entitlements limits can be defined based on feature usage like number of collaborators, rows synced, page history days. + +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). + ## Try It Out 1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) diff --git a/stores/banking/README.md b/stores/banking/README.md index 57d0368..e484f7c 100644 --- a/stores/banking/README.md +++ b/stores/banking/README.md @@ -1,11 +1,11 @@ # OpenFGA Banking Sample Store -* **Title**: **Bankings** - ## Use-Case It models a banking system, with account managers and account owners, where they have different limits for doing bank transactions. The limit can be overruled for a specific transaction. +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). + ## Try It Out 1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) diff --git a/stores/condition-data-types/README.md b/stores/condition-data-types/README.md index 63f046b..d6f0015 100644 --- a/stores/condition-data-types/README.md +++ b/stores/condition-data-types/README.md @@ -1,13 +1,13 @@ # OpenFGA Condition Data Types Store -* **Title**: **Condition Data Types Store** - ## Use-Case OpenFGA's Conditional Relationship Tuples are defined using [Google's CEL expressions](https://github.com/google/cel-spec/blob/master/doc/langdef.md). This example showcases the different data types and expressions that are supported in OpenFGA conditions and how to use them. +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). + ## Try It Out 1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) diff --git a/stores/custom-roles/store.fga.yaml b/stores/custom-roles/store.fga.yaml index ad3b12a..d1b3951 100644 --- a/stores/custom-roles/store.fga.yaml +++ b/stores/custom-roles/store.fga.yaml @@ -104,7 +104,7 @@ tuples: relation: member object: team:qa tests: - - name: Test + - name: Test for different user/permissions check: - user: user:carlos object: org:contoso @@ -139,3 +139,25 @@ tests: object: asset-category:website-media assertions: asset_creator: true + + - name: Test which asserts can Beth view + list_objects: + - user: user:beth + type: asset + assertions: + view: + - asset:homepage + - asset:website-hero-image + + - name: Test users can view the homepage asset + list_users: + - object: asset:homepage + user_filter: + - type: user + assertions: + view: + users: + - user:beth + - user:daniel + - user:carlos + - user:anne diff --git a/stores/developer-portal/README.md b/stores/developer-portal/README.md index dcbfb3b..5b91ac2 100644 --- a/stores/developer-portal/README.md +++ b/stores/developer-portal/README.md @@ -2,25 +2,23 @@ ## Use-Case -If your application provides a way to generate API keys to applications to call your APIs, you'll want to create a dashboard where users can manage API keys, and define each API key's permissions. +It models a developer portal for a B2B SaaS application, where customers can define applications that will make calls to your APIs. -For this example, we have the following requirements +For this example, we have the following requirements: -- We want to support multiple customers, and each one should be able to define regular members and administrators for their account. +- Each customer should be able to define regular members and administrators. - Each customer should be able to define multiple applications. - Each customer's administrator should be able to: - - Manage organization members (invite, remove, view) + - Manage customer's members (invite, remove, view) - Manage applications (create, update, delete) - Manage application's credentials - Configure application's permissions - Regular members should be able to: - View members - View application details -- Each API should be provisioned access to specific components they can use. For example, the B2B SaaS application could have a Purchase and Payments components. If the customer only paid for the Purchase component, their applications should not be able to access the Payments one. +- Each application should be provisioned access to specific components they can use. For example, the B2B SaaS application could have a Purchase and Payments components. If the customer only paid for the Purchase component, their applications should not be able to access the Payments component. - - -See the model, tuples and tests in the [store.yaml](./store.fga.yaml) file. +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). ## Try It Out diff --git a/stores/developer-portal/store.fga.yaml b/stores/developer-portal/store.fga.yaml index 7f41212..8168754 100644 --- a/stores/developer-portal/store.fga.yaml +++ b/stores/developer-portal/store.fga.yaml @@ -101,7 +101,8 @@ tuples: object: component:payment tests: - - check: + - name: Test permissions for users and applications + check: - user: user:anne object: application:1 assertions: @@ -127,3 +128,23 @@ tests: assertions: can_view : true can_write : true + + - name: Test the applications anne can view + list_objects: + - user: user:anne + type: application + assertions: + can_view: + - application:1 + + - name: Test who can view application:1 + list_users: + - object: application:1 + user_filter: + - type: user + assertions: + can_view: + users: + - user:anne + - user:marie + diff --git a/stores/entitlements/store.fga.yaml b/stores/entitlements/store.fga.yaml index e7329f3..5d7718c 100644 --- a/stores/entitlements/store.fga.yaml +++ b/stores/entitlements/store.fga.yaml @@ -52,7 +52,7 @@ tuples: relation: subscriber object: plan:team tests: - - name: Test + - name: Test which users have access to different features check: - user: user:anne object: feature:issues @@ -90,3 +90,25 @@ tests: object: feature:sso assertions: can_access: true + + - name: Test who has access to the issues feature + list_users: + - object: feature:issues + user_filter: + - type: user + assertions: + can_access: + users: + - user:charles + - user:beth + - user:anne + + - name: Test which features can Charles access + list_objects: + - user: user:charles + type: feature + assertions: + can_access: + - feature:draft_prs + - feature:issues + - feature:sso \ No newline at end of file diff --git a/stores/expenses/store.fga.yaml b/stores/expenses/store.fga.yaml index 1318ce4..141e151 100644 --- a/stores/expenses/store.fga.yaml +++ b/stores/expenses/store.fga.yaml @@ -23,7 +23,7 @@ tuples: relation: submitter object: report:sam-chair1 tests: - - name: Test + - name: Test for managers and approvers check: - user: employee:matt object: employee:daniel @@ -36,4 +36,25 @@ tests: - user: employee:daniel object: report:daniel-chair1 assertions: - approver: false \ No newline at end of file + approver: false + + - name: Test which reports can Emily approve + list_objects: + - user: employee:emily + type: report + assertions: + approver: + - report:daniel-chair1 + - report:sam-chair1 + + - name: Test who can approve daniel-chair + list_users: + - object: report:daniel-chair1 + user_filter: + - type: employee + assertions: + approver: + users: + - employee:emily + - employee:sam + - employee:matt \ No newline at end of file diff --git a/stores/gdrive/store.fga.yaml b/stores/gdrive/store.fga.yaml index 175d32b..0bcc771 100644 --- a/stores/gdrive/store.fga.yaml +++ b/stores/gdrive/store.fga.yaml @@ -40,7 +40,7 @@ tuples: relation: viewer object: doc:public-roadmap tests: - - name: Test + - name: Test user permissions for doc:2021-roadmap check: - user: user:anne object: doc:2021-roadmap @@ -55,6 +55,28 @@ tests: assertions: can_read: true + + - name: Test which documents can Anne read + list_objects: + - user: user:anne + type: doc + assertions: + can_read: + - doc:2021-roadmap + - doc:public-roadmap + + - name: Test who can access doc:2021-roadmap + list_users: + - object: doc:2021-roadmap + user_filter: + - type: user + assertions: + can_read: + users: + - user:anne + - user:beth + - user:charles + - name: Check if the right users have access to the right documents list_users: - object: doc:public-roadmap @@ -90,4 +112,3 @@ tests: users: - user:anne - user:charles - diff --git a/stores/github/store.fga.yaml b/stores/github/store.fga.yaml index f30c048..b5d1acd 100644 --- a/stores/github/store.fga.yaml +++ b/stores/github/store.fga.yaml @@ -40,7 +40,7 @@ tuples: relation: member object: team:openfga/backend tests: - - name: Test + - name: Test individual user permissions on the openfga/openfga repo check: - user: user:anne object: repo:openfga/openfga @@ -64,6 +64,28 @@ tests: assertions: reader: true + - name: Test who are readers of the openfga/openfga repo + list_users: + - object: repo:openfga/openfga + user_filter: + - type: user + assertions: + reader: + users: + - user:diane + - user:charles + - user:beth + - user:anne + - user:erik + + - name: Test which repos can Diane read + list_objects: + - user: user:diane + type: repo + assertions: + reader: + - repo:openfga/openfga + - name: Check if the right users have access to the right repositories list_users: - object: repo:openfga/openfga @@ -86,4 +108,3 @@ tests: users: - team:openfga/backend#member - team:openfga/core#member - diff --git a/stores/github/tuples.yaml b/stores/github/tuples.yaml deleted file mode 100644 index e69de29..0000000 diff --git a/stores/groups-resource-attributes/README.md b/stores/groups-resource-attributes/README.md index e62760b..76c6d5d 100644 --- a/stores/groups-resource-attributes/README.md +++ b/stores/groups-resource-attributes/README.md @@ -1,11 +1,11 @@ # OpenFGA Groups Resource Attributes Sample Store -* **Title**: **Temporal Access** - ## Use-Case It enables members of specific groups to access content depending on resource attributes. For example, you can specify that members of the 'marketing' team can only view documents that are 'published' but members of the 'content' team can also view 'draft' documents. +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). + ## Try It Out 1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) diff --git a/stores/iot/store.fga.yaml b/stores/iot/store.fga.yaml index 46af6e5..c93ce54 100644 --- a/stores/iot/store.fga.yaml +++ b/stores/iot/store.fga.yaml @@ -44,7 +44,7 @@ tuples: relation: security_guard object: device_group:group1 tests: - - name: Test + - name: Test specific user permissions on each device check: - user: user:anne object: device:1 @@ -59,3 +59,24 @@ tests: object: device:2 assertions: can_rename_device: true + + - name: Test who can view live video on device:1 + list_users: + - object: device:1 + user_filter: + - type: user + assertions: + can_view_live_video: + users: + - user:diane + - user:charles + - user:anne + - user:beth + + - name: Test in which devices can Beth view live video + list_objects: + - type: device + user: user:beth + assertions: + can_view_live_video: + - device:1 \ No newline at end of file diff --git a/stores/ip-based-access/README.md b/stores/ip-based-access/README.md index e57ce67..d10d2f3 100644 --- a/stores/ip-based-access/README.md +++ b/stores/ip-based-access/README.md @@ -1,10 +1,10 @@ # OpenFGA IP-Based Access Sample Store -* **Title**: **IP-Based Access** - ## Use-Case -It enables granting access for users in a specific IP range.. +It enables granting access for users in a specific IP range. + +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). ## Try It Out diff --git a/stores/ip-based-access/store.fga.yaml b/stores/ip-based-access/store.fga.yaml index db2cad5..44a2a3d 100644 --- a/stores/ip-based-access/store.fga.yaml +++ b/stores/ip-based-access/store.fga.yaml @@ -7,12 +7,17 @@ model: | type organization relations define member : [user] + + # An IP range can be assigned to the members of every organization define ip_based_access_policy : [organization#member with in_company_network] type document relations define organization : [organization] define viewer: [user] + + # An user can view a document if they are assigned as a viewer, and the Organization's IP range + # matches the provided IP address define can_view: viewer and ip_based_access_policy from organization condition in_company_network(user_ip: ipaddress, cidr: string) { diff --git a/stores/modular/README.md b/stores/modular/README.md index 94efe3b..b361685 100644 --- a/stores/modular/README.md +++ b/stores/modular/README.md @@ -1,10 +1,58 @@ # OpenFGA Modular Model Sample Store -* **Title**: **Modular Model** - ## Use-Case -This example showcases how to use modular models to separate your model across multiple files and how to use type extensions within those modules. +This example showcases how to use [modular models](https://openfga.dev/modeling/modular-models) to organize your model across multiple files. + +It models an application with three modules: + +- A `core` [module](./core.fga) defines the entity types that are shared across components. +- A `wiki` [module](./wiki.fga) defines the entity types for the wiki component (e.g. spaces and pages). +- A `issue tracker` module defines the entity types for the issue tracking component. This module is defined in 2 separate files, one for [projects](./issue-tracker/projects.fga) and another for [tickets](./issue-tracker/tickets.fga) + +An `fga.mod` [manifest file](./fga.mod) declares all the modules for the model. The model can be written to an OpenFGA store with the `fga model write --file fga.mod --store-id ` CLI command. + +If you then try to get the model with the `fga model get --format fga --store-id ` command, OpenFGA will be displayed it as a single combined model, with annotations describing the module that defined each type: + +```dsl +model + schema 1.2 + +type group # module: core, file: core.fga + relations + define member: [user] + +type organization # module: core, file: core.fga + relations + define admin: [user] + define member: [user] or admin + define can_create_project: admin # extended by: module: issue-tracker, file: issue-tracker/projects.fga + define can_create_space: admin # extended by: module: wiki, file: wiki.fga + +type user # module: core, file: core.fga + +type project # module: issue-tracker, file: issue-tracker/projects.fga + relations + define organization: [organization] + define viewer: member from organization + +type ticket # module: issue-tracker, file: issue-tracker/tickets.fga + relations + define owner: [user] + define project: [project] + +type page # module: wiki, file: wiki.fga + relations + define owner: [user] + define space: [space] + +type space # module: wiki, file: wiki.fga + relations + define can_view_pages: member from organization + define organization: [organization] +``` + +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). ## Try It Out diff --git a/stores/modular/wiki.fga b/stores/modular/wiki.fga index 5548842..0af2490 100644 --- a/stores/modular/wiki.fga +++ b/stores/modular/wiki.fga @@ -4,7 +4,6 @@ extend type organization relations define can_create_space: admin - type space relations define organization: [organization] diff --git a/stores/slack/store.fga.yaml b/stores/slack/store.fga.yaml index eff8d43..36ee076 100644 --- a/stores/slack/store.fga.yaml +++ b/stores/slack/store.fga.yaml @@ -82,3 +82,26 @@ tests: object: channel:general assertions: writer: false + + + - name: Test which channels can David write to + list_objects: + - user: user:david + type: channel + assertions: + writer: + - channel:proj_marketing_campaign + + - name: Test who can write to the proj_marketing_campaign channel + list_users: + - object: channel:proj_marketing_campaign + user_filter: + - type: user + assertions: + writer: + users: + - user:bob + - user:amy + - user:david + - user:emily + - user:catherine \ No newline at end of file diff --git a/stores/superadmin/README.md b/stores/superadmin/README.md index ef73a1b..113f57f 100644 --- a/stores/superadmin/README.md +++ b/stores/superadmin/README.md @@ -2,7 +2,7 @@ ## Use-Case -In B2B SaaS applications, each customer usually has one or more admin users that have full permission over the account. +In B2B SaaS applications, each customer usually has one or more admin users that have full permission over the account. It's also common that employees of the SaaS company can perform specific actions across different accounts, for configuration or help desk purposes. @@ -17,10 +17,10 @@ The application will have two kinds of resources: - **Project** - **Tasks** -See the model, tuples and tests in the [store.yaml](./store.fga.yaml) file. +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). ## Try It Out 1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) -2. In the `slack` directory, run `fga model test --tests store.yaml` +2. In the `superadmin` directory, run `fga model test --tests store.yaml` diff --git a/stores/superadmin/store.fga.yaml b/stores/superadmin/store.fga.yaml index 43daefa..edfa21e 100644 --- a/stores/superadmin/store.fga.yaml +++ b/stores/superadmin/store.fga.yaml @@ -14,12 +14,12 @@ model: | # top level type where we define system administrators, note that we are only defining # superadmins but there could be other roles that would have restricted permissions type system - relations + relations define admin : [employee, application] # organization represent the SaaS customer type organization - relations + relations define system : [system] # system admins have the same permissions in the organization as @@ -35,7 +35,7 @@ model: | define can_create_project : admin or member type project - relations + relations define organization : [organization] define owner : [user] @@ -44,7 +44,7 @@ model: | define viewer : [user] or editor or helpdesk_member from organization type task - relations + relations define project: [project] define owner : [user] @@ -96,38 +96,79 @@ tuples: object: task:create-example tests: - - check: - # anne is a super admin, has full access - - user: employee:anne - object: task:create-example - assertions: - viewer: true - editor: true - - # peter is an admin in the organization, has full access - - user: user:peter - object: task:create-example - assertions: - viewer: true - editor: true - - # the system application has full access - - user: application:system-management-app - object: task:create-example - assertions: - viewer: true - editor: true - - # john only has temporary access as viewer - - user: employee:john - object: task:create-example - context: - current_time: "2024-01-01T00:10:00Z" - assertions: - viewer: true - editor: false + - name: Test specific permissions for different users + check: + # anne is a super admin, has full access + - user: employee:anne + object: task:create-example + assertions: + viewer: true + editor: true + + # peter is an admin in the organization, has full access + - user: user:peter + object: task:create-example + assertions: + viewer: true + editor: true + + # the system application has full access + - user: application:system-management-app + object: task:create-example + assertions: + viewer: true + editor: true + # john only has temporary access as viewer + - user: employee:john + object: task:create-example + context: + current_time: "2024-01-01T00:10:00Z" + assertions: + viewer: true + editor: false + - name: Test the tasks that each user can view + list_objects: + - user: employee:john + type: task + context: + current_time: "2024-01-01T00:10:00Z" + assertions: + viewer: + - task:create-example + + - user: user:peter + type: task + assertions: + viewer: + - task:create-example - - \ No newline at end of file + - user: employee:anne + type: task + assertions: + viewer: + - task:create-example + + - name: Test the users/employees can can view task:create-example + list_users: + - object: task:create-example + context: + current_time: "2024-01-01T00:10:00Z" + user_filter: + - type: user + assertions: + viewer: + users: + - user:peter + + - object: task:create-example + context: + current_time: "2024-01-01T00:10:00Z" + user_filter: + - type: employee + assertions: + viewer: + users: + - employee:anne + - employee:john \ No newline at end of file diff --git a/stores/temporal-access/README.md b/stores/temporal-access/README.md index 506ba3f..15e25af 100644 --- a/stores/temporal-access/README.md +++ b/stores/temporal-access/README.md @@ -1,10 +1,12 @@ # OpenFGA Temporal Access Sample Store -* **Title**: **Temporal Access** - ## Use-Case -It enables granting access for a limited time. +An application needs to grant access to users to a document during a specific period of time. + +We can model it with OpenFGA using [conditional relationship tuples](https://openfga.dev/docs/modeling/conditions). + +The model, tuples and unit tests are detailed in [store.fga.yaml](./store.fga.yaml). ## Try It Out diff --git a/stores/temporal-access/store.fga.yaml b/stores/temporal-access/store.fga.yaml index 88fdf86..6a39bb0 100644 --- a/stores/temporal-access/store.fga.yaml +++ b/stores/temporal-access/store.fga.yaml @@ -63,7 +63,7 @@ tests: object: document:1 assertions: viewer: true - + - name: Test the documents that anne can view list_objects: - user: user:anne type: document @@ -72,4 +72,29 @@ tests: assertions: viewer: - document:1 - - document:2 \ No newline at end of file + - document:2 + + - name: Test the users that can view document:1 + list_users: + - object: document:1 + context: + current_time: "2023-01-01T00:00:01Z" + user_filter: + - type: user + assertions: + viewer: + users: + - user:anne + - user:bob + + - name: Test the users that can view document:2 + list_users: + - object: document:2 + context: + current_time: "2023-01-01T00:00:01Z" + user_filter: + - type: user + assertions: + viewer: + users: + - user:anne