Conditional Roles
The conditional roles pattern enables several advanced access control schemes, including default roles and toggles.
Default Roles
GitCloud is a multitenant service where countless software engineers at countless organizations collaborate on code. Organization members are automatically granted a role on all repositories in the organization. However, since organizations have different access control models, we've allowed them to choose the repository role that organization members inherit. Some organizations with tighter controls only grant the "viewer" role on their repositories, whereas organizations at the opposite end of the spectrum give all members the "admin" role on all repositories.
Without the conditional roles pattern, we might end up syncing a fact like
has_role(User{"Alice"}, <default role>, Repository{"Anvils"})
to Oso Cloud
for every single combination of user and repository across every single
organization. That's a lot of data!
Instead of syncing all that data, organizations can send a single fact like
has_default_role(Organization{"acme"}, "editor")
to set a default role for
their members to inherit on all of their repositories.
Writing rules over resource attributes (in this case, the default role configured for each organization) is a great way to reduce the data management burden in a complex authorization system.
Implement the logic
We add a custom has_role
rule that grants the organization-configured default
role on repositories to all members of the repository's organization.
Test it out
The ACME organization decided "editor" should be the default role on their repositories. So ACME members like Alice can write to all ACME repositories.
Toggles
We can also conditionally inherit roles by specifying attributes on the resource itself instead of on a related resource, as in the Default Roles example.
A common example of this is a toggle on the resource. For example, a setting that specifies if the resource is "protected" and restricts access accordingly.
Implement the logic
Instead of inheriting all roles unconditionally (role if role on "organization"
) or even a default role on all repositories like the previous
example, now we'll only allow users to inherit roles on repositories that
aren't marked as "protected".
Test it out
There are four interesting cases to try out:
- As an organization member, Alice can read unprotected repositories.
- As an organization member, Alice can not read protected repositories.
- As an organization member, Alice can read a protected repository if she's explicitly invited to it.
- As an organization admin, Alice can read and delete all repositories regardless of protected status.
Extension: Combination
The two pieces of logic we just wrote combine together perfectly:
This now says that organization members inherit the organization's default repository role on all non-protected repositories. Powerful stuff!