Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ABAC with ReBAC example #38

Merged
merged 2 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions stores/abac-with-rebac/README.md
Original file line number Diff line number Diff line change
@@ -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 for each possible value, where the resource is related to 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`


101 changes: 101 additions & 0 deletions stores/abac-with-rebac/store.fga.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
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