Property-based access control

It is possible to create read privileges that are based on properties of nodes. Each property-based privilege can only be restricted by a single property. To specify the property/value conditions of the read privilege the pattern syntax described below is used, for more information about read privilege syntax see read privilege page.

Adding property-based access control may lead to a significant performance overhead in certain scenarios. See Limitations for more detailed information. To reduce the performance impact, it is recommended to use the Block Storage format as it is better optimized for the kind of read required for the resolution of property-based privileges.

Some of the factors that can worsen the impact on performance when having property rules are:

  • The number of properties on the nodes concerned (more properties = greater performance impact)

  • The number of property-based privileges (more property-based privileges = greater performance impact).

  • The type of the privilege: TRAVERSE property-based privileges have a greater performance impact than READ property-based privileges.

  • The type of storage medium in operation. The performance impact of property-based privileges will be considerably amplified by accessing disc storage.

For performance-critical scenarios, it is recommended to design privileges based on labels. For more information, see Read privileges.

When using property-based access control, ensure the property used for the rule cannot be modified. Users who can change this property can affect the granted property-based privileges.

Pattern syntax:

([var][:label["|" ...]] "{" property: value "}")
| (var[:label["|" ...]]) WHERE [NOT] var.property { { = | <> | > | >= | < | <= } value | IS NULL | IS NOT NULL | IN { "["[value[, ...]]"]" | listParam } }
| (var[:label["|" ...]] WHERE [NOT] var.property { { = | <> | > | >= | < | <= } value | IS NULL | IS NOT NULL | IN { "["[value[, ...]]"]" | listParam } } )

For more details about the syntax descriptions, see Cypher syntax for administration commands.

The role does not need to have READ privilege for the property used by the property-based privilege.

You can use this pattern syntax for defining read privileges as follows:

GRANT ... ON GRAPH ... FOR pattern TO ...
Granting permission to READ the address property on Email or Website nodes with domain exampledomain.com to role regularUsers:
GRANT READ { address } ON GRAPH * FOR (n:Email|Website) WHERE n.domain = 'exampledomain.com' TO regularUsers

Alternatively, you can use the following syntax:

GRANT READ { address } ON GRAPH * FOR (:Email|Website {domain: 'exampledomain.com'}) TO regularUsers
Granting permission to TRAVERSE nodes with label Email where property classification is NULL to role regularUsers:
GRANT TRAVERSE ON GRAPH * FOR (n:Email) WHERE n.classification IS NULL TO regularUsers
Denying permission to READ and TRAVERSE nodes where the property classification is different from UNCLASSIFIED to role regularUsers:
DENY MATCH {*} ON GRAPH * FOR (n) WHERE n.classification <> 'UNCLASSIFIED' TO regularUsers
Granting permission to READ all properties on nodes where the property securityLevel is higher than 3 to role regularUsers:
GRANT READ {*} ON GRAPH * FOR (n) WHERE n.securityLevel > 3 TO regularUsers

The role regularUsers does not need to have READ privilege for the property securityLevel used by the property-based privilege.

Denying permission to READ all properties on nodes where the property classification is not included in the list of [UNCLASSIFIED, PUBLIC]
DENY READ {*} ON GRAPH * FOR (n) WHERE NOT n.classification IN ['UNCLASSIFIED', 'PUBLIC'] TO regularUsers
Granting permission to READ all properties on nodes where the property createdAt is later than the current date to role regularUsers:
GRANT READ {*} ON GRAPH * FOR (n) WHERE n.createdAt > date() TO regularUsers

The date() function is evaluated, and the value used to evaluate the privilege is the date when the property-based privilege is created. Keep this in mind when designing your property rules, and use the SHOW PRIVILEGES AS COMMANDS command to check the stored value. This is essential when revoking property-based privileges containing evaluated function values like date().

Show the privilege created by the command in the previous example as a revoke command:
SHOW ROLE regularUsers PRIVILEGES AS REVOKE COMMANDS
Table 1. Result
command

REVOKE GRANT READ {*} ON GRAPH * FOR (n) WHERE n.createdAt  date('2024-10-25') FROM `regularUsers`

Rows: 1