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 our Guides.

Structs + Enums

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

Rust structs can also be constructed from inside an Oso policy using the new operator if a type constructor is provided at registration.

Numbers and Booleans

Polar supports integer and floating point real 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:

allow(actor, _action, _resource) if actor.username.ends_with("example.com");
#[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.

Vec

Vec<T> maps to a Polar list, given that T: ToPolar.

Implementations also exist to convert LinkedList, VecDeque, BinaryHeap, HashSet, and BTreeSetto and from Polar lists, but lists are treated as Vec<T> when calling methods.

Currently, no methods on Vec are exposed to Polar.

allow(actor, _action, _resource) if "HR" in actor.groups;
#[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.

Rust methods like Vec::get may be used for random access to list elements, but there is currently no Polar syntax that is equivalent to the Rust 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.

HashMap

A Rust HashMap maps to a Polar dictionary but requires that the HashMap key is a String.

Implementations also exist to convert BTreeMaps to and from Polar dictionaries, but dictionaries are treated as HashMap when calling methods.

allow(actor, _action, _resource) if actor.roles.project1 = "admin";
#[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 Rust methods.

Iterators

You may iterate over a Rust iterator using Polar’s in operator:

allow(actor, _action, _resource) if "payroll" in actor.get_groups();
#[derive(Clone, PolarClass)]
struct User {
    groups: Vec<String>,
}

oso.register_class(
    User::get_polar_class_builder()
        .add_iterator_method("get_groups", |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")?);

Options

The Rust type Option<T> is registered as a class. You can use unwrap() on an option in a policy, but it’s safer to use the in operator, which will return 0 or 1 values depending on whether the value is None or Some(T) respectively.

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

allow(actor, _action, _resource) if
    "Jimmy" in actor.nickname or
    actor.get_optional() != nil;
#[derive(Clone, PolarClass)]
struct User {
    #[polar(attribute)]
    nickname: Option<String>,
}

oso.register_class(
    User::get_polar_class_builder()
        .add_method("get_optional", |u: &User| None)
        .build(),
)
.unwrap();

let user = User { nickname: Some("Jimmy".to_string()), };
assert!(oso.is_allowed(user, "foo", "bar")?);

Rust → Polar Types Summary

Rust type Polar type
i32, i64, usize Integer
f32, f64 Float
bool Boolean
String, &'static str, str String
HashMap, BTreeMap Dictionary
Vec, LinkedList, VecDeque BinaryHeap, HashSet, BTreeSet List

Set up a 1x1 with an Oso Engineer

Our team is happy to help you get started with Oso. If you'd like to learn more about using Oso in your app or have any questions about this guide, schedule a 1x1 with an Oso engineer.


Was this page useful?