Operators
When building conditions, you need to be aware of the different types of operators you can use to construct your complex condition rules. There are two types of operators that you need to be aware of - Logical and Comparison.
Logical Operators
There are currently three types of logical operators you need to be aware of. These work like logic gates and represent a boolean function.
Logical Operator | Alias (if any) |
---|---|
AND | allOf |
OR | anyOf |
NOT | not |
Comparison Operators
Comparison operators enable us to construct much more complex conditions and introduce more concrete rules to our policies.
Text | String used in condition | Description | Valid for type |
---|---|---|---|
EQUALS | equals | a = b | Bool, Number, String |
DOES NOT EQUAL | not-equals | a != b | Bool, Number, String |
LESS THAN | less-than | a < b | Number |
GREATER THAN | greater-than | a > b | Number |
LESS THAN EQUALS | less-than-equals | a ≤ b | Number |
GREATER THAN EQUALS | greater-than-equals | a ≥ b | Number |
CONTAINS | contains | "aaa??bbbbbb" | String |
ARRAY CONTAINS | array_contains | ["a", "b", "c"] has "a" | Array |
ARRAY SUBSET | array_subset | ["a", "b"] has ["a", "b", "c"] | Array |
ARRAY SUPERSET | array_superset | ["a", "b", "c"] has ["a", "b"] | Array |
ARRAY INTERSECT | array_intersect | ["a", "b", "c"] and ["c", "d", "e"] share at least one value | Array |
EQUALS REF (reference) | ref | E.G. equals user email | Number, Array, String |
NOT EQUAL REF (reference) | ref | E.G. not equals user key | Number, Array, String |
CONTAINS REF (reference) | ref | E.G. tenant name contains user first_name | String |
ARRAY CONTAINS REF (reference) | ref | ["admin", "editor"] contains user role | Array |
LESS THAN (reference) | ref | a < b | Reference to number value E.G user.age |
GREATER THAN (reference) | ref | a > b | Reference to number value E.G user.age |
LESS THAN EQUALS (reference) | ref | a ≤ b | Reference to number value E.G user.age |
GREATER THAN EQUALS (reference) | ref | a ≥ b | Reference to number value E.G user.age |
The ref
operators are mentioned using a nested object in the condition set.
For example, if you want to check if the user's email is equal to the user's first name, you can use the following condition:
{
"allOf": [
{
"user.email": {
"contains": {
"ref": "user.first_name"
}
}
}
]
}
Object Match Operators
Object-match operators enables us to run multiple comparisons on object-like (or dictionary-like) attributes, as well as object-array attributes.
Matching a single Object-typed attribute
Assuming you have a user attribute called user.organization
with type Object
:
{
"name": "Cool Inc",
"country": "US"
"subscription": "pro",
...
}
And you want to have a condition set that filters all users who are working in companies located in the US and have "pro" subscriptions:
If we map each attribute from our source data into a separate attribute in Permit, the conditions would look like this:
{
"allOf": [
{"user.country": {"equals": "US"}},
{"user.subscription": {"equals": "pro"}}
]
}
In other words, normal comparison operators will do the trick.
However with object-typed attributes, we can have a single user.organization
attribute:
{
"allOf": [
{
"user.organization": {
"object_match": {
"match": {
"country": {"equals": "US"},
"subscription": {"equals": "pro"}
}
}
}
}
]
}
As you can see, when you match an object you can use comparison operators within the match
object, for each object-attributes and only if all the conditions match - the operator will return a true
result.
This is beneficial in case you want to map your data as closely to the source data format in your db, but it becomes crucial if you data is an array of dictionaries (or object-array).
Matching Object Array typed attribute
Assuming you have a user attribute called user.organizations
with type Object Array
:
[
{
"name": "Cool Inc",
"country": "US"
"subscription": "pro",
...
},
{
"name": "Awesome Inc",
"country": "IN"
"subscription": "enterprise",
...
},
{
"name": "Sweet Inc",
"country": "US"
"subscription": "enterprise",
...
},
]
In other words, a user can belong to multiple companies, and you still wish to have a condition set that filters all users who are working in companies located in the US and have "pro" subscriptions.
In this case, it is not possible to split the user.organizations
attribute, instead we can match each item of the array:
{
"allOf": [
{
"user.organizations": {
"any_match": {
"match": {
"country": {"equals": "US"},
"subscription": {"equals": "pro"}
}
}
}
}
]
}
This will return true if a single item in the user.organizations
array is an object where item.country == "US"
and item.subscription == "pro"
.
Finally if we want to check if all items in the array match a certain condition we can replace any_match
with all_match
:
{
"allOf": [
{
"user.organizations": {
"all_match": {
"match": {
"country": {"equals": "US"},
"subscription": {"equals": "pro"}
}
}
}
}
]
}
Object Match Operator Reference
Text | String used in condition | Description | Valid for type |
---|---|---|---|
Object Match | object_match | apply conditions to multiple sub-attributes of an object-typed attribute and return true if all the conditions are met | Object |
Any Match | any_match | apply conditions to each item of an object-array attribute (use comparison operators on each sub attribute of the item) an return true if all the conditions are met for at least one item in the array | Object Array |
All Match | all_match | apply conditions to each item of an object-array attribute (use comparison operators on each sub attribute of the item) an return true if all the conditions are met for all the items of the array | Object Array |
Object Match using a "foreign key"
In some cases, we have an attribute on one resource that references the key of other resource.
For example, a resource repo
has an attribute of organization
( string ) that holds the organization key of that repo,
similar to a foreign key in a database.
In case we want to create a condition that checks if the organization of the repo is located in the US, we can the
object_match
operator with a reference to the organization object by adding the fk_resource_type
key and provide the foreign resource type in it.
The following example will extract the stored attributes of the organization in the organization
attribute of the repo
resource queried
and apply the conditions on those extracted organization attributes:
{
"allOf": [
{
"resource.organization": {
"object_match": {
"match": {
"country": {"equals": "US"}
},
"fk_resource_type": "organization"
}
}
}
]
}
Same can be done using the any_match
and all_match
operators for array of foreign keys attributes.
For example, A resource repo
has an attribute of issues
( array of string ) that holds the foreign keys to the issues of that repository.
In case we want to create a condition that checks that all the repo issues are closed we can use the any_match
or all_match
operators with the fk_resource_type
key and provide the foreign resource type in it.
The following example will extract the stored attributes of each issue in the issues
attribute of the repo
resource queried
and apply the conditions on those extracted issue attributes:
{
"allOf": [
{
"resource.issues": {
"all_match": {
"match": {
"status": {"equals": "closed"}
},
"fk_resource_type": "issue"
}
}
}
]
}
This can also be done with any_match
:
{
"allOf": [
{
"resource.issues": {
"any_match": {
"match": {
"status": {"not-equals": "closed"}
},
"fk_resource_type": "issue"
}
}
}
]
}
While other ABAC operators can be used by attributes from the check arguments or attributes stored in Permit/PDP,
the foreign key condition aims to solve cases where we already store the attributes in Permit Cloud and
want to have a condition that does not need to pass them explicitly as part of the check function.
Now that we have a basic understanding of the language to construct conditions, lets jump into creating Condition Sets.