Oso 0.20.0.beta is out! It includes three major new features to cut down the amount of thinking you need to do when adding authorization to your app:
- Built-in syntax for common authorization models like role- and relationship-based access control
- Data filtering from any data source in Python, Ruby and JavaScript (support for other languages coming soon)
- Built-in APIs for resource-level, field-level and request-level enforcement
Join us in Slack to talk about your app, the new features, how to use them, how we built them and any other questions you have about the beta.
Built-In Syntax for Role- and Relationship Based Access Control
We've taken the most common authorization models, built them into our declarative policy language, Polar, and pruned the syntax for concision. The result is that you have ready-to-go primitives for defining who can access what in your app. This syntax plays beautifully with the rest of Polar, and you can be extend using it built-in rules to cover anything that falls outside of the built-in model, like conditional permissions.
Here's a policy example for a GitHub clone app where we declare "reader"
& "writer"
roles on a Repository.
# Declare a Repository resource in Polar
resource Repository {
# A repository has the "reader" and "writer" role
roles = ["reader", "writer"];
# A repository has "pull" and "push" permissions
permissions = ["pull", "push"];
# A repository has a creator with the User type.
relations = { creator: User };
# A user has the writer role if they are the creator.
"writer" if "creator";
# A user has the reader role if they have the writer role.
"reader" if "writer";
# A user has the push permission if they have the writer role.
"push" if "writer";
# A user has the pull permission if they have the reader role.
"pull" if "reader";
}
This syntax is available in Oso 0.20.0.beta, but we have not yet released documentation for it. If you are using built-in roles now, or thinking about building role-based access control, this is a feature for you. It makes policy code easier to write and easier to read.
If you want to try out the new syntax, set up a 1x1 with an Oso engineer. We'll help you think through your authorization model and show you how to quickly apply it using the built-in role & relationship modeling.
Data filtering from any Data Source in Python, Ruby and Node
Oso has supported authorizing collections of objects using data filtering for some time. Data filtering is useful when you want to display a list of authorized objects to users without loading all data into memory. Data filtering translates your authorization policy into filters that can be applied by your database when retrieving records.
But until this point, data filtering was only available to Python SQLAlchemy and Django users. Today, we're releasing the Fetcher API for data filtering, available for Python, Ruby and Node. Fetchers lets you tell Oso how to retrieve data from any data store: a database, another service, or even a search index. To use the fetcher API, you implement a function that processes a simple set of filters from the policy and returns authorized objects.
Here's an example implementing the fetcher API in Python for Repositories:
# Implement fetcher for Repositories
def get_repositories(constraints):
query = session.query(Repository)
for constraint in constraints:
assert constraint.kind in ["Eq", "In"]
field = getattr(Repo, constraint.field)
if constraint.kind == "Eq":
query = query.filter(field == constraint.value)
elif constraint.kind == "In":
query = query.filter(field.in_(constraint.value))
return query.all()
# Register your data type with Oso
oso.register_class(
Repository,
types={
"id": str,
"org_id": str,
"org": Relationship(
kind="parent", other_type="Organization", my_field="org_id", other_field="id"
),
},
fetcher=get_repos,
)
We currently support fetchers for the most common operations in an Oso policy: =
, in
, and
and or
. We're working hard to add support for additional operators in short order, as well as support for Java, Go and Rust.
See our documentation on this feature to get started with it!
Built in APIs for resource-level enforcement, field-level enforcement, and request level enforcement
To use Oso you: 1) Model your authorization logic in a policy, and 2) Enforcement the policy throughout your app. Before, you would need to wrap is_allowed
with custom code or use the lower level query_rule
API to accomplish field level & request level enforcement. Now, the Oso API has explicit support for resource level, field level, and request enforcement.
Here's an example of using the new enforcement API in Python to perform resource-level enforcement:
# Setup your authorization policy.
policy = Policy()
policy.load_file("authorization.polar")
# Build an enforcer
oso = Enforcer(policy)
# Enforce resource authorization in your controller
def get_expense(user, expense_id):
expense = db.fetch(
"SELECT * FROM expenses WHERE id = %", expense_id)
oso.authorize(user, "read", expense)
# process request & return response ...
See our documentation for more on this feature, including field-level & request-level enforcement.
Other Bug Fixes and Improvements
Changed precedence of and & or operations
The or
operator now has lower precedence than and
to be consistent with other languages. Use parenthesis for grouping to achieve the old precedence if needed:
foo(a, b, c) if a and (b or c);
In the beta release, using or
without parenthesis will cause an error to avoid silent changes to policy behavior. We will removed this error in 0.20.0.
Breaking on rules in the debugger
The debugger can now step to the next rule, using the rule
command. See our debugger documentation for more details.
For more details on these and other changes, read the changelog.
Set up a 1x1 with an Oso engineer
Our team is happy to help you get started with Oso. If you'd like to try out any of these new features, or if you're interested in learning how to use Oso in your app, schedule a 1x1 with an Oso engineers.
Our team is also available to help in Slack.