Attribute Based Access Control (ABAC)

Attributes are a way to further describe your application. Every part of your application has characteristics that can be thought of as an attribute. You can use this to control your authorization logic in a very granular way. For example, a user in your app might have a status of active or inactive. Or, a resource might be public or private. A few more examples are given in the table below.

ObjectExample Attributes
Users• Employment Status: full-time, part-time, contractor, ...
• Reward Status: platinum, gold, silver, ...
• User Level: superadmin, user, guest
Resources• Privacy Status: private, public
• Region: Africa, Americas, Asia, Europe, Oceania
• Confidentiality Status: top secret, secret, restricted,..., public

Attributes also have a few characteristics of their own! They might be binary (this or that, true or false, ect.), or they may come from a collection of terms. These factor contribute to how you use them in your authorization.

Toggle Attributes

When modeling attributes that have only one or two states that you care about, you can use the rule name to describe the state that a user or resource currently has. The resulting rule statements usually take the form is_<ATTRIBUTE_STATE>.

Example Use CaseAttributeAttribute StateRule Statement
All users have the read permission on public repos.Privacy StatuspublicUse this attribute to label a resource as public: is_public(repo).
Superadmins can edit resources across organizations.User LevelsuperadminUse this attribute to label a user as a superadmin: is_superadmin(user).
Only rewards members users have access to certain resources.Membership Typerewards_memberUse this attribute to label a user as a rewards member: is_rewards_member(user).

Get Started with Toggle Attributes

Action Items

Prerequisites

We'll use a concrete Github example and add two attributes:

  1. An attribute that marks a repo as public.
  2. An attribute that describes a user as the owner of a repo.

Step 1: Use the attribute rule statement to modify existing rule behavior

If the rule doesn't exist in longhand, write a new rule with the attribute rule statement. Make sure the new rule doesn't conflict with any shorthand rules defined in resource blocks.

In this example we'll be extending the logic for read if collaborator. By extending the rule, rather than replacing it, we allow existing has_role(actor, "collaborator, repo) facts to still be valid. The new has_permission rule appears in the right column code block below.

NOTE: What's not obvious in this example is that we are modifying a has_permission rule. You may recall that the shorthand statement read if collaborator;, expands to:


has_permission(actor: Actor, "read", repo: Repository) if
has_role(actor, "collaborator", repo);


Simple Resource Specific Pattern


actor User {}
# Top level resource.
resource Organization {
...
}
# Repository resource block.
resource Repository {
permissions = [
"read",
"write",
"delete"
];
roles = [
"owner",
"collaborator"
];
# Rules assigning permissions to roles.
"read" if "collaborator";
"write" if "collaborator";
"collaborator" if "owner";
"delete" if "owner";
}
====>

Resource Specific Pattern with Attributes


actor User {}
# Top level resource.
resource Organization {
...
}
# Repository resource block.
resource Repository {
permissions = [
"read",
"write",
"delete"
];
roles = [
"admin",
"collaborator"
];
# Rules assigning permissions to roles.
"read" if "collaborator";
"write" if "collaborator";
"collaborator" if "admin";
"delete" if "admin";
}
# ATTRIBUTE PATTERN (Step 1):
# - Use the attribute rule statement to modify
# existing rule behavior.
has_permission(_: Actor, "read", repo: Repository) if
is_public(repo);

Using this same pattern we can also assign default roles to users with certain attributes. For example, the owner of a repo should have admin permissions.


has_role(user: User, "admin", repo: Repository) if
is_owner(user, repo);

NOTE: The ownership of a resource is dependent on two pieces of information: the specific resource in question, and the user labeled as the owner. The attribute rule statement must also contain this information to work as intended.

Next Steps

Defining Attributes with Additional State

Get Started with Defining Attributes with Additional State

Action Items

In the get started example above, we introduced a simple way to add attributes to rules. However, this approach does not work when the attribute has many possible states that you need to represent. In this case, you'll use an additional argument to the attribute to represent this additional state:

has_<ATTRIBUTE>(Type, <ATTRIBUTE_STATE>)

Using Multiple Attribute States

In Github, public and private are labels repositories can have. For this last pattern we'll present, suppose there is a third label: open_collaboration. Anyone can collaborate on a repo with this label.

First, change the attribute rule statement from is_public to has_label in the has_permission rule:


has_permission(_: Actor, "read", repo: Repository) if
has_label(repo, "public");

Next, create a new default collaborator role when a repo has the open_collaboration label. Reuse the has_label rule statement and change the attribute state.


has_role(_: Actor, "collaborator", repo: Repository) if
has_label(repo, "open_collaboration");

Next Steps


Additional Resources

Talk to an Oso Engineer

If you'd like to learn more about using Oso Cloud in your app or have any questions about this guide, connect with us on Slack. We're happy to help.

Get started with Oso Cloud →