Skip to main content

Directory

The Topaz Directory stores the information required to make authorization decisions. It is flexible enough to support different access control strategies including Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), and Relationship-Based Access Control (ReBAC).

An authorization decision is an answer to the question "Is subject S allowed to perform action A on resource R?" In other words, authorization decisions determine whether a subject (e.g. user, group, service) has a given permission (e.g. read, write, delete) on a resource (e.g. document, folder, project, etc.).

Concepts

Authorization Model

The authorization model specifies the object types that can participate in authorization decisions. Each object type can have relations and permissions.

Relations can be thought of as the roles that an object type supports. Permissions are the actions that can be performed on the object type, and are granted through relations.

For example, a file object type can define the can_read, can_write, and can_delete permissions, and have these granted through the owner, editor, and viewer relations.

Objects

Objects represent the participants in authorization decisions. In the context of an authorization decision one object represents a subjectan actor who performs an actionand another represents a resourcethe item that subject attempts to access.

Each object has a type and the set of all available types is defined in the directory's manifest. An object is uniquely identified by the combination of its type and a user-defined ID. For example, a user object may have an email address as its ID.

IDs must be unique within a type, but objects of different types are allowed to have the same ID.

To support ABAC-style policies in which authorization decision are affected by attributes of the resource being accessed or the subject performing the action (e.g. credit limit, date of birth, region), objects may include JSON properties that are stored in the directory and can be inspected by the authorizer when evaluating authorization requests.

In other cases, authorization decisions can be made purely based on relations between objects (e.g. Michael is the owner of the Sales folder) without any properties. Such objects don't need to be stored explicitly. They can simply appear as pairs of object type and ID in one or more relations.

Relations

A relation is a labeled association between a resource (source object) and a subject (target object). Each object type, defined in the directory's manifest, may specify the kinds of relations that can be created from objects of that type, and the definition of each relation type indicates the types of objects that can be used as the subjects of the relation.

For example, a file object type my define an owner relation that can take a user as its subject.

See the Manifest Reference for more details about defining relations.

Permissions

A permission represents a kind of action that a subject may perform on a resource. Similar to relations, each permission is defined in the manifest as part of an object type definition.

Unlike relations, permissions cannot be assigned explicitly. They are granted indirectly by combining relations and/or other permissions using permission operators.

For example, if a file resource has editor and viewer relations, it can grant a can_write permission to anyone with the editor relation to the resource, and a can_read permission to anyone who can_write or has the viewer relation. The example below illustrates this exact scenario.

Manifest

The manifest is a yaml file that defines the authorization model. Here is a manifest for the example above:

# yaml-language-server: $schema=https://www.topaz.sh/schema/manifest.json
---
model:
# version of the manifest file format.
version: 3

types:
user: {}

file:
relations:
owner: user
editor: user
viewer: user
permissions:
can_delete: owner
can_write: can_delete | editor
can_read: can_edit | viewer
  • This manifest defines two types: user and file.
  • The user type as no relations or permissions and can only used as a subject (target) of relations.
  • The file type has three relations: owner, editor, and viewer. All three can only be assigned to subjects of type user.
  • The file type has three permissions: can_delete, can_write, and can_read.
  • The can_delete permission is granted to anyone who has the owner relation to the file.
  • The can_write permission is granted to anyone with the can_delete permission on the file OR the editor relation to it.
  • The can_read permission is granted to anyone with the can_edit permission OR the viewer relation to the file.

Checking Permissions and Relations

The directory provides a convenient Check API to determine whether a subject has a given relation to or permission on a specified resource. It simply takes:

  • The type and ID of an object (the resource).
  • The relation or permission to check.
  • The type and ID of the subject.

The result of the call is a boolean value that indicates whether or not the subject has the specified relation or permission on the resource.

Example

With these building blocks, it's possible to construct expressions like:

  • Euan is a member of the Sales-group
  • Sales-folder is a parent of the Sales-plan-document
  • Sales-group is a viewer of the Sales-folder
  • The viewer relation includes the read permission

And answer queries like:

  • Does Euan have the read permission on the Sales-plan-document ?

The Topaz directory is able to evaluate this graph query, traversing through these relations and determining the outcome.

Common Object Types

While Topaz does not have any hard-coded types, it does come with a few templates, including simple-rbac, gdrive, and others. Each of these templates defines its own manifest, but these manifests share a set of common object types and relations:

  • User: a principal (typically used as a subject)
  • Group: a collection of users and/or other groups (can be used as a subject or object)
  • Identity: a unique identifier for a user (e.g. email, PID)

These object types can be found in almost all identity providers. Topaz templates define these common types to make it easy to model a few universal patterns:

  • Groups are used to model collections of users, and can be nested. This makes it easy to model authorization rules that depend on (nested) group membership.
  • Identities are used to look up users. This makes it easy to look up a user by any of their unique identifiers, including email, or the sub claim that an identity provider embeds in a JWT.

User Context and Identity objects

Applications can provide an identity context in an authorization request, which is used to look up the user object associated with that identity.

For an identity context of type IDENTITY_TYPE_JWT, the Authorizer will load an identity object with the id that is found in the sub claim of the JWT. For an identity context of type IDENTITY_TYPE_SUB, the string passed in will be used as the id of the identity object to load.

The Authorizer then looks up the identifier relation to the corresponding user object, and loads the user object, making it available to the Policy as input.user.

In this way, a Policy can reference properties of the user using the expression input.user.properties.<property_name>.

Built-ins

Authorization policies can access directory contents via a set of built-ins.