基于特性的访问控制

基于属性的访问控制 (ABAC) 根据用户身份验证令牌中包含的属性(或声明)的评估结果来授予角色。

设置

要设置基于属性的访问控制,请遵循以下步骤:

  1. neo4j.conf 文件中,将 dbms.security.abac.authorization_providers 设置为您希望用于 ABAC 的 OIDC 提供商。

  2. 使用 CREATE AUTH RULE 命令定义授权规则,以便根据用户属性授予角色。详细信息请参阅 创建授权规则

  3. 使用 GRANT ROLE 命令指定在满足授权规则时要分配的角色。详细信息请参阅 将角色分配给授权规则

创建授权规则

要创建授权规则,请使用 CREATE AUTH RULE 命令。

CREATE AUTH RULE 命令需要 CREATE AUTH RULE 权限。有关如何授予此权限的详细信息,请参阅 授予创建授权规则的权限

CREATE AUTH RULE 语法
CREATE [OR REPLACE] AUTH RULE ruleName (1)
    [IF NOT EXISTS] (2)
    SET CONDITION conditionExpression (3)
    [ SET ENABLED {true | false} ] (4)

说明:

1 在命令中添加 OR REPLACE 将删除任何具有相同名称的现有授权规则,并创建一个同名的新规则。与旧授权规则关联的任何已分配角色将不会关联到新规则。
2 在命令后附加 IF NOT EXISTS 可确保如果已存在同名规则,则不会返回错误,也不会有任何更改,且该命令无效。OR REPLACEIF NOT EXISTS 不能同时使用。
3 SET CONDITION 子句允许您指定用户必须满足的条件,才能被授予与该授权规则关联的角色。conditionExpression 是一个布尔型 Cypher 表达式,用于评估身份验证令牌中包含的用户属性(声明)。要访问某个属性,请使用语法 abac.oidc.user_attribute('<claim_key>')

conditionExpression 可以使用任何计算结果为布尔值的有效 Cypher 表达式,包括逻辑运算符 (AND, OR, NOT 等)、比较运算符 (=, <>, <, >, <=>=) 以及以下内置函数:

表 1. Neo4j 用于授权规则条件的内置函数
函数组 函数

列表函数

range(), reduce(), reverse(), tail(), toBooleanList(), toFloatList(), toIntegerList(), toStringList()

数值函数

abs(), ceil(), floor(), isNaN(), round(), sign()

谓词函数

all(), any(), isEmpty(), none(), single()

标量函数

char_length(), character_length(), coalesce(), head(), last(), nullIf(), size(), toBoolean(), toBooleanOrNull(), toFloat(), toFloatOrNull(), toInteger(), toIntegerOrNull()

字符串函数

btrim(), left(), lower(), ltrim(), replace(), reverse(), right(), rtrim(), split(), substring(), toLower(), toString(), toStringOrNull(), toUpper(), trim(), upper()

时间间隔函数

duration(), duration.between(), duration.inDays(), duration.inMonths(), duration.inSeconds()

时间瞬时类型函数

date([ input, pattern ]), date.transaction(), date.truncate(), datetime([ input, pattern ]), datetime.transaction(), datetime.truncate(), localdatetime([ input, pattern ]), localdatetime.transaction(), localdatetime.truncate(), localtime([ input, pattern ]), localtime.transaction(), localtime.truncate(), time([ input, pattern ]), time.transaction(), time.truncate()

函数 date, datetime, localdatetime, localtimetime 仅在使用输入参数时才受支持。

4 (可选) SET ENABLED 子句允许您在创建时启用或禁用该规则。默认情况下,规则是启用的。

示例 1:创建带有简单条件的授权规则

以下示例创建了一条授权规则,将关联的角色授予 department 属性等于 sales 的用户:

CREATE AUTH RULE salesRule
    SET CONDITION abac.oidc.user_attribute('department') = 'sales';

示例 2:创建带有多个条件的授权规则

以下示例创建了一条授权规则,将关联的角色授予 department 属性等于 engineeringlocation 属性等于 UK 的用户:

CREATE AUTH RULE engineeringUKRule
    SET CONDITION abac.oidc.user_attribute('department') = 'engineering'
        AND abac.oidc.user_attribute('location') = 'UK';

示例 3:基于值列表创建授权规则

以下示例创建了一条授权规则,将关联的角色授予 citizenshipCountries 属性包含允许的国家/地区 c1c5 中任何一个的用户:

CREATE AUTH RULE ruleset_countries SET CONDITION
  any(country IN abac.oidc.user_attribute('citizenshipCountries')
    WHERE country IN ['c1', 'c5']);

示例 4:创建带有时间条件的授权规则

以下示例创建了一条授权规则,在 19:00 到 20:00 之间,临时将分配的角色授予 jobTitle 属性等于 developer 的用户:

CREATE AUTH RULE temporary_reader
    SET CONDITION abac.oidc.user_attribute('jobTitle') = 'developer'
        AND datetime.transaction().hour >= 19 AND datetime.transaction().hour < 20;

将角色分配给授权规则

要指定在满足授权规则时向用户授予哪些角色,请使用 GRANT ROLE 命令。

GRANT ROLE 命令需要 ASSIGN ROLE 权限。有关如何授予此权限的详细信息,请参阅 授予分配角色的权限

GRANT ROLE 语法
GRANT ROLE[S] role[, ...] TO AUTH RULE[S] ruleName[, ...]

有关 GRANT ROLE 命令的信息,请参阅 将角色分配给用户

以下示例将角色分配给 创建授权规则 中示例里的授权规则:

GRANT ROLE salesTeam TO AUTH RULE salesRule;
GRANT ROLE engineeringTeamUK TO AUTH RULE engineeringUKRule;
GRANT ROLE countryAccessRole TO AUTH RULE ruleset_countries;
GRANT ROLE reader TO AUTH RULE temporary_reader;

任何具有关联拒绝权限的角色都不能分配给授权规则。

此外,一旦某个角色已被分配给授权规则,随后便不能再向该角色赋予被拒绝的权限。这确保了如果某个规则意外未被满足(例如,由于用户的身份验证令牌中缺少某个声明),则永远不会发生权限提升,只会发生权限缩减。

ABAC 规则不会限制 RBAC 角色。用户既会获得其 RBAC 角色,也会获得已满足的 ABAC 规则所授予的角色。如果用户通过 ABAC 和 RBAC 同时获得了某个角色,则无论 ABAC 规则当前是否满足,用户都将拥有该角色。例如,如果用户因为出现在其 JWT groups 声明中而获得了 admin 角色(RBAC),且同时存在一条在 19:00 到 20:00 之间授予 admin 角色的 ABAC 规则,则用户将始终拥有 admin 角色(即使在 19:00 到 20:00 之外),这是因为有 RBAC 分配。

从授权规则中撤销角色

要从授权规则中撤销角色,请使用 REVOKE ROLE 命令。

REVOKE ROLE 命令需要 REMOVE ROLE 权限。有关如何授予此权限的详细信息,请参阅 授予删除角色的权限

REVOKE ROLE 语法
REVOKE ROLE[S] role[, ...] FROM AUTH RULE[S] ruleName[, ...]

有关 REVOKE ROLE 命令的信息,请参阅 从用户处撤销角色

以下示例从授权规则 temporary_reader 中撤销了 reader 角色:

REVOKE ROLE reader FROM AUTH RULE temporary_reader;

列出授权规则

您可以使用 Cypher 命令 SHOW AUTH RULES 列出所有授权规则。

SHOW AUTH RULES 命令需要 SHOW AUTH RULE 权限。有关如何授予此权限的详细信息,请参阅 授予列出授权规则的权限

SHOW AUTH RULES 返回一个表格,每条授权规则占一行,包含以下列:

表 2. SHOW AUTH RULES 输出
描述 类型

名称 (name)

CREATERENAME AUTH RULE 命令中所定义的授权规则名称。

STRING

condition

在确定是否向用户授予角色时进行评估的 Cypher 表达式。

STRING

enabled

授权规则是否启用。当规则启用时,此列值为 true,否则为 false。当授权规则被禁用时,它不会被评估,因此用户无法获得其角色。

布尔值 (BOOLEAN)

角色

通过一个或多个 GRANT ROLE … TO AUTH RULE … 命令授予授权规则的角色。如果执行用户缺失或被拒绝 SHOW ROLES 权限,此列将返回 null

字符串列表 (LIST OF STRING)

要将授权规则作为命令查看,请使用 SHOW AUTH RULES AS COMMANDS,默认返回单列。您可以选择附加 YIELD * 以额外查看授予该授权规则的角色。

表 3. SHOW AUTH RULES AS COMMANDS 输出
描述 类型

command(命令)

用于创建授权规则的 CREATE AUTH RULE 命令。

STRING

角色

通过一个或多个 GRANT ROLE … TO AUTH RULE … 命令授予授权规则的角色。如果执行用户缺失或被拒绝 SHOW ROLES 权限,此列将返回 null

字符串列表 (LIST OF STRING)

示例 1:列出授权规则

以下示例列出了所有授权规则及其条件、启用状态和已分配的角色:

SHOW AUTH RULES;
表 4. 结果
名称 (name) condition enabled 角色

"salesRule"

"abac.oidc.user_attribute('department') = 'sales'"

true

["salesTeam"]

"engineeringUKRule"

"abac.oidc.user_attribute('department') = 'engineering' AND abac.oidc.user_attribute('location') = 'UK'"

true

["engineeringTeamUK"]

"ruleset_countries"

"any(country IN abac.oidc.user_attribute('citizenshipCountries') WHERE country IN ['c1', 'c5'])"

true

["countryAccessRole"]

行:3

示例 2:带过滤和排序功能的列出授权规则

要过滤和排序返回的结果,您可以使用 YIELDORDER BYWHERE

SHOW AUTH RULES YIELD name, roles
ORDER BY name
WHERE name ENDS WITH 'e';

结果为一个授权规则表,其名称以 'e' 结尾,以及它们已分配的角色,并按 name 排序。

表 5. 结果
名称 (name) 角色

"engineeringUKRule"

["engineeringTeamUK"]

"salesRule"

["salesTeam"]

行:2

也可以使用 SKIPLIMIT 对结果进行分页。

示例 3:以命令形式列出授权规则

以下示例以命令形式列出授权规则:

SHOW AUTH RULES AS COMMANDS;
表 6. 结果
command(命令)

CREATE AUTH RULE engineeringUKRule SET CONDITION abac.oidc.user_attribute('department') = 'engineering' AND abac.oidc.user_attribute('location') = 'UK' SET ENABLED true

CREATE AUTH RULE salesRule SET CONDITION abac.oidc.user_attribute('department') = 'sales' SET ENABLED true

CREATE AUTH RULE ruleset_countries SET CONDITION any(country IN abac.oidc.user_attribute('citizenshipCountries') WHERE country IN ['c1', 'c5']) SET ENABLED true

行:3

重命名授权规则

要重命名现有的授权规则,请使用 RENAME AUTH RULE 命令。

RENAME AUTH RULE 命令需要 RENAME AUTH RULE 权限。有关如何授予此权限的详细信息,请参阅 授予重命名授权规则的权限

RENAME AUTH RULE 语法
RENAME AUTH RULE ruleName [IF EXISTS] TO newRuleName

如果指定 IF EXISTS,则如果规则不存在,不会抛出错误,且该命令无效。

例如,使用以下命令将授权规则 ruleset_countries 重命名为 disabled_ruleset_countries

RENAME AUTH RULE ruleset_countries TO disabled_ruleset_countries;

修改授权规则

要修改现有的授权规则,请使用 ALTER AUTH RULE 命令。

ALTER AUTH RULE 命令需要 ALTER AUTH RULE 权限。有关如何授予此权限的详细信息,请参阅 授予修改授权规则的权限

ALTER AUTH RULE 语法
ALTER AUTH RULE ruleName [IF EXISTS]
    [SET CONDITION conditionExpression]
    [SET ENABLED {true | false}]

如果指定 IF EXISTS,则如果规则不存在,不会抛出错误,且该命令无效。必须至少指定 SET CONDITIONSET ENABLED 中的一项。

示例 1:修改授权规则的条件

以下示例修改授权规则 ruleset_countries,设置一个新条件,同时也允许国家/地区 'c6'

ALTER AUTH RULE ruleset_countries SET CONDITION any(country IN abac.oidc.user_attribute('citizenshipCountries')
WHERE country IN ['c1', 'c5', 'c6'])

示例 2:禁用授权规则

以下示例禁用了授权规则 ruleset_countries

ALTER AUTH RULE ruleset_countries SET ENABLED false

删除授权规则

要删除现有的授权规则,请使用 DROP AUTH RULE 命令。

DROP AUTH RULE 命令需要 DROP AUTH RULE 权限。有关如何授予此权限的详细信息,请参阅 授予删除授权规则的权限

DROP AUTH RULE 语法
DROP AUTH RULE ruleName [IF EXISTS]

如果指定 IF EXISTS,则如果规则不存在,不会抛出错误,且该命令无效。

例如,使用以下命令删除授权规则 temporary_reader

DROP AUTH RULE temporary_reader;

注意事项与局限性

ABAC 具有以下注意事项与局限性:

  • 在评估 abac.oidc.user_attribute('<claim_key>') 时,如果身份验证令牌中不存在该声明,则评估结果为 NULL

  • 新创建的授权规则会应用于现有用户会话,但只能访问在会话开始时有规则引用它们的用户声明。只有在会话开始时已存在于授权规则中的用户声明才会被保留。如果新规则使用新的声明,用户必须重新进行身份验证,以便应用新规则。

  • 基于属性的访问控制仅支持 OIDC 身份验证提供商。

  • 要排查 ABAC 评估问题,请为安全日志和调试日志启用调试记录,并在 neo4j.conf 文件中设置 dbms.security.logs.oidc.jwt_claims_at_debug_level_enabled=true 以开启调试级别的 JWT 声明日志记录。