permify icon indicating copy to clipboard operation
permify copied to clipboard

Wildcard support for relationships

Open tolgaOzen opened this issue 2 years ago • 5 comments

Based on this schema:

entity user {}

entity course {
    relation owner @user
    relation member @user
    action read = owner or member
    action write = owner
}

entity program {
    relation owner @user
    relation member @user
    action read = owner or member
    action write = owner
}

We can have: For alice user:

  1. course:1#owner@user:alice
  2. course:2#member@user:alice

For alex user:

  1. program:1#owner@user:alex
  2. program:2#member@user:alex

Question: How can I have a admin user who will be able to manage all resources? This would be an application and not resource level permission. I only want to set/check if the user has a role (admin), without having to add a permission to each resource type as below: course:#owner@user:admin and program:#owner@user:admin

tolgaOzen avatar Feb 07 '23 01:02 tolgaOzen

Looking forward to this one. It will also work towards your method for supporting RBAC. For example, if a user has a relation to a group, and a group has a relation towards another resource without specifying an ID or using a "*" wildcard type character in the relationship definition it will allow for more coarse grained or broad sweeping permissions which is what groups are intended for. In our case we have a schedule entity that group:admins are allowed to edit no matter the ID.

brandensilva avatar Feb 10 '23 16:02 brandensilva

Hi @brandensilva, we added this feature to our roadmap, I'll let you know you when its released.

EgeAytin avatar Feb 10 '23 21:02 EgeAytin

Just an updated example for you on this one of what we have settled on:

Rather than "Group" we have "Departments"

The scheduling department can control any schedule. So rather than writing the following multiple times:

schedule:1#dept@department:scheduling schedule:2#dept@department:scheduling schedule:3#dept@department:scheduling ...

we could instead just write:

schedule:*#dept@department:scheduling to denote a wildcard character for explicitness or schedule#dept@department:scheduling for implicitness.

I could see how this latter example could be confusing so it might have to be explained or documented somewhere but it is less to write.

This would cover most RBAC needs since you are saying a group/department/entity has full control over another entity no matter the id. Given you will want some push to create a wildcard relationship to establish it initially in writeDb, it seems like a wildcard character makes a lot of sense. Then it's just a matter of checking with department or group someone is a part of as the sole check permissions that returns authorization as true.

Our goal is to get more fined grained over time as more authorization is needed, but this is a good starting point for many to get something going for RBAC and then they can incrementally adopt better patterns around ReBAC and ABAC.

In our case we will likely treat departments as RBAC, but then have more fine grained ABAC specific to departments, and have ReBAC based on the company org chart so its a bit of a hybrid approach.

brandensilva avatar Feb 28 '23 17:02 brandensilva

I've been thinking about this some more in how we can workaround this until such a coarse-grained RBAC solution exists such that we only have to write one relation so departments/groups can have access to all schedules.

The way forward I think is that the schedule identifier stays consistent whenever we do the authorization check for everything schedule related such that it acts like a group for a given entity.

Here is such an example:

entity department {
    relation member @user
}
entity schedule {
    relation dept @department

    action read = dept.member
    action write = dept.member
}

write relations: department:scheduling#member@user:john schedule:all#dept@department:scheduling

checks: - "can user:john read schedule:all": true - "can user:john write schedule:all": true

all in this case is a unique identifier that can be used several times when checking for access since a group/department can access any schedule.

This allows us to avoid writing multiple relations for each schedule created with a specific id. The downside is this negates unique identifiers for each individual schedule model created in a given database so perhaps less secure but does get you group/role-like functionality over a schedule entity once it is assigned once.

Does this seem like a reasonable workaround @EgeAytin to handle role-based needs over an entity/resource?

brandensilva avatar Mar 14 '23 23:03 brandensilva

@brandensilva While above works, the caller has to do 2 checks - one for entity id all and one for specific entity. Defining a recursive wildcard seems better to me as a workaround.

entity department {
    relation member @user
}
entity schedule {
    relation wildcard @schedule
    relation dept @department

    action read = wildcard.read or dept.member
    action write = wildcard.write or dept.member
}

Relations

department:scheduling#member@user:john
schedule:all#dept#department:scheduling

Check

entity: schedule:1 
subject: user:john
read: true
context: schedule:1#wildcard@schedule:all // this has to be added on all checks but its fixed, no logic involved.

So as long as the wildcard definition (<entity_type>:<id>#wildcard@<entity_type>:all) is added on every check it works. Subject and Entity can be ideal.

MohitKS5 avatar Jun 14 '24 02:06 MohitKS5