Working with Ruby Types

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

Note

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

Class Instances

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

Ruby instances can be constructed from inside an Oso policy using the new operator if the Ruby class has been registered using the Oso#register_class method. 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 Ruby Integer, Float, and TrueClass/FalseClass types.

Strings

Ruby strings are mapped to Polar strings. Ruby’s string methods may be called in policies:

allow(actor, _action, _resource) if actor.username.end_with?("example.com");
class User
  attr_reader :username

  def initialize(username)
    @username = username
  end
end

user = User.new("alice@example.com")
oso.authorize(user, "foo", "bar")
Warning

Polar does not support methods that mutate strings in place.

Lists

Ruby Arrays are mapped to Polar lists. Ruby’s Array methods may be called in policies:

allow(actor, _action, _resource) if actor.groups.include?("HR");
class User
  attr_reader :groups

  def initialize(groups)
    @groups = groups
  end
end

user = User.new(["HR", "payroll"])
oso.authorize(user, "foo", "bar")
Warning

Polar does not support methods that mutate lists in place unless the list is also returned from the method.

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

allow(actor, _action, _resource) if actor.has_groups?(["HR", "payroll"]);
class User
  attr_reader :groups

  def initialize(groups)
    @groups = groups
  end

  def has_groups(other)
    @groups & other == other
  end
end

user = User.new(["HR", "payroll"])
oso.authorize(user, "foo", "bar")

Ruby methods like Array#at may be used for random access to list elements, but there is currently no Polar syntax that is equivalent to the Ruby expression user.groups[1]. To access the elements of a list without using a method, you may iterate over it with the in operator or destructure it with pattern matching.

Hashes

Ruby hashes are mapped to Polar dictionaries:

allow(actor, _action, _resource) if actor.roles.project1 = "admin";
class User
  attr_reader :roles

  def initialize(roles)
    @roles = roles
  end
end

user = User.new({"project1" => "admin"})
oso.authorize(user, "foo", "bar")

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

Enumerables

You may iterate over any Ruby enumerable using Polar’s in operator:

allow(actor, _action, _resource) if "payroll" in actor.get_groups();
class User
  def get_groups(self)
    ["HR", "payroll"]
  end
end

oso.authorize(User.new, "foo", "bar")

nil

The Ruby value nil is registered as the Polar constant nil. If a Ruby method can return nil, you may want to compare the result to Polar’s nil in your policy:

allow(actor, _action, _resource) if actor.get_optional != nil;
class User
  def get_optional
    some_condition? ? some_thing : nil
  end
end

oso.authorize(User.new, "foo", "bar")

Ruby → Polar Types Summary

Ruby type Polar type
Integer Integer
Float Float
TrueClass Boolean
FalseClass Boolean
Array List
Hash Dictionary
String 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.