Polar Language Reference

Reference guides for the Polar policy language.

Polar Syntax

A brief description of the core syntax elements of Polar.

Java Types in Polar
Working with Java Types Oso’s Java authorization library lets you write policy rules over Java objects directly. This document explains how different types of Java 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 may pass an instance of any Java class into Oso and access its methods and fields from your policy (see Application Types). Java instances can be constructed from within an Oso policy using the new operator: new User("alice@example.com") To construct instances of a Java class, the class must be registered using the registerClass() method: oso.registerClass(User.class) If you want to refer to the class using another name from within a policy, you may supply an alias: oso.registerClass(Person.class, "User") At instantiation time, Oso will search the list returned by Class.getConstructors() for a constructor that is applicable to the supplied positional constructor arguments. For example, given the Polar expression new User("alice@example.com"), Oso will search for a Constructor with one parameter compatible with String.class, e.g.: public User(String username) { ... } Applicability is determined using Class.isAssignableFrom(Class<?> cls), which allows arguments that are instances of subclasses or implementations of interfaces to properly match the constructor’s parameter types. Numbers and Booleans Polar supports integer and floating point real numbers, as well as booleans (see Primitive Types). Note Java primitives may be passed into Oso, but numbers and booleans created in an Oso policy will be converted to autoboxed Integer, Float, and Boolean types respectively. This means that methods called from Oso must have autoboxed argument types. E.g.: class Foo { public static unboxed(int a, int b) { // ... } public static boxed(Integer a, Integer b) { // ... } } The boxed() method may be called from a policy, but attempting to call unboxed() will fail. Strings Java Strings are mapped to Polar strings. Java’s String methods may be accessed from policies: allow(actor, action, resource) if actor.username.endsWith("example.com"); public class User { public String username; public User(String username) { this.username = username; } public static void main(String[] args) { User user = new User("alice@example.com"); assert oso.isAllowed(user, "foo", "bar"); } } Lists and Arrays Java Arrays and objects that implement the List interface are mapped to Polar lists. Java’s List methods may be accessed from policies: allow(actor, action, resource) if actor.groups.contains("HR"); public class User { public List<String> groups; public User(List<String> groups) { this.groups = groups; } public static void main(String[] args) { User user = new User(List.of("HR", "payroll")); assert oso.isAllowed(user, "foo", "bar"); } } Note that the isAllowed() call would also succeed if groups were an Array. Warning Polar does not support methods that mutate lists in place. E.g., add() will have no effect on a list in Polar. Likewise, lists constructed in Polar may be passed into Java methods: allow(actor, action, resource) if actor.has_groups(["HR", "payroll"]); public class User { ... public boolean hasGroups(List<String> groups) { for(String g : groups) { if (!this.groups.contains(g)) return false; } return true; } public static void main(String[] args) { User user = new User(List.of("HR", "payroll")); assert oso.isAllowed(user, "foo", "bar"); } } Java methods like List.get may be used for random access to list elements, but there is currently no Polar syntax for that is equivalent to the Java 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. Maps Java objects that implement the Map interface are mapped to Polar dictionaries: allow(actor, action, resource) if actor.roles.project1 = "admin"; public class User { public Map<String, String> roles; public User(Map<String, String> roles) { this.roles = roles; } public static void main(String[] args) { User user = new User(Map.of("project1", "admin")); assert oso.isAllowed(user, "foo", "bar"); } } Likewise, dictionaries constructed in Polar may be passed into Java methods. Enumerations You may iterate over a Java Enumeration (or anything that can be converted to one, such as a Collection or Iterable) using Polar’s in operator: allow(actor, action, resource) if "payroll" in actor.getGroups(); public class User { public List<String> getGroups() { return List.of("HR", "payroll"); } public static void main(String[] args) { User user = new User(Map.of("project1", "admin")); assert oso.isAllowed(user, "foo", "bar"); } } null The Java null reference is registered as the Polar constant nil. If a Java method can return null, you may want to compare the result to nil: allow(actor, action, resource) if actor.getOptional() != nil; public class User { ... public Thing getOptional() { if someCondition() { return new Thing(); } else { return null; } } } Java → Polar Types Summary Java type Polar type int/Integer Integer float/Float Float double/Double Float boolean/Boolean Boolean List List Array List Map Dictionary String String