Skip to main content

Access policies

Conditional item access

Permissions let you define who has read/write access to all the items of a particular design/interface. For more granular per-item access control, you can extend your permissions configuration with access policies via the Alloy API.

An access policy lets you define rules for groups that grant conditional read access to items of a specific design, based on one or more item values.

For example, this group can only see items of the Basic Highway Jobs design, whose Geometry attribute is within this area.

Access policies are enforced throughout Alloy, whenever item data is fetched. This includes:

If any access policies exist for a given design/interface, the items shown to users will be filtered, according to the groups a user is assigned to (either directly or via a role).

Note

Layers and workflows aren't affected by access policies because they run under a system user (even when manually triggered). However, you can use permissions to individually restrict access if needed.

Interface access policies

If you create an access policy for an interface, it will apply to all designs/interfaces that implement it.

For example, this group can only see items of designs that implement the Jobs interface, whose Team attribute stores this value.

However, be aware that those designs/interfaces may have their own access policies, which could affect the overall item results.

Multiple access policies

In situations where multiple access policies apply, group users will see items that fulfil any of them (logical OR).

For example, imagine a user that belongs to both groups mentioned in the two examples above. If they search the Basic Highway Jobs design, they'll only see items located in the specified area, or assigned to the specified team, or both.

Caution

Access policies don't work on their own! If a group doesn't have the Read permission enabled for a design/interface, the group can't access any of those items, regardless of any access policies.

API only

Currently, access policies can only be created and edited via the Alloy API by admin users. The AccessPolicy endpoint details are available on Swagger.

Create an access policy

No rules are defined when creating an access policy.

POST /api/accessPolicy
{
"name": "MyExampleAP",
"description": "This access policy demonstrates the types of rule that can be added",
"enabled": false, // only set this to true when ready to use
"targetDodiCode": "designs_myExampleDesign" // the Guc code of the design/interface this will apply to
}
Response
{
"code": "accessPolicies_myExampleAP_64d92cac1669d55c91815627",
"name": "MyExampleAP",
"description": "This access policy demonstrates the types of rule that can be added",
"enabled": false,
"targetDodiCode": "designs_myExampleDesign",
"rules": [],
"metadata": {
"createdDate": "2023-08-10T1:19:09.035Z",
"createdUserUsername": "tobylerone",
"signature": "64d92cad1669d55s91815269"
}
}

Add a rule

You can add one or more rules to an access policy. Each rule can apply to one or more groups. All rules must be fulfilled for read access to be granted (logical AND).

The rule's expression property accepts one expression of any type (logical, relational, conditional). The expression model can contain other expressions models, enabling you to construct a complex rule definition.

POST /api/accessPolicy/{code}/rule
{
"userGroups": ["userGroups_MyExampleGroup"],
"expression": {
// a single expression model of any type
},
"signature": "64d92cad1669d55s91815269" // to get the current signature, use GET /api/accessPolicy/{code}
}

Expression types

Logical expressions

A logical expression lets you enforce conditional logic. Its conditions property accepts one or more expressions (relational or conditional).

Depending on the supplied discriminator:

  • AccessPolicyAndExpressionWebModel - all conditions must be met for the expression to be fulfilled.

  • AccessPolicyOrExpressionWebModel - at least one condition must be met for the expression to be fulfilled.

{
"conditions": [
// one or more relational/conditional expression models
],
"discriminator": "AccessPolicyOrExpressionWebModel" // one of the two described above
}

Relational expressions

Relational expressions let you evaluate items related to the current item.

Parent relation

This relational expression performs a single hop to any parent items that reference the current item via the specified Link attribute.

Its RelationCondition property accepts one conditional expression, which is evaluated against the parent items. The relational expression is fulfilled if any parent items fulfil the condition (logical OR).

{
"attributeCode": "attributes_exampleParentDesignLinkAttribute_62ffa11f29e504015a04d7b0",
"condition": "All", // no other values are currently accepted
"relationCondition": {
// one conditional expression model
},
"discriminator": "AccessPolicyParentRelationExpressionWebModel"
}
Child relation

This relational expression performs a single hop to any child items stored in the specified Link attribute of the current item.

Its RelationCondition property accepts one conditional expression, which is evaluated against the child items. The relational expression is fulfilled if any parent items fulfil the condition (logical OR).

{
"attributeCode": "attributes_myExampleDesignLinkAttribute_63a30437742b9503a172395d",
"condition": "All", // no other values are currently accepted
"relationCondition": {
// one conditional expression model
},
"discriminator": "AccessPolicyChildRelationExpressionWebModel"
}
HasAccess relation

Link attribute contents

This relational expression is fulfilled if the current user has read access to any of the items stored in the specified Link attribute on the current item.

Caution

To ensure safe performance and reliability, the Link attribute must never contain more than 100 item IDs.

{
"attributeCode": "attributes_myExampleDesignLinkAttribute_6527107c464545d591710338",
"discriminator": "AccessPolicyHasAccessExpressionWebModel"
}

String attribute reference

Alternatively, this relational expression is fulfilled if the current user has read access to the object (basemap, card, design, interface, layer or workflow) referenced by the specified string attribute on the current item. For the best user experience, ensure the attribute is tagged with the FeatureCode tag.

In the following example, if a user has access to the layers_myBollardsLayer_63593b8a5d6f2603953cb9f7 layer, they will also have access to items of the Bollards design with a Layer Code attribute value matching that string.

{
"attributeCode": "attributes_bollardsLayerCode_63592f1344596f0392ffc966",
"discriminator": "AccessPolicyHasAccessExpressionWebModel"
}

Conditional expressions

Conditional expressions let you compare values against an attribute/property of the current item (or its related parent/child items if used within a relational expression).

String condition

This conditional expression compares one or more supplied strings against an attribute/property of the item. At least one match is required for the condition to be met (logical OR).

{
"valueString": ["Green", "Purple", "Blue"],
"condition": "Equals", // no other values are currently accepted
"itemValue": {
"attributeCode": "attributes_myExampleDesignStringAttribute_643e8b79f68507036f9b1533",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"discriminator": "AccessPolicyStringConditionExpressionWebModel"
}
Link condition

This conditional expression compares one or more supplied item IDs against the contents of a Link attribute on the item, or the item's own ID property (shown below). At least one match is required for the condition to be met (logical OR).

{
"valueLink": ["643e9f7df68507036fa169cc", "643e9ec2f68507036fa0ff6a"], // one or more item IDs
"condition": "Intersects", // no other values are currently accepted
"itemValue": {
"property": "itemID",
"discriminator": "AccessPolicyItemValuePropertyWebModel"
},
"discriminator": "AccessPolicyLinkConditionExpressionWebModel"
}
Geometry condition

This conditional expression compares a Geometry attribute on the item against the supplied geometry value.

Its condition property accepts one of two values:

  • Intersects - does the attribute's geometry overlap the supplied geometry?

  • Within - does the attribute's geometry fall completely within the supplied geometry?

{
"itemValue": {
"attributeCode": "attributes_itemsGeometry",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"condition": "Within", // one of the two described above
"valueGeometry": {
"type": "Point",
"coordinates": [-1.516923, 52.288392]
},
"discriminator": "AccessPolicyGeometryConditionExpressionWebModel"
}
Boolean condition

This conditional expression compares a boolean attribute on the item against the supplied boolean value.

{
"itemValue": {
"attributeCode": "attributes_myBooleanAttribute_65e89f72e16307df9c69a065",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"valueBoolean": "true", // or "false"
"condition": "Equals", // no other values are currently accepted
"discriminator": "AccessPolicyBooleanConditionExpressionWebModel"
}
User condition

This conditional expression checks the contents of a Link attribute on the item, which stores items of the Users design. It compares any stored item IDs against the item ID of the Users item that represents the current user.

In other words, is the current user referenced by the specified Link attribute on the item?

Its condition property accepts one of two values:

  • Equals - is the current user stored in the Link attribute?

  • NotEquals - is the current user absent from the Link attribute?

{
"itemValue": {
"attributeCode": "attributes_myUsersLinkAttribute_65e8a88ee16307df9c6cb18b",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"userItemValue": {
"property": "ItemId",
"discriminator": "AccessPolicyItemValuePropertyWebModel"
},
"condition": "Equals",
"discriminator": "AccessPolicyUserConditionExpressionWebModel"
}
User group condition

This conditional expression checks if the current user belongs to the group referenced by the specified string attribute on the current item.

It provides a way to perform a tiered user group check: does the current user belong to the access policy's group AND the group referenced by the item?

In the following example, if a user belongs to the userGroups_myLovelyGroup group, they will also have access to items of the Trees design with a User Group Code attribute value matching that string.

{
"itemValue": {
"attributeCode": "attributes_treesUserGroupCode",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"condition": "Equals", // no other values are currently accepted
"discriminator": "AccessPolicyExpressionUserGroup"
}

Enable an access policy

We recommend setting an access policy's enabled property to false while it's being configured. When it's ready to use, you can edit the access policy accordingly.

PUT /api/accessPolicy/{code}
{
"name": "MyExampleAP",
"enabled": true,
"signature": "64d92cad1669d55s91815269" // to get the current signature, use GET /api/accessPolicy/{code}
}

Item logs

To maintain security, access policies also affect item logs. When a user views an item's details, the audit log won't show events involving items they don't have access to.

For example, imagine an item with a Link attribute. It stores some items that you don't have access to. You won't see them when you examine the Link attribute. You also won't see them in the corresponding create/edit event in the audit log!

Full examples

Here are some full examples for reference and inspiration! 🧐

Example 1 - Link attribute check (Logical AND)

Imagine adding this rule to an access policy for the Jobs interface. It will affect all items of designs that implement the Jobs interface (unless those designs have permissions or other access policies set).

The rule allows read access to items whose Priority attribute is High/Critical and the Team attribute is Street Cleaning Team.

POST /api/accessPolicy/{code}/rule
{
"userGroups": ["userGroups_StreetCleaners"],
"expression": {
"conditions": [
{
"valueLink": ["643e9f7df68507036fa169cc", "643e9ec2f68507036fa0ff6a"], // items of the Task Priorities design
"condition": "Intersects",
"itemValue": {
"attributeCode": "attributes_tasksPriority", // inherited from the Tasks interface
"discriminator": "AccessPolicyItemValuePropertyWebModel"
},
"discriminator": "AccessPolicyLinkConditionExpressionWebModel"
},
{
"valueLink": ["5e8b237cca31500c941bd16e"], // an item of the Teams design
"condition": "Intersects",
"itemValue": {
"attributeCode": "attributes_tasksTeam", // inherited from the Tasks interface
"discriminator": "AccessPolicyItemValuePropertyWebModel"
},
"discriminator": "AccessPolicyLinkConditionExpressionWebModel"
}
],
"discriminator": "AccessPolicyAndExpressionWebModel"
},
"signature": "62c3105bfab20501542e7134" // to get the current signature, use GET /api/accessPolicy/{code}
}
Example 2 - Geometry attribute check (Logical OR)

Imagine adding this rule to an access policy for a Benches design.

The rule allows read access to items whose Geometry attribute intersects a specific area, or whose Zone Tag attribute equals BUVCYKZY, or both.

POST /api/accessPolicy/{code}/rule
{
"userGroups": ["userGroups_BenchViewers"],
"expression": {
"conditions": [
{
"itemValue": {
"attributeCode": "attributes_itemsGeometry", // inherited from the Items interface
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"condition": "Intersects",
"valueGeometry": {
"type": "Polygon",
"coordinates": [
[
[-0.710355, 52.634739],
[-0.600632, 52.634739],
[-0.600632, 52.677035],
[-0.710355, 52.677035],
[-0.710355, 52.634739]
]
]
},
"discriminator": "AccessPolicyGeometryConditionExpressionWebModel"
},
{
"valueString": ["BUVCYKZY"],
"condition": "Equals",
"itemValue": {
"attributeCode": "attributes_BenchesZoneTag_643e8b79f68507036f9b1533",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
}
}
],
"discriminator": "AccessPolicyOrExpressionWebModel"
},
"signature": "6315c78cb7a8fc016dc79eec" // to get the current signature, use GET /api/accessPolicy/{code}
}
Example 3 - String attribute check (Parent relation)

Imagine adding this rule to an access policy for a Playground Defects design.

The rule allows read access to items with a parent asset, whose Owner attribute equals Causeway Technologies. The parent relation happens via the Defects Link attribute on the parent item (which is inherited from the Defects Assignable interface).

POST /api/accessPolicy/{code}/rule
{
"userGroups": ["userGroups_PlaygroundDefectViewers"],
"expression": {
"attributeCode": "attributes_defectsAssignableDefects",
"condition": "All",
"relationCondition": {
"valueString": ["Causeway Technologies"],
"condition": "Equals",
"itemValue": {
"attributeCode": "attributes_playgroundsOwner_6336ef3fe6c5cf0394bd0f25",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
}
"discriminator": "AccessPolicyStringConditionExpressionWebModel"
},
"discriminator": "AccessPolicyParentRelationExpressionWebModel"
},
"signature": "6321e19d1890d60158d30e01" // to get the current signature, use GET /api/accessPolicy/{code}
}
Example 4 - User group check (Child relation)

Imagine adding this rule to an access policy for a Car Parks design.

The rule allows read access to specific child items stored in the Tasks Link attribute of the current item, where the current user belongs to the group referenced by the User Group Code attribute on each task.

To have access, a user must belong to the access policy's user group AND the group referenced on each child item!

In this imaginary scenario, car park tasks are performed by internal workers and third party contractors. Therefore, when users view a Car Parks item, this rule ensures they only see the linked task items meant for their group.

{
"userGroups": ["userGroups_CarParkViewers"],
"expression": {
"attributeCode": "attributes_tasksAssignableTasks", // inherited from the Tasks Assignable interface
"condition": "All",
"relationCondition": {
"itemValue": {
"attributeCode": "attributes_carParkTasksUserGroupCode",
"discriminator": "AccessPolicyItemValueAttributeWebModel"
},
"condition": "Equals",
"discriminator": "AccessPolicyExpressionUserGroup"
},
"discriminator": "AccessPolicyChildRelationExpressionWebModel"
},
"signature": "653f80d90b04ec8fb2cbc754" // to get the current signature, use GET /api/accessPolicy/{code}
}