Rust Authorization Library

oso is packaged as a cargo crate for use in Rust applications.

API documentation for the crate lives on docs.rs.

To install, see installation instructions.

Working with Rust Types

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

Note

More detailed examples of working with application objects can be found in Policy Examples.

Structs + Enums

Rust structs and enums can be registered with oso which lets you pass them in and access their methods and fields. (see Application Types).

Rust structs can also be constructed from inside an oso policy using the New operator if the type has been given a constructor when registered.

Numbers and Booleans

Polar supports both integer and floating point numbers, as well as booleans (see Primitive Types).

Strings

Rust Strings are mapped to Polar Strings. Many of rust’s string methods may be called in policies:

policy.polar
allow(actor, action, resource) if actor.username.ends_with("example.com");
main.rs
#[derive(Clone, PolarClass)]
struct User {
  #[polar(attribute)]
  pub username: String
}

oso.register_class(User::get_polar_class())?;

let user = User{username: "alice@example.com".to_owned()};
assert!(oso.is_allowed(user, "foo", "bar")?);

Warning

Polar does not support methods that mutate strings in place.

Vectors

Vec<T> is mapped to Polar Lists, given that T: ToPolar.

Currently, no methods on Vec are exposed to Polar.

policy.polar
allow(actor, action, resource) if "HR" in actor.groups;
main.rs
#[derive(Clone, PolarClass)]
struct User {
    #[polar(attribute)]
    pub groups: Vec<String>,
}

oso.register_class(User::get_polar_class())?;

let user = User { groups: vec!["HR".to_string(), "payroll".to_string()] };
assert!(oso.is_allowed(user, "foo", "bar")?);

Warning

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

HashMaps

Rust HashMaps are mapped to Polar Dictionaries, but require that the HashMap key is a String:

policy.polar
allow(actor, action, resource) if actor.roles.project1 = "admin";
main.rs
#[derive(Clone, PolarClass)]
struct User {
    #[polar(attribute)]
    pub roles: HashMap<String, String>,
}

oso.register_class(User::get_polar_class())?;

let user = User { roles: maplit::hashmap!{ "project1".to_string() => "admin".to_string() } };
assert!(oso.is_allowed(user, "foo", "bar")?);

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

Iterators

oso handles Rust iterators by evaluating the yielded values one at a time. To register methods returning iterators, you need to use the Class::add_iterator_method call.

policy.polar
allow(actor, action, resource) if actor.get_group() = "payroll";
main.rs
  #[derive(Clone, PolarClass)]
  struct User {
      groups: Vec<String>,
  }

  oso.register_class(
      User::get_polar_class_builder()
          .add_iterator_method("get_group", |u: &User| u.groups.clone().into_iter())
          .build(),
  )
  .unwrap();

  let user = User {
      groups: vec!["HR".to_string(), "payroll".to_string()],
  };
  assert!(oso.is_allowed(user, "foo", "bar")?);

In the policy above, the body of the allow rule will first evaluate "HR" = "payroll" and then "payroll" = "payroll". Because the latter evaluation succeeds, the call to oso.is_allowed will succeed. Note that if get_group returned an array instead of an iterator, the rule would fail because it would be comparing an array (["HR", "payroll"]) against a string ("payroll").

Summary

Rust -> Polar Types Summary

Rust type

Polar type

i32, i64, usize

Number (Integer)

f32, f64

Number (Float)

bool

Boolean

String, &’static str, str

String

Vec

List

HashMap

Dictionary