Guides
/
Authorization Building Blocks

Authorization Modeling

This guide introduces a few Building Blocks, which are commonly-seen elements of authorization models, and then presents a few real-world Patterns that combine these Building Blocks in ways applications can use.

Building Blocks

Authorization models often consist of a few independent concepts that can be combined in an Oso policy. Each such concept is called a Building Block.

Roles

Roles are one of the most useful building blocks for talking about authorization. A role represents a named set of permissions given to a specific actor on a specific resource. A single role can extend permissions to multiple actors over multiple resources through the use of Actor and Resource Hierarchies. Roles are a very general building block that can be used to represent any kind of relationship between an actor and a resource, so practically any use case can be modeled using roles.

Resource Hierarchies

It’s common to organize resources into hierarchies, where access flows from resources to their subresources. Three common patterns using this building block are Ownership/Sharing, Org Roles, and Files / Folders. In all of these cases, a resources are grouped beneath other resources. Only the names have been changed.

Actor Hierarchies

It’s often useful to arrange actors into hierarchies. Two common patterns using this building block are Groups and Organizational Charts. In the first case, permissions belonging to a Group are shared by the Group’s members. In the second case, permissions belonging to workers are shared by their managers.

Attributes

Attributes describe information about actors and resources. An attribute on a particular actor or resource provides information about that actor or resource. Information from attributes on a specific actor and on a specific resource can then be used to determine whether to give the actor a specific permission on that resource.

Patterns

Authorization models in real-world applications usually combine a number Building Blocks, and there are some common Patterns of how the Building Blocks go together in applications.

Org Charts

Organizational charts are a common kind of Actor Hierarchy that capture the authority structure of an organization. In this example, managers automatically inherit all the permissions of their subordinates.

Oso Policy

# A manager has permission to do anything their workers can.
has_permission(manager: Actor, action: String, resource: Resource) if
  has_relation(manager, "manager", worker) and
  has_permission(worker, action, resource);

CLI Example

# This shows that granting a permission to Bob grants Eve permission,
# since Eve is Bob's manager's manager.
oso-cloud tell has_relation User:bob "manager" User:alice
oso-cloud tell has_relation User:alice "manager" User:eve
oso-cloud tell has_role User:bob "reader" Repo:service
oso-cloud authorize User:eve "read" Repo:service

Files/Folders

Collecting files or documents into folders is a common use case for Resource Hierarchies. In this example, anyone having a permission on a container object automatically has that permission on the object’s contents.

Oso Policy

# If you can act on the container, you can act on the contents
has_permission(actor: Actor, action: String, inner: Resource) if
  has_relation(outer, "container", inner) and
  has_permission(actor, action, outer);

CLI Example

oso-cloud tell has_relation User:bob container Org:oso
oso-cloud tell has_role User:alice reader Org:oso
oso-cloud authorize User:alice read User:bob

Ownership/Sharing

Many applications require a concept of resource ownership. Ownership is a basic example of a Resource Hierarchy, where resources have a specific, globally unique relation to their owners.

This example defines roles and permissions on a shareable resource type: the owner of an Issue can share it with others by assigning the role "reader" on the issue. The ability to assign the role is reflected in the "add_reader_role" permission on the Issue resource.

Oso Policy

# A shareable resource
resource Issue {
  roles = ["reader", "writer", "owner"];
  permissions = ["read", "write", "add_reader_role"];
  "reader" if "writer";
  "writer" if "owner";
  "read" if "reader";
  "write" if "writer";
  "add_reader_role" if "owner";
}

CLI Example

# Bob is the owner of Issue:bug so Bob can give Alice the reader role on Issue:bug
oso-cloud tell has_role User:bob "owner" Issue:bug
oso-cloud authorize User:bob "add_reader_role" Issue:bug
# In reality Bob would do this
oso-cloud tell has_role User:alice "reader" Issue:bug
oso-cloud authorize User:alice "read" Issue:bug

Groups

Groups are named collections of actors, just like roles are named collections of permissions. In this common case of Actor Hierarchies, roles and permissions are assigned directly to a group, and inherited by the group’s members.

Oso Policy

# A group is an actor and membership is a role on the group
actor Group {
  roles = ["member"];
}

# Actors inherit permissions from groups
has_permission(actor: Actor, action: String, resource: Resource) if
  has_role(actor, "member", group) and
  has_permission(group, action, resource);

CLI Example

oso-cloud tell has_role Group:oso-readers reader Org:oso
oso-cloud tell has_role User:alice member Group:oso-readers
oso-cloud authorize User:alice read Org:oso

Org Roles

In a multi-tenant application, resources are often associated with the tenant they belong to. In this special case of Resource Hierarchies, a role on an organization extends to all of its resources.

Oso Policy

# A role on an org extends to the org's resources
has_role(actor: Actor, role: String, resource: Resource) if
  has_relation(organization, "container", resource) and
  has_role(actor, role, organization);

CLI Example

oso-cloud tell has_relation Repo:service container Org:oso
oso-cloud tell has_role User:alice reader Org:oso
oso-cloud authorize User:alice read Repo:service

Custom Roles

Sometimes an application allows its users to create new roles with customizable permissions. In this case, rather than statically defining the roles in the policy, the application can create these custom roles on the fly by defining what permissions they grant.

Oso Policy

# A custom role is defined by the permissions it grants
has_permission(actor: Actor, action: String, resource: Resource) if
  role matches Role and
  has_role(actor, role, resource) and
  grants_permission(role, action);

CLI Example

# If you have the custom role "viewer", you are allowed to read
oso-cloud tell grants_permission Role:viewer read
# Alice is a viewer
oso-cloud tell has_role User:alice Role:viewer Repo:service
oso-cloud authorize User:alice read Repo:service

Default Roles

In a multi-tenant application, resources are often associated with the tenant they belong to. Users may dynamically decide an organization's default role, which all of the organization's members inherit.

Oso Policy

has_role(actor: Actor, role: String, repo: Repo) if
  org matches Org and
  has_parent(repo, org) and
  has_default_role(org, role) and
  has_role(actor, "member", org);

CLI Example

# Members of Oso are writers by default
oso-cloud tell has_default_role Org:oso writer
# Bob is a member of Oso
oso-cloud tell has_role User:bob member Org:oso
oso-cloud tell has_parent Repo:service Org:oso
oso-cloud authorize User:bob write Repo:service

Public Resources

Some resources are public, meaning they can be read by anyone. An attribute on a resource can be used to indicate that it is public.

Oso Policy

has_permission(_: Actor, "read", resource: Resource) if
  is_public(resource);

CLI Example

oso-cloud tell is_public Org:oso
oso-cloud authorize Actor:alice read Org:oso

User Statuses

Additional information about a user, such as whether it is an active account, may be used for additional authorization checks. Such information can be provided as an attribute on the user.

Oso Policy

allow(actor: Actor, action: String, resource: Resource) if
  is_active(actor) and
  has_permission(actor, action, resource);

CLI Example

oso-cloud tell has_permission User:bob delete Repo:legacy
oso-cloud tell is_active User:bob
oso-cloud authorize User:bob delete Repo:legacy

Toggles

A toggle on a resource can turn on and off certain permissions that a specific role has. The state of the toggle can be provided as an attribute on the resource.

Oso Policy

has_permission(actor: Actor, "delete", resource: Resource) if
   has_role(actor, "member", resource) and
   is_protected(resource, false);

CLI Example

oso-cloud tell has_role User:alice member Repo:legacy
oso-cloud tell is_protected Repo:legacy Boolean:false
oso-cloud authorize User:alice delete Repo:legacy
Last updated on May 25, 2022