-
Notifications
You must be signed in to change notification settings - Fork 82
ABAC #2728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
HannesSandberg
wants to merge
17
commits into
neo4j:dev
Choose a base branch
from
HannesSandberg:abac
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
ABAC #2728
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
b1fe178
abac page
HannesSandberg 5c104ed
fix code block
HannesSandberg 45552f7
add link
HannesSandberg ccf0801
added that SHOW commands and alter commands are not supported yet.
HannesSandberg aabfe55
updates to grant/revoke section in the ABAC page
HannesSandberg d1eb4e5
fix heading
HannesSandberg 9b9fdc2
Update modules/ROOT/pages/authentication-authorization/attribute-base…
phil198 0e8a650
add a temporal example
phil198 e3df800
Play-day review suggestions
phil198 136d8d6
Play-day review suggestions
phil198 d5aa9b9
Apply suggestions
HannesSandberg f1d1e5b
Play-day review suggestions
phil198 18b748c
Play-day review suggestions contd
phil198 e47b1d7
review fixes
HannesSandberg cba96c3
Re-add and fix stuff after the rebase
HannesSandberg ea9f03e
review fixes
HannesSandberg 2cada46
review fix
HannesSandberg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
203 changes: 203 additions & 0 deletions
203
...les/ROOT/pages/authentication-authorization/attribute-based-access-control.adoc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| :description: How to use Cypher to manage attribute-based access control on a graph. | ||
|
|
||
| //// | ||
| [source, cypher, role=test-setup] | ||
| ---- | ||
| CREATE ROLE salesTeam; | ||
| CREATE ROLE engineeringTeamUK; | ||
| CREATE ROLE countryAccessRole; | ||
| ---- | ||
| //// | ||
|
|
||
| :page-role: enterprise-edition aura-db-business-critical aura-db-dedicated | ||
|
|
||
| [[attribute-based-access-control]] | ||
| = Attribute-based access control | ||
|
|
||
| Attribute-based access control (ABAC) grants roles based on the evaluation of attributes (or claims) contained in a user's authentication token. | ||
|
|
||
| == Setup | ||
|
|
||
| Use the following steps to set up attribute-based access control: | ||
|
|
||
| 1. Enable attribute-based access control in the `neo4j.conf` file by setting the `internal.dbms.feature_flag.attribute_based_access_control` setting to `true`. | ||
| 2. Specify which OIDC provider(s) will be used for attribute-based access control by setting the `internal.dbms.security.abac_enabled_authorization_providers` setting to the appropriate providers. | ||
| 3. Define the authorization rules that will be used to grant roles based on user attributes by using the Cypher command `CREATE AUTH RULE`, explained below. | ||
| 4. Specify which roles will be assigned when the authorization rules are fulfilled using the `GRANT ROLE` command, explained below. | ||
|
|
||
| == Create auth rules | ||
| To create an authorization rule, use the following syntax: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| CREATE AUTH RULE ruleName [IF NOT EXISTS] | ||
| SET CONDITION conditionExpression | ||
| [ SET ENABLED {true | false} ] | ||
| ---- | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| To be able to create auth rules, the user must have the `AUTH RULE MANAGEMENT` privilege, | ||
| see xref:authentication-authorization/dbms-administration/dbms-auth-rule-management-privileges.adoc[DBMS AUTH RULE MANAGEMENT privileges]. | ||
| ==== | ||
|
|
||
| The SET ENABLED clause is optional and can be used to enable or disable the rule upon creation. By default, the rule is enabled. | ||
|
|
||
| If specifying `IF NOT EXISTS`, no error is raised if a rule with the same name already exists and the command has no effect. | ||
|
|
||
| The conditionExpression is a boolean cypher expression that evaluates user attributes (claims) contained in the authentication token. | ||
| To access an attribute, use the syntax `abac.oidc.user_attribute('<claim_key>')`. | ||
|
|
||
| The conditionExpression can use any valid Cypher expression that evaluates to a boolean value, including logical operators (AND, OR, NOT etc), comparison operators (=, <>, <, >, <=, >=) and functions (e.g. `IN`, `ANY`, `ALL`, etc). | ||
| The expression can also use the following in-build Neo4j functions: | ||
|
|
||
| [cols="1,3",options="header"] | ||
| |=== | ||
| | Function group | Functions | ||
Hunterness marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| | List functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-range[range()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-reduce[reduce()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-reverse[reverse()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-tail[tail()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-tobooleanlist[toBooleanList()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-tofloatlist[toFloatList()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-tointegerlist[toIntegerList()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/list/#functions-tostringlist[toStringList()] | ||
|
|
||
| | Numeric functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/mathematical-numeric/#functions-abs[abs()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/mathematical-numeric/#functions-ceil[ceil()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/mathematical-numeric/#functions-floor[floor()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/mathematical-numeric/#functions-isnan[isNaN()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/mathematical-numeric/#functions-round[round()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/mathematical-numeric/#functions-sign[sign()] | ||
|
|
||
| | Predicate functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/predicate/#functions-all[all()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/predicate/#functions-any[any()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/predicate/#functions-isempty[isEmpty()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/predicate/#functions-none[none()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/predicate/#functions-single[single()] | ||
|
|
||
| | Scalar functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-char_length[char_length()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-character_length[character_length()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-coalesce[coalesce()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-head[head()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-last[last()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-nullIf[nullIf()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-size[size()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-toboolean[toBoolean()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-tobooleanornull[toBooleanOrNull()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-tofloat[toFloat()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-tofloatornull[toFloatOrNull()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-tointeger[toInteger()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/scalar/#functions-tointegerornull[toIntegerOrNull()] | ||
|
|
||
| | String Functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-btrim[btrim()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-left[left()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-lower[lower()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-ltrim[ltrim()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-replace[replace()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-reverse[reverse()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-right[right()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-rtrim[rtrim()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-split[split()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-substring[substring()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-tolower[toLower()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-tostring[toString()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-tostringornull[toStringOrNull()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-toupper[toUpper()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-trim[trim()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/string/#functions-upper[upper()] | ||
|
|
||
| | Temporal duration functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/duration/#functions-durations[duration()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/duration/#functions-duration-between[duration.between()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/duration/#functions-duration-indays[duration.inDays()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/duration/#functions-duration-inmonths[duration.inMonths()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/duration/#functions-duration-inseconds[duration.inSeconds()] | ||
|
|
||
| | Temporal instant types functions | ||
| | link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-date[date([ input, pattern \])], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-date-transaction[date.transaction()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-date-truncate[date.truncate()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-datetime[datetime([ input, pattern \])], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-datetime-transaction[datetime.transaction()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-datetime-truncate[datetime.truncate()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-localdatetime[localdatetime([ input, pattern \])], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-localdatetime-transaction[localdatetime.transaction()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-localdatetime-truncate[localdatetime.truncate()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-localtime[localtime([ input, pattern \])], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-localtime-transaction[localtime.transaction()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-localtime-truncate[localtime.truncate()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-time[time([ input, pattern \])], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-time-transaction[time.transaction()], link:{neo4j-docs-base-uri}/cypher-manual/current/functions/temporal/#functions-time-truncate[time.truncate()] | ||
|
|
||
| |=== | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| The functions, `date`, `datetime`, `localdatetime`, `localtime` and `time` are only supported when an input argument is used. | ||
| ==== | ||
|
|
||
|
|
||
| == Drop auth rules | ||
| To drop an existing authorization rule, use the following syntax: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| DROP AUTH RULE ruleName [IF EXISTS] | ||
| ---- | ||
|
|
||
| If specifying `IF EXISTS`, no error is raised if the rule does not exist and the command has no effect. | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| To be able to drop auth rules, the user must have the `AUTH RULE MANAGEMENT` privilege, | ||
| see xref:authentication-authorization/dbms-administration/dbms-auth-rule-management-privileges.adoc[DBMS AUTH RULE MANAGEMENT privileges]. | ||
| ==== | ||
|
|
||
| [[assign-roles-auth-rules]] | ||
| == Assign roles to auth rules | ||
| To specify which roles will be granted to the user when the authorization rule is fulfilled, use the `GRANT ROLE` command with the following syntax: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| GRANT ROLE[S] role[, ...] TO AUTH RULE[S] ruleName[, ...] | ||
| ---- | ||
|
|
||
| For information about the `GRANT ROLE` command, see xref:authentication-authorization/manage-roles.adoc#access-control-assign-roles[Assigning roles to users]. | ||
Hunterness marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| [NOTE] | ||
| ==== | ||
| No roles with associated deny privileges can be assigned to an auth rule. Also, deny privileges may not be subsequently assigned to a role once that role has been assigned to an auth rule. This is to ensure that if a role is unexpectedly not fulfilled (e.g. because a claim is missing from the users auth token) then there can never be an escalation of privileges, only ever a reduction. | ||
| ==== | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| To be able to grant roles, the user must have the xref:authentication-authorization/dbms-administration/dbms-role-management-privileges.adoc#access-control-dbms-administration-role-assignment[`ASSIGN ROLE`] privilege. | ||
| ==== | ||
|
|
||
phil198 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| [NOTE] | ||
| ==== | ||
| OR semantics are used between roles granted via ABAC and those granted by RBAC mechanisms. For example, given an ABAC rule which grants the `admin` role between the hours of 1900 and 2000, then a user who receives the `admin` role because it appears in their JWT `groups` claim (RBAC) will always have the `admin` role, even outside the hours of 1900 and 2000. | ||
| ==== | ||
|
|
||
| [[revoke-roles-auth-rules]] | ||
| == Revoke roles from auth rules | ||
| To revoke roles from an authorization rule, use the `REVOKE ROLE` command with the following syntax: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| REVOKE ROLE[S] role[, ...] FROM AUTH RULE[S] ruleName[, ...] | ||
| ---- | ||
|
|
||
| For information about the `REVOKE ROLE` command, see xref:authentication-authorization/manage-roles.adoc#access-control-revoke-roles[Revoking roles from users]. | ||
|
|
||
| [NOTE] | ||
| ==== | ||
| To be able to revoke roles, the user must have the xref:authentication-authorization/dbms-administration/dbms-role-management-privileges.adoc#access-control-dbms-administration-role-removal[`REMOVE ROLE`] privilege. | ||
| ==== | ||
|
|
||
| == Examples | ||
Hunterness marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| An auth rule specifying that users with the attribute `department` equal to `sales` should be granted the `salesTeam` role can be created as follows: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| CREATE AUTH RULE salesRule | ||
| SET CONDITION abac.oidc.user_attribute('department') = 'sales'; | ||
| GRANT ROLE salesTeam TO AUTH RULE salesRule; | ||
| ---- | ||
|
|
||
| Granting the role `engineeringTeamUK` to users with the attribute `department` equal to `engineering` and `location` equal to `UK` can be done as follows: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| CREATE AUTH RULE engineeringUKRule | ||
| SET CONDITION abac.oidc.user_attribute('department') = 'engineering' | ||
| AND abac.oidc.user_attribute('location') = 'UK'; | ||
| GRANT ROLE engineeringTeamUK TO AUTH RULE engineeringUKRule; | ||
| ---- | ||
|
|
||
| Granting a role based on the presence of the allowed countries in a list of citizenship countries in the claims can be done as follows: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| CREATE AUTH RULE ruleset_countries SET CONDITION | ||
| any(country IN abac.oidc.user_attribute('citizenshipCountries') | ||
| WHERE country IN ['c1', 'c5']); | ||
| GRANT ROLE countryAccessRole TO AUTH RULE ruleset_countries; | ||
| ---- | ||
|
|
||
| Temporarily granting a role based on the value of a claim and the time being between 1900 and 2000 can be done as follows: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| CREATE AUTH RULE temporary_reader | ||
| SET CONDITION abac.oidc.user_attribute('jobTitle') = 'cover' | ||
| AND datetime.transaction().hour >= 19 AND datetime.transaction().hour < 20; | ||
| GRANT ROLE reader TO AUTH RULE temporary_reader; | ||
| ---- | ||
|
|
||
| Revoking the `reader` role from auth rule `temporary_reader` and drop the auth rule can be done as follows: | ||
|
|
||
| [source, cypher25, role="noheader"] | ||
| ---- | ||
| REVOKE ROLE reader FROM AUTH RULE temporary_reader; | ||
| DROP AUTH RULE temporary_reader; | ||
| ---- | ||
|
|
||
| == Caveats and limitations | ||
|
|
||
| * When evaluating `abac.oidc.user_attribute('<claim_key>')`, if the claim does not exist in the authentication token, it will evaluate to `NULL`. | ||
| * Newly created auth rules are applied to existing user sessions, but will only have access to the user claims which had rules containing them at the start of the session. | ||
| Only user claims which are used in pre-existing auth rules at the start of a session are retained. | ||
| Users must re-authenticate to have new rules applied if the new rules use new claims. | ||
| * Attribute-based access control is only supported for OIDC authentication providers. | ||
| * For troubleshooting ABAC evaluation, enable debug logging for the security log and debug log, and turn on JWT claims logging at debug level in `neo4j.conf`: `dbms.security.logs.oidc.jwt_claims_at_debug_level_enabled=true` | ||
| * Show commands for listing AUTH RULES are not supported yet. | ||
| * Altering existing auth rules is not supported yet. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.