I have another design question; consider the follo...
# spicedb
l
I have another design question; consider the following schema
Copy code
definition 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
Copy code
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)
v
Hey 👋🏻 sorry we didn't follow up earlier. We did the modelling exercise yesterday and currently there is no way to model unless we engineer "synthetic arrow" (which the zanzibar paper does not mention either). Synthetic arrow would allow us to have a permission in the left-hand side of an arrow, so you'd be able to model this:
Copy code
definition 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 parallel
l
Thanks for taking the time to respond! That arrow is indeed one of the things I tried as well. The 2 permissions check is a neat idea. I will look into this. We might have come up with another solution as well but that turns our usecase entirely on its head. I will see where it goes, thanks!
v
I'd be curious to understand more about your use-case. When something is not modelable with Zanzibar's paradigm there may be a way around it by exploring alternative ways to reason about the business domain. Sometimes folks come with a preconceived way on how thing should be solved, and get stuck. That may mean reevaluating the use-case themselves, or reconsidering whether a specific restriction must be handled by the authorization service or by the client application. Of course not saying your use-case is not legitimate, it certainly seems reasonable! but that sometimes it helps to take a step back and reevaluate.
In your second scenario it would seem like permissions coming from different groups are no longer relevant right? So if a user is member of a group with
aaa
and another with
bbb
, you wouldn't want to allow
ccc
in that case?
l
Yes exactly. The point is that we want any permission over an object to come from a single group only. So a user being in two groups should not have more permissions than two separate users each in one group have combined. So that means we basically want to do our set algebra on groups instead of users. However this is not possible as any algebra is only allowed on the subject type. The problem comes mainly from the
and
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.
Copy code
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 {}
v
got it. I think you got the gist of SpiceDB's set algebra semantics very well 😄 Now that I have a better understanding, I think this could be supported with SpiceDB, except we need to implement an operator that we don't have right now (we have an open issue for that): the intersection arrow. Essentially it gives you the set intersection algebra but when walking the graph with
->
. 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)
Copy code
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
}
This is the issue proposal for intersection arrow https://github.com/authzed/spicedb/issues/597