Understand record access policy rules

Record access policies are groups of filtering rules that apply when accessing data records in Skedulo.

The filters implement row-level security, meaning a user may be able to see some records of a given object type, but not all of them. In database terms, the filter is controlling access to each row of a table, rather than blocking access to the whole table (the object) or a column (a field on the object).

Each policy comprises rules that each define a data access filter for a type of object. The filters 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.

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 applies to, for example Jobs. This field also supports a hasLookup:<lookup name> value (see Pattern rules below).
Filter records The EQL filter that will be applied to the object. See also Rule filters below.
Access type Controls how the filter is applied when accessing the object’s data.
If set to deny, access will be denied unless it passes the filter condition. This is the normal use case.
If set to allow, access will be allowed if the record passes the filter condition. This may be required in special cases.

If there are multiple deny filters for the same object, they all need to pass; the conditions are linked with an AND operator.
If a deny rule is in effect for an object, an allow rule can be added to conditionally override it; the deny and allow conditions are linked with 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 skedulo.tenant.data.viewAll and skedulo.tenant.data.modifyAll permissions, 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 they are allocated to the current user (resource), you could exclude schedulers from this restriction by adding a permission exclusion for skedulo.tenant.schedule.allocation.dispatch. Schedulers and importantly, any other roles with permission to dispatch, would be able to see jobs regardless of their allocation.

Rule filters

Record access policy rule filters are defined using Skedulo’s Elastic Query Language (EQL), which is also used in the GraphQL API. See the EQL documentation for more information on how to write and use these filters for the Skedulo data model.

In general, any EQL expression that is valid in a GraphQL request is valid as a RAP rule filter. Note however that referring to a field of a lookup field is not supported in RAP rule filters. A sub-query (IN clause) must be used instead. For example, for JobAllocations a GraphQL request would support a filter "Resource.Name != 'secret'", but for a RAP rule you would need:

ResourceId IN (SELECT UID FROM Resources WHERE Name != 'secret')

Rule variables

Plain text placeholders resourceId and userId are supported in RAP filter expressions. These will be substituted with the relevant values for the user who is making each request. Template variables must be enclosed in double curly braces, for example {{resourceId}}, {{userId}}.

Pattern rules

A pattern rule is a rule that applies to multiple object types based on a common pattern in the data model of those objects. The hasLookup:<lookup-name> pattern can be specified in the object type for a RAP rule in order to match every object type that that has a Lookup field with the given name.

The rule will be applied to all object types in the data model that have defined a lookup with the specified name. For example, to control access to data based an object’s related account (if they have one), you could define a rule with object type hasLookup:Account.

Note the pattern is based on the name of the lookup relationship in the data model, so the filter can refer to the corresponding ID field (“AccountId” in the above example). If an object had a custom field that was a lookup to the Accounts object but was not named “Account” (say it was “CustomerAccount”), then it would not be affected by this rule.

The names of the lookup relationships in the data model can be found in the GraphL schema for your team or in the Objects and Fields settings in the Skedulo web app.

Screenshot of the hasLookup:Region pattern rule in the list of rules in the Data Isolation by Region policy

Record access type

Each rule in a policy has a filter and an access type that determines how the queries work with each other. When there are multiple rules that apply to a given object type, the filters are combined using logic according to the access type. This helps you to separate out complex logic applying to an object type into separate rules that combine to work as a single conditional expression at runtime.

The deny access type can be thought of as “Deny unless the condition is true”, while the allow access type can be thought of as “But allow if the condition is true”.

If an object type has a deny rule in effect but there are cases when the data should be accessible, then you can add an allow filter that describes when the deny rule should be overridden.

Another way to think of it is that deny filters are combined with the AND operator and then allow filters are added with the OR operator.

Note: Generally, an allow rule on an object type that does not have a deny rule has no effect on records of that object type. However, it can still have an impact on another object type because of the filters that are automatically added to handle mandatory lookup relationships. For example, if there was a deny rule on Regions, then any job records associated with denied regions would also be denied due to the fact that Jobs has a mandatory lookup to Regions. If an allow rule is added for Jobs then the deny rule on Regions can be effectively overridden for jobs.

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

Resources must only see jobs that are in their region, but if jobs from other regions have been allocated to them, then they can also see those jobs.

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:

  1. 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": [ "skedulo.tenant.schedule.allocation.dispatch" ]
}
  1. 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

Skedulo provides a pre-defined record access policy for “Data isolation by region”. This policy prevents users from seeing any data that is associated with a region unless the user is also associated with that region.

This policy can be seen in more detail in the [Data isolation by region policy template].(/user-guides/admin-and-config/admin-and-config-webapp/permissions-and-data-access-control/use-record-access-policies-to-control-data-access/record-access-policy-templates/#policy-template-data-isolation-by-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 the goal, the policy has a pattern rule of type deny 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 a direct lookup to the Region object, but are linked via an imtermediate object. For example Holidays are linked via HolidayRegion and Users are linked via UserRegion.

The policy also has allow rules so that users can always see work allocated to them, regardless of the region. There is a further allow rule for Contacts so that contacts are not hidden when the optional region field is undefined.