LarsRan
01/09/2023, 12:44 PMdefinition document {
relation aaa: group#member
relation bbb: group#member
permission ccc = aaa & bbb
}
definition group {
relation member: user
}
definition user {}
Here users get their permission by the group that they are in. For permission ccc
then need permissions aaa
and bbb
.
In this example if a user is part of group1
which has aaa
on document1
and is also part of group2
which has bbb
on document1
then this user has permission ccc
on document1
.
However, lets say we want permissions to only come from a single group so that a user only has permission ccc
if they are in a group that has both aaa
and bbb
. How do I do this? My naive incorrect approach was this
definition document {
relation aaa: group
relation bbb: group
permission ccc = (aaa & bbb)#member
}
definition group {
relation member: user
}
definition user {}
but that is (unsurprisingly) syntactically incorrect. What would be a good way to model this, perhaps using auxiliary definitions/relations/permissions? (Note: this is of course simplified from our actual usecase so just merging aaa
and bbb
does not work for us)vroldanbet
01/10/2023, 9:20 AMdefinition document {
relation assignment: group_assignment#ccc
permission ccc = assignment # this is supported
permission ccc_user = assignment->member # this is not supported
}
definition group_assignment {
relation aaa: group
relation bbb: group
permission ccc = aaa & bbb
}
definition group {
relation member: user
}
definition user {}
I think you could solve this by turning it into 2 Permission Checks:
- One checks the user
is member of a group
with the permission
- Another one checks a permission that makes sure the group
has both aaa
and bbb
You'd run these 2 checks in parallelLarsRan
01/10/2023, 12:05 PMvroldanbet
01/10/2023, 12:26 PMaaa
and another with bbb
, you wouldn't want to allow ccc
in that case?LarsRan
01/12/2023, 9:48 AMand
operator and diamond shapes.
In our case this comes from the fact that groups have rights, so edit_document
for example, and a hierarchical realm in which this holds, say one or more organisation
. So the right is global over all organisation
. However now, when belonging to two groups, the realms and rights can be mixed and matched, leading to extra permissions that are not from either group but rather from the combination. (see zedfile below)
The solution that we now chose is by linearizing our permission graph and eliminate diamonds by defining rights for groups directly on organisation
. The inelegant thing here is that edit_document
has to be given to all organisation
in a groups realm even though this is domainwise just a single boolean. What is even more is that we want the collection of these booleans in a role
definition so it is reusable, but this is not possible in this case either.
definition global_rights {
document_editor: group#member
}
definition organisation {
relation realm_holder: group#member
}
definition document {
relation organisation: organisation
relation global_rights: global_rights
permission edit = global_rights->document_editor && organisation->realm_holder
}
definition group {
relation member: user
}
definition user {}
vroldanbet
01/12/2023, 11:43 AM->
. Unless I'm mistaken, the intersection of the permissions of the groups should be the same as the intersection of the permissions of the users. What the "intersection arrow" gives us is that the user must be present in all relationships of the relation, not just one. What this gives us is that if the subject is member of multiple groups, the user should have permission in every group, else it does not have permission. Effectively this gives you the intersection of the permissions granted over each group.
This is how I think it can be implemented. I took the liberty to change things a bit:
- rights are not global, but granted to groups. We use the "wildcard operator" as an ON/OFF switch
- we use the intersection arrow over the realm_holder (not supported right now in SpiceDB)
definition rights {
document_editor: user:*
document_creator: user:*
}
definition organisation {
relation realm_holder: group#member
}
definition document {
relation realm_holders: organisation#realm_holder
permission edit = realm_holders-&>document_editor
permission create = realm_holders-&>document_creator
}
definition group {
relation member: user
relation rights: rights
permission edit_document = rights->document_editor & member
permission create_document = rights->document_creator & member
}