diff --git a/stores/abac-with-rebac/README.md b/stores/abac-with-rebac/README.md new file mode 100644 index 0000000..923ef28 --- /dev/null +++ b/stores/abac-with-rebac/README.md @@ -0,0 +1,66 @@ +# OpenFGA Modeling Attribute-Based Access Control with Relationship Based Access Control + +## Use-Case + +This example demonstrates how to model Attribute-Based access control scenarios purely with Relationship Based Access Control constructs. + +In ABAC, you make authorization decisions based on different attributes of the user, the resource, and the environment. Depending on the kind of attribute, you can model them pretty easily in ReBAC or not. + +If the attribute is a **reference to another entity**, e.g. the equivalent of a foreign key in a relational database, then you can model it as a relation. For example, the user's department can be modeled as: + +``` +type user + +type department + relations + define member : [user] + +type folder + relations + define department : [department] + define viewer : member from department +``` + +If the attribute is a **category with a few values**, e.g. a boolean, a category like `status', then you can model it by defining a relationship with the resource where the attribute is defined with itself. + +For example, the following model defines a policy where the user can only view a document if their email is verified, you'll add an email_verified relation to the user type: + +```` +type user + relations + define email_verified : [user] + +type document + relations + define viewer : [user] + define can_view : email_verified from viewer +``` + +If you want to model a document status, you'll add a relation for each possible status with the document itself: + +```` +type user + +type document + relations + define published : [document] + define draft : [document] + + define viewer : [user] + + define can_view : viewer from published +``` + +If the attribute is a discrete variable with many possible values, e.g. birth date, age, IP address, a a currency amount, then it's not possible to be modeled with pure ReBAC and you need to resort to using [OpenFGA conditions](https://openfga.dev/docs/modeling/conditions). + +If you can model your attribute as a relation, you should do so, as it will make your model simpler and more efficient. + +The example in [store.fga.yaml](./store.fga.yaml) showcases the two examples above. + +## Try It Out + +1. Make sure you have the [FGA CLI](https://github.com/openfga/cli/?tab=readme-ov-file#installation) + +2. In the `abac-with-rebac` directory, run `fga model test --tests store.yaml` + + diff --git a/stores/abac-with-rebac/store.fga.yaml b/stores/abac-with-rebac/store.fga.yaml new file mode 100644 index 0000000..9947c10 --- /dev/null +++ b/stores/abac-with-rebac/store.fga.yaml @@ -0,0 +1,100 @@ +model: | + model + schema 1.1 + + type user + relations + define email_verified : [user] + + type document + relations + define draft : [document] + define published : [document] + + define viewer : [user] + define viewer_email_verified : email_verified from viewer + + define owner : [user] + define owner_email_verified : email_verified from owner + + define can_view : owner_email_verified or viewer_email_verified from published + define can_edit : owner_email_verified from draft + +tuples: + + # Whenever bob/anne verify their email, these two tuples should be created + - user: user:bob + relation: email_verified + object: user:bob + + - user: user:anne + relation: email_verified + object: user:anne + + - user: user:bob + relation: owner + object: document:readme + + - user: user:anne + relation: viewer + object: document:readme + + - user: user:jeremy + relation: viewer + object: document:readme + +tests: + - name: Test permissions for draft document + tuples: + # This tuple can be written to OpenFGA when the document status changes + # or can be sent as a contextual tuple + - user: document:readme + relation: draft + object: document:readme + check: + # Only the owner can view and edit a draft document + - user: user:anne + object: document:readme + assertions: + can_edit : false + can_view : false + + - user: user:bob + object: document:readme + assertions: + can_edit : true + can_view : true + + # jeremy does not have a verified email so it's not allowed to edit or view regardless of status + - user: user:jeremy + object: document:readme + assertions: + can_edit : false + can_view : false + + - name: Test permissions for published document + tuples: + # This tuple can be written to OpenFGA when the document status changes + # or can be sent as a contextual tuple + - user: document:readme + relation: published + object: document:readme + check: + # Everyone can view a published document, but nobody can edit it + - user: user:anne + object: document:readme + assertions: + can_edit : false + can_view : true + - user: user:bob + object: document:readme + assertions: + can_edit : false + can_view : true + + # jeremy does not have a verified email so it's not allowed to edit or view regardless of status + - user: user:jeremy + object: document:readme + assertions: + can_edit : false + can_view : false \ No newline at end of file