oso
oso copied to clipboard
Built-in `get_allowed_permissions`-style method to retrieve all allowed (action, resource) pairs for a given actor
Hello!
We are creating an RBAC implementation based on OSO and it is working fine.
Currently the library provides a way to retrieve actions for a single resource using oso.get_allowed_actions()
.
For example, John can "read"
a "Post 1"
. By asking oso.get_allowed_actions("Josh", "Post 1")
we can get following result: ["read"].
Unfortunately, our project has a complex UI so it is not possible to ask backend for available actions per resource on the page because it may cause:
- high amount of similar http requests asking about allowed actions for resource
- high traffic
- resource consumption on the server
- poor user experience and other related issues
Is it possible to somehow get result like [("read", "Post 1")]
in a single query? We are trying to feed UI with all available permissions using one HTTP query.
We managed to get almost desired results using following python code:
# Predicates have following signature:
# assign_role(user, role) — maps user to role
# role_allow(role, action, resource, user) — describes which action role's owner can do, user is a hacky way to provide more context to the predicate.
# User -assigned_to-> Role -grants-> Action-On-Resource
user = User(2)
assigned_roles = oso.query_rule("assign_role", user, Variable("role"))
for result in assigned_roles:
role = result.get("bindings").get("role")
permissions = oso.query_rule("role_allow", role, Variable("action"), Variable("resource"), user, accept_expression=True)
for p in permissions:
print(p)
# The output is following:
# {'bindings': {'resource': 'Post1', 'action': 'read'}, 'trace': None}
# {'bindings': {'action': 'delete', 'resource': Expression(And, [Expression(Isa, [Variable('_this'), Pattern(Post, {})]), Expression(Unify, [Expression(Dot, [Variable('_this'), 'id']), 2])])}, 'trace': None}
# {'bindings': {'resource': 'Post2', 'action': 'write'}, 'trace': None}
Provided solution
- feels like a hack,
- has N+1 query problem (caching must be used to partially solve the issue),
- we have to parse returned
Expression
to figure out which instance (object) is described in results
It would be great to have a way to achieve this task in more readable and performant way.
Thanks!
Thanks for opening the issue @asyncee! I agree this would be a nice feature to have — I'm imagining an API in the same vein as Oso.get_allowed_actions
(renamed to Enforcer.authorized_actions
in the new beta release).
It should be possible to get around the N+1 issue by setting up your policy like so:
has_role("Abhi", "writer");
role_allow("writer", "write", "Post 1");
role_allow("writer", "write", "Post 2");
allow(user, action, resource) if
has_role(user, role) and
role_allow(role, action, resource);
And then querying for:
abhi = "Abhi"
permissions = oso.query_rule("allow", abhi, Variable("action"), Variable("resource"), accept_expression=True)
for p in permissions:
print(p)
Great news, thanks, i'll try it!
It works great, not sure why this elegant solution missed my head :)
It works great, not sure why this elegant solution missed my head :)
In fairness, it also missed mine while I was talking to you on Slack before you opened this issue haha. I re-read the issue and had an "aha" moment 😆
FWIW I still think we could ultimately add a built-in get_allowed_actions
-style API for this — Polar is very well-suited to this "for a given rule, keep N arguments concrete and query for all possible combinations of the remaining arguments" type of policy introspection.
@asyncee does the new issue title look good? Feel free to adjust
Very accurate, looks good.
This seems like, from an implementation perspective, it would pair well with #1427 as a pull request in one go