Working with Python Types

Oso’s Python authorization library allows you to write policy rules over Python objects directly. This document explains how different types of Python objects can be used in Oso policies.

Note

More detailed examples of working with application classes can be found in our Guides.

Class Instances

You can pass an instance of any Python class into Oso and access its methods and fields from your policy (see Application Types).

Python instances can be constructed from inside an Oso policy using the new operator if the Python class has been registered using either the register_class() method or the polar_class() decorator. An example of this can be found here.

Numbers and Booleans

Polar supports integer and floating point real numbers, as well as booleans (see Primitive Types). These map to the Python int, float, and bool types.

Strings

Python strings are mapped to Polar strings. Python’s string methods may be accessed from policies:

allow(actor, _action, _resource) if actor.username.endswith("example.com");
user = User()
user.username = "alice@example.com"
assert(oso.is_allowed(user, "foo", "bar))
Warning

Polar does not support methods that mutate strings in place. E.g., capitalize() will have no effect on a string in Polar.

Lists

Python lists are mapped to Polar lists. Python’s list methods may be accessed from policies:

allow(actor, _action, _resource) if actor.groups.index("HR") == 0;
user = User()
user.groups = ["HR", "payroll"]
assert(oso.is_allowed(user, "foo", "bar"))
Warning

Polar does not support methods that mutate lists in place. E.g. reverse() will have no effect on a list in Polar.

Likewise, lists constructed in Polar may be passed into Python methods:

allow(actor, _action, _resource) if actor.has_groups(["HR", "payroll"]);
class User:
   def has_groups(self, groups):
      """ Check if a user has all of the provided groups. """
         for g in groups:
            if not g in self.groups:
               return False
         return True

user = User()
user.groups = ["HR", "payroll"]
assert(oso.is_allowed(user, "foo", "bar))

There is currently no syntax for random access to a list element within a policy; i.e., there is no Polar equivalent of the Python expression user.groups[1]. To access the elements of a list, you may iterate over it with the in operator or destructure it with pattern matching.

Dictionaries

Python dictionaries are mapped to Polar dictionaries:

allow(actor, _action, _resource) if actor.roles.project1 = "admin";
user = User()
user.roles = {"project1": "admin"}
assert(oso.is_allowed(user, "foo", "bar))

Likewise, dictionaries constructed in Polar may be passed into Python methods.

Iterables

You may iterate over any Python iterable, such as those yielded by a generator, using Polar’s in operator:

allow(actor, _action, _resource) if "payroll" in actor.get_groups();
class User:
   def get_groups(self):
      """Generator method to yield user groups."""
      yield from ["HR", "payroll"]

user = User()
assert(oso.is_allowed(user, "foo", "bar))

None

The Python value None is registered as the Polar constant nil. If a Python method can return None, you may want to compare the result to nil:

allow(actor, _action, _resource) if actor.get_optional() != nil;
class User:
   def get_optional(self):
      """Return something or None."""
      if self.some_condition():
          return self.some_thing
      else:
          return None

user = User()
assert(oso.is_allowed(user, "foo", "bar))

Python → Polar Types Summary

Python type Polar type
int Integer
float Float
bool Boolean
list List
dict Dictionary
str String

Connect with us on Slack

If you have any questions, or just want to talk something through, jump into Slack. An Oso engineer or one of the thousands of developers in the growing community will be happy to help.