Understand record access policy rules
Record access policies apply at the data record level rather than the object type level. As a result, a user may be able to see some records of a given object type, but not all of them. In database terms, it is controlling access to each row of a table, rather than to the whole table (the object) or to a column column (a field on the object).
Each policy comprises rules that define the data access filters. They are request query filters that limit the data that is returned for any request made by the Skedulo web app, mobile app, or API. A rule always has to be part of a parent policy and rules are enabled and disabled via the parent policy.
For more information about record access policies and how to manage them in the web app, see the user guide.
Important
Policy rules are extremely flexible, but can also cause the Skedulo web or mobile app to stop functioning properly if configured incorrectly. We recommend that you test new policies and their rules in a separate environment before applying them to your production system.Record access policy rule fields
Each rule consists of the following fields:
Field | Description |
---|---|
Rule description | A text description that makes it easy to identify the rule’s purpose. |
Object type | The data object that the rule must apply to, for example, if the rule pertains to accessing job records, then the object type would be Jobs . This field also supports a hasLookup:<lookup name> value (details provided below in the Pattern rules section). |
Filter records | The filter, written in EQL, that must be applied to the object data to limit what is accessible. See the EQL documentation for more information on how to write and use these filters for the Skedulo data model. |
Access type | Controls how the filter applies to the object’s data. If set to deny , then only data that passes the filter expression will be returned. Multiple deny filters for the same object act as if linked with AND operators in the query. When an object has a rule with access type deny in effect, a rule with access type allow can be added to override it if the allow filter expression passes; in effect providing an OR operator. |
Roles excluded | Users with a role listed in this field will be exempt from the rule. Note that users with the administrator role, or a role containing the “View all data” permission, are exempt from all record access policies. |
Permissions excluded | Users with a role that contains any of the permissions in this field will be exempt from the rule. For example, if you have a rule intended for resources, which denies access to jobs unless the it is allocated to the current user,you could exclude schedulers by adding a permission exclusion for skedulo.tenant.schedule.allocation.dispatch . Schedulers would be able to see jobs regardless of their allocation. |
Rule filters
Although GraphQL-binding is generally supported in Skedulo, bound lookups are not supported in the RAP rule filters. An IN
clause must be used instead. For example, if you have a rule on JobAllocations
, you should use:
ResourceId IN (SELECT UID FROM Resources WHERE Name != 'secret')
rather than Resource.Name != 'secret'
.
Note that if you were to do a JobAllocations
query via GraphQL, this syntax would be perfectly legitimate:
{
jobAllocations(filter: "Resource.Name != 'secret'") {
edges {
node {
Name
Resource {
Name
}
}
}
}
}
Rule variables
Plain text placeholders resourceId
and user
are supported in the record access policy rules. Template variables must be enclosed in single quotes, for example, {{resourceId}}
, {{user}}
.
Pattern rules
Record access policies are generally composed of rules that apply to different data object types. If, however, there is a pattern to the data that requires multiple rules to achieve, then it may be easier to use a rule that describes the pattern instead, for example, lookup relationships to a particular object type. This type of rule also covers future scenarios where objects could be linked via a lookup relationship via a new custom object.
Skedulo supports the hasLookup
pattern in rules, such that a rule can be applied to all objects that have a certain lookup relationship.
To add a pattern rule to a policy, do one of the following:
- In a POST request to
/authorization/policies/rules
, addhasLookup:<lookup name
in the Object type field.
{
"policyId": "843760be-2355-4a3d-8646-728875d81a75",
"description": "Deny all object types directly linked to a Region, unless its region is associated with the user (pattern rule)",
"objectType": "hasLookup:Region",
"filter": "RegionId IN (SELECT RegionId FROM UserRegions WHERE UserId == '{{userId}}') OR RegionId IN (SELECT PrimaryRegionId FROM Resources WHERE UID == '{{resourceId}}') OR RegionId IN (SELECT RegionId FROM ResourceRegions WHERE ResourceId == '{{resourceId}}')",
"accessType": "deny"
}
- In the Skedulo web app, on the Settings > Record access policies > Policy > Create rule page, add
hasLookup:
before the name of the lookup in the Object type field.
Lookup names can be found in the GraphL schema for your team.
The filter query will now apply to all object types that have the lookup specified.
Record access type
Each rule in a policy has a filter (a query the specifies criteria for data to show) and an access type (which determines how the queries work with each other). When multiple rules are in a single policy, the filters are applied using logic based on the access type. This helps you to separate out complex logic that applies to a single object type into separate rules, which then work as a single piece of logic at runtime.
All filters work the same, in that only data that passes the expression will be accessible. Rules are generally of the access type deny
, because they deny access to data that doesn’t meet the criteria in the filter.
If, however, an object type has a deny
rule in effect and there are some special cases when the data should be accessible, then it may make sense to add a filter that describes the circumstances under which the deny
rule does not hold. This can be achieved by adding an allow
rule, which effectively overrides the deny
rule if the given filter expression passes.
Another way to think of it is that deny
filters are applied with the AND operator, while allow
filters are added to any existing deny
filters with the OR operator.
Note: An allow
rule on an object type that does not have a deny
rule typically has no effect on records of that object type, but can still have an impact on another object type because of how record access policies handle relationships between them. For example, an allow
rule on Jobs
would have no effect in isolation, but if there was also a deny
rule on Regions
, then any job records with a region that is denied would still be visible because of the allow
rule.
Multiple rules for a single object type can be created, but it is generally simpler to contain all logic pertaining to a single object type in a single rule per access type (if more than one access type is needed).
Performance considerations
When creating record access policy rules, be mindful that some rules could have an impact on performance. For example, rules with filters that require searching through the contents of multiple text fields may require considerable computation. As always, rules need to be tested extensively before being put into production to assess their impact on the user experience and data access.
Practical example
Business requirement
Users must only see jobs that are in their region, unless they are allocated to a job in another region.
Record access policy solution
This could be achieved by adding two rules for the Jobs
object type; one with access type deny
and one with access type allow
:
- A
deny
rule that only returns jobs in the user’s region:
{
"description": "Deny access to Jobs unless they are in a region associated with the user",
"objectType": "Jobs",
"filter": "RegionId IN (SELECT RegionId FROM UserRegions WHERE UserId == '{{userId}}')",
"accessType": "deny",
"rolesExcluded": [],
"permissionsExcluded": []
}
- An
allow
rule that returns any jobs that have been allocated to the user, regardless of region (thereby overriding the first rule):
{
"description": "Allow access to Jobs that are allocated to the current Resource",
"filter": "UID IN (SELECT JobId FROM JobAllocations WHERE ResourceId == '{{resourceId}}' AND Status != 'Deleted' AND Status != 'Declined')",
"objectType": "Jobs",
"accessType": "allow",
"rolesExcluded": [],
"permissionsExcluded": []
}
The Data isolation by region policy rules
The scenario above can be seen in more detail in the Data isolation by region policy template. The Data isolation by region policy is designed so that users only see jobs that are in the same region as they are, as well as any other jobs (or shifts) that are allocated to them, regardless of region.
Rule description | Object | Access type |
---|---|---|
Deny Regions unless they are associated with the user | Regions | deny |
Deny all object types linked to a region, unless its region is associated with the user (pattern rule) | hasLookup:Region | deny |
Deny Activities unless their allocated resource’s region is associated with the user | Activities | deny |
Deny Users unless their region is associated with the user | Users | deny |
Deny Holidays unless they are global or their region is associated with the user | Holidays | deny |
Allow Contacts that do not have a region | Contacts | allow |
Allow Jobs that are allocated to the current resource | Jobs | allow |
Allow Shifts that are allocated to the current resource | Shifts | allow |
To achieve this, the policy uses a deny
rule to only show records that have the same region as the user (as in the example in the previous section). The policy has additional deny
rules for Holidays
, Activities
, and Users
, because these objects do not have direct lookups to the Region
object, but are linked via another object, for example Holiday
has HolidayRegion
and Activity
has Location
.
These rules work together to deny access; i.e., the filters in rule 1 AND rule 2 AND rule etc. are in effect.
The policy also has allow
rules that override the hasLookup:Region
rule for Jobs
and Shifts
so that users can always see work allocated to them, regardless of the region. There is a further allow
rule for Contacts
so that these are not hidden when the region field has no value.
Feedback
Was this page helpful?