Inheriting roles from other resources

Using the relations feature

If two resources have a hierarchical relationship (e.g. parent-child), users commonly inherit roles or permissions on the subordinate resource from their role on the superior resource.

In this case, users often rely on Polar's relations feature, which often expresses the relationship between the resources in the subordinate resource's definition.

A common example of this is files and folders; granting access to a folder typically grants access to the folder's contents.

In this example, anyone with a role on a folder also has the same role on any file/folder it contains.

Oso Policy


actor User { }
resource Repository {
roles = ["reader", "maintainer"];
}
resource Folder {
roles = ["reader", "writer"];
relations = {
repository: Repository,
folder: Folder,
};
"reader" if "reader" on "repository";
"writer" if "maintainer" on "repository";
role if role on "folder";
}
resource File {
permissions = ["read", "write"];
roles = ["reader", "writer"];
relations = {
folder: Folder,
};
role if role on "folder";
"read" if "reader";
"write" if "writer";
}
test "folder roles apply to files" {
setup {
has_role(User{"alice"}, "reader", Repository{"anvil"});
has_relation(Folder{"python"}, "repository", Repository{"anvil"});
has_relation(Folder{"tests"}, "folder", Folder{"python"});
has_relation(File{"test.py"}, "folder", Folder{"tests"});
}
assert allow(User{"alice"}, "read", File{"test.py"});
}

Using longhand rules

If two types of resources have any kind of relationship (hierarchical or otherwise), you can inherit roles on one resource from the other. For example, in a parent-child relationship, users can inherit roles from the child on the parent.

This essentially uses the same convention as the relations feature (relying on has_relation facts in your authorization data), but requires writing out the rule in longhand.

Oso Policy


actor User {}
resource ParentResource {
roles = ["admin", "member"];
permissions = ["read", "write"];
"read" if "member";
"write" if "admin";
"member" if "admin";
}
resource ChildResource {
roles = ["admin", "member"];
permissions = ["read", "write"];
relations = { parent: ParentResource };
"read" if "member";
"write" if "admin";
"member" if "admin";
# ChildResource inherits admin from ParentResource
"admin" if "admin" on "parent";
}
# ParentResource inherits member from ChildResource
has_role(user: User, "member", parent_resource: ParentResource) if
child_resource matches ChildResource and
has_role(user, "member", child_resource) and
has_relation(child_resource, "parent", parent_resource);
test "inherit role on parent from child" {
setup {
has_relation(ChildResource{"anvil"}, "parent", ParentResource{"acme"});
has_role(User{"alice"}, "member", ChildResource{"anvil"});
}
assert allow(User{"alice"}, "read", ParentResource{"acme"});
}