Forum Academy Marketplace Showcase Pricing Features

RBAC access control

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:

  • User table
  • Group table has List of Users
  • Organization table has List of Repos, List of Users, List of Groups
  • Repo table has List of Grants (& also relationships with most resources)
  • Grants table contains 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_write, 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
Where

  • Search for Grants 1: constraints on repo = Current Page Repo and user = Current User
  • Arbitrary text 1: VIEW Repos
  • Search for Grants 2: constraints on repo = Current Page Repo and group is in Search for Groups
    • Search of Groups: constraints on users contains Current User and organization = Current Page Repo's organization
  • Arbitrary text 2: VIEW Repos

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?

Thanks, Roman


P.S.
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.