Hey, another “please help with access control” post…
TLDR; Please help me implement an access control pattern similar to what you would find in GitHub.
What I need
I need to implement access control that is very similar to GitHub, so I will use that as an example to explain:
- After I sign up, I can create an Organization, which will add me as a User to that Org. The Org has no other Users, Groups or Repos by default.
- I may also have been invited, in which case I get added to Org, Repo and Group as applicable.
- An Organization object owns Users, Groups and Repos (and other resources we want to access)
- By default, a User cannot see any of the Orgs Repos, but have permission to create a new Repo.
- The creator of the Repo is granted ‘admin’ Role and can add Users and Groups to a Repo, and grant that User (or Group) a Role.
- A Role has a name like ‘read’, ‘write’ and ‘admin’, where each builds upon the other. Roles are owned by the app, not the Org or Repo.
- A Role has multiple Permissions assigned. A Permission is something like “Allow open PR”, and can be assigned to multiple Roles in order to build hierarchy (and possibly feature flags)
- I may have multiple Roles assigned to me for different Repos. (eg have ‘read’ granted to me as User in Repo X, and ‘admin’ granted to me via a User in a Group in Repo Y)
- All resources within a Repo determine if a User may view/update/delete it depending on the Role (and possibly Permissions attached to Role) granted to the current User (or Group containing User)
In summary, I may have multiple Organizations, which may have multiple Repos, for whose resources I want to grant access to Users and Groups via reusable Roles.
What I’ve tried
I figured the best way to do this is to have the following tables:
List of Users
List of Repos,
List of Users,
List of Groups
List of Grants(& also relationships with most resources)
User, Group, Repo, Role
Then, if I wanted to know if a User may access a resource, I should be able to query the Grants table, filter by my current Repo and User (or Group containing User) and find all applicable Roles to formulate the complete list of applicable Permissions. If one of those Permissions is for my resource, then I allow.
1) Privacy Rules
From your documentation: “…Without Privacy Rules… an outsider can access all the data in your app, even if you don’t design a page that shows that data.”
So obviously the way I want to do this, but the privacy rules seem to be exceedingly simplistic.
For example, to decide if a User may view a particular Repo, I would want to do something like this (forgive the mess of pseudocode please)
search for Grants WHERE Grant.repo = CurrentRepo AND (Grant.user = CurrentUser OR Grant.group contains CurrentUser) :each item's permission.policy == "view repo" :count > 0
But the privacy rules are limited to something not more complex than
This Repo's grants contains This Repo… Which is obviously not getting us anywhere.
That means the only option would be to add a fields like
users_allow_view: List of Users,
users_allow_admin to absolutely every resource, which seems difficult to build and maintain. This means Groups become a fiction and assigning a Role requires adding/updating a User to all the lists of all the resources. This becomes really gross.
2) Conditions on elements
This looks possible, but really isn’t what I would consider elegant. Also, as your own documentation pointed out, making an element invisible does not make it inaccessible
Using a condition (to make invisible or do a conditional Data Source query) I have got something like this:
Search for Grants: each item's role's permissions's policy : contains Arbitrary text OR Search for Grants: each item's role's permissions's policy : contains Arbitrary text
Search for Grants 1: constraints on
repo = Current Page Repoand
user = Current User
Arbitrary text 1:
Search for Grants 2: constraints on
repo = Current Page Repoand
group is in Search for Groups
Search of Groups: constraints on
users contains Current Userand
organization = Current Page Repo's organization
Arbitrary text 2:
I haven’t tried using styles, but I suspect it would look the same
What I want
My attempt at using Privacy policies looks simpler, but doesn’t work, and the conditional queries seem to work, but aren’t simple.
Please tell me if there is a better way to do this? And if option 2 is the only way to do this, please check if I’ve overcomplicated my life?
I would consider Conditions and Styles to be workarounds to do data access, not a secure solution. If this is the case, please create a feature request to expand the Privacy functionality, else it may force me to build with other tools (which would make me sad)
And my god, I hope this helps someone else.