Quad-based Access Control

Note

This feature requires a GraphDB Enterprise license.

What is quad-based access control?

By default, permissions in GraphDB are set at the repository level – access to a repository grants access to all its statements indiscriminately. However, in some cases a more robust access control system may be necessary.

Quad-based access control allows you to fine-tune access to specific RDF statements, so that only authorized users can read certain data. This mechanism provides a means to allow or deny access based on any part of an RDF statement, where the full representation of a statement consists of a quad: the subject, the predicate, the object, and the named graph, also known as context.

Common use-cases for quad-based access control are restricting access to a specific named graph (a collection of statements with sensitive data) or a specific predicate (a single statement with sensitive information, e.g. a salary).

In other words, with the help of quad-based access control, you can create rules that grant or deny access to specific statements in your repository, and apply those rules to specific groups of users.

Important

Quad-based access control is currently limited to controlling only read access. As such, if a user has write access to the repository, all quad-based access control rules will be bypassed and the user will be able to read every statement in the repository.

How it works

Access control list

Quad-based access control is specified by defining an Access Control List (ACL) consisting of a list of rules.

A rule definition consists of three elements:

  • The quad the rule applies to, where each position may be an RDF value or a wildcard

  • The role attribute the user must match

  • The permission policy of the rule (allow or deny)

The role attribute specifies role membership. It can be one of the following:

  • A role name: the user must have that role

  • ! followed by a role name: the user must not have that role, or in other words, ! negates the role membership

There are two permission policies:

  • Allow: the rule will allow access to the applicable quad

  • Deny: the rule will deny access to the applicable quad

When GraphDB needs to determine whether to grant access to an RDF statement, the rules are processed sequentially until either of the following occurs:

  • A rule applies to the statement and matches the role attribute – in that case, GraphDB will return the rule’s policy (either allow or deny access to the statement)

  • The end of the ACL is reached – in this case, the default policy is to allow access to the statement

Thus, the order of your ACL rules is of crucial importance.

Duplicate rules (where all elements of the rule definition are identical) are not permitted.

Custom roles

Custom roles are similar to the GraphDB system user roles. Unlike those, custom roles have no inherent rights or restrictions associated with them, and are instead just markers that can be freely granted to any number of users, and each user can be granted any number of custom roles. Thus, custom roles provide the facility for grouping users together for the sake of defining ACL rules.

Custom roles are identified by the prefix CUSTOM_ in their name. For example, CUSTOM_ROLE_ADMIN and CUSTOM_ADMIN are custom roles, while ROLE_ADMIN (one of the system roles) and ADMIN_ROLE (neither a system role, nor a custom one) are not custom roles.

The names of custom roles are not case sensitive – CUSTOM_ROLE_ADMIN, custom_role_admin and Custom_Role_ADMIN all refer to the same custom role – but they will be normalized to uppercase when returned by API calls and shown in the user interface.

Managing ACL rules

Remember that the order of ACL rules matters and duplicates are not allowed.

Managing ACL rules through Workbench

Creating ACL rules can be done easily through the Setup ‣ ACL Management view in Workbench. This opens the interface where the ACL rules are loaded and rendered in as a list.

_images/quad-based-acl-manage-acl-management-ui.png

This interface also allows you to create, edit, reorder and delete rules.

Warning

Any changes to the rules – be it adding, deleting, editing or reordering rules – are not preserved until you click on the Save ACL button on the bottom of the page

Add a new rule

  1. Click on the Add new rule plus-shaped button on the top right of the UI to create a new rule

  2. Enter the parameters you want to apply to your rules – the subject, predicate, object, context, the custom role the rule applies to (optionally prefixed with ! for negation), and the permission policy

  3. Click on the Save icon to save the new rule

_images/quad-based-acl-manage-acl-management-ui-add.png

Note

  • New rules are added to the top of the list – you can also add a rule immediately after an existing rule by clicking the Add new rule button next to the existing rule

  • You can leave any one of the subject, predicate, object or context as a wildcard placeholder * in order to match any value at that position

Edit an existing rule

  1. Click on the Edit rule pencil-shaped button next to the rule you want to edit

  2. Change the parameters you want to modify

  3. Click on the Save icon to save the changed rule

Reordering rules

Click the up and down arrow icons on the left of each rule to move the rule one position up or down respectively.

_images/quad-based-acl-manage-acl-management-ui-reorder.png

Deleting an existing rule

  1. Click on the Delete rule trash can button next to the rule you want to edit

  2. A pop up window will appear asking you to confirm the deletion

_images/quad-based-acl-manage-acl-management-ui-delete.png

ACL management REST API

ACL rules can also be managed through the ACL management API. The API represents rules according to this JSON model:

{
  "subject": "rdf-value",
  "predicate": "rdf-value",
  "object": "rdf-value",
  "context": "rdf-value",
  "role": "role-string",
  "policy": "allow|deny"
}

RDF values must be specified using Turtle-star syntax. Negated roles are specified by prefixing the role with !.

For example, the rule below will deny access to RDF statements whose predicate is the IRI <https://swapi.co/vocabulary/averageHeight> and whose object is the literal "180.0"^^<http://www.w3.org/2001/XMLSchema#decimal> to all users who do not have the CUSTOM_ROLE1 role:

{
  "subject": "*",
  "predicate": "<https://swapi.co/vocabulary/averageHeight>",
  "object": "\"180.0\"^^<http://www.w3.org/2001/XMLSchema#decimal>",
  "context": "*",
  "role": "!CUSTOM_ROLE1",
  "policy": "deny"
}

The API supports the following operations:

List ACL rules for a repository

List all ACL rules in the repository. You can use one or more optional request parameters to narrow down the search for specific rules that meet your criteria.

Returns a JSON array of ACL rule objects.

GET /rest/repositories/<repositoryID>/acl

Optional request parameters for filtering:

  • subject – The subject of the ACL rule in Turtle-star format (e.g., <http://example.com/Mary>)

  • predicate – The predicate of the ACL rule in Turtle-star format (e.g., <http://www.w3.org/2000/01/rdf-schema#label>)

  • object – The object of the ACL rule in Turtle-star format (e.g., "Mary"@en)

  • context – The context of the ACL rule in Turtle-star format (e.g., <http://example.org/graphs/graph1>)

  • role – The role associated with the ACL rule (e.g. CUSTOM_ROLE1 or !CUSTOM_ROLE1)

  • policy – The policy for the ACL rule (allow or deny)

All of these correspond to the individual fields of the ACL rule object and they must use the same string representation. When a parameter is not provided, the result will not be filtered by that parameter.

Note

If you construct your request manually, pay attention to the required URL-encoding of the request parameters.

Possible response type:

  • HTTP Status 200 (OK) – The request was successful, and the response will contain a list of ACL rules

  • HTTP Status 400 (Bad Request) – The request is invalid (i.e. invalid value in any of the filtering parameters)

Add ACL rules to a repository

Adds new ACL rules to the repository. Accepts a JSON array of ACL rule objects.

You can also provide an optional URL request parameter position that specifies the position of the rules to be added. The position is zero-based, i.e., 0 is the first position. If the position parameter is not provided, the rules are added at the end of the list.

POST /rest/repositories/<repositoryID>/acl

Possible response type:

  • HTTP Status 200 (OK) – The ACL rules were successfully added

  • HTTP Status 400 (Bad Request) – The request is invalid or missing required information (e.g. wrong value or a rule already exists)

Delete ACL rules from a repository

Deletes the provided ACL rules from the repository. Accepts a JSON array of ACL rule objects. The provided ACL rules are removed from the list regardless of their position.

DELETE /rest/repositories/<repositoryID>/acl

Possible response type:

  • HTTP Status 204 (No Content): The ACL rules were successfully removed if they existed or the rules did not exist and thus nothing was removed

  • HTTP Status 400 (Bad Request): The request is invalid or missing required information (e.g. wrong value)

Set ACL rules of a repository

Replaces the existing ACL rules of a repository with a new list of ACL rules. Accepts a JSON array of ACL rule objects.

PUT /rest/repositories/<repositoryID>/acl

Possible response type:

  • HTTP Status 200 (OK) – The list of ACL rules was successfully updated

  • HTTP Status 400 (Bad Request) – The request is invalid or missing required information

Managing custom user roles

Custom roles together with ACL rules are the key mechanisms for granting or denying access. In order to allow or deny access with ACL rules, you need to grant custom roles to users according to your needs.

Managing custom roles through Workbench

Granting or revoking custom roles can be done easily through the Workbench UI:

  1. Navigate to to Setup ‣ Users and Access.

  2. Start creating a new user or editing an existing one.

To grant a custom role, simply input the name of the custom role without the CUSTOM_ prefix in the Custom Roles field.

To revoke a custom role, click the x-icon of the custom role you want to revoke.

The CUSTOM_ prefix is omitted in the User management view in Workbench for convenience.

_images/quad-based-acl-manage-custom-roles.png

Note

The Workbench UI allows you to grant custom roles only to basic Users. Admin and Repository manager users are automatically granted access to all statements and thus assigning custom roles to them has no practical use. However, if you add custom roles to those users through the REST API, they will also be displayed in Workbench.

Custom role management REST API

Custom roles can also be managed through the custom role management REST API, which provides additional functionality.

Users in a role can be represented as a simple JSON array in the API:

[
  "user1",
  "user2"
]

Conversely, custom roles are described by a simple JSON object where the key is the role name and the value is the user array:

{
  "custom_role1": [
    "user1",
    "user2"
  ],
  "custom_role2": [
    "user1"
  ],
  "custom_role3": [
    "user2",
    "user3"
  ]
}

The API supports the following operations:

List all custom roles and their users

Returns a JSON custom roles object that contains all custom roles and the users associated with each role.

GET /rest/security/custom-roles

Possible response type:

Set all custom roles and their users

Replaces all existing custom roles/users associations with the provided ones. Accepts a JSON custom roles object.

PUT /rest/security/custom-roles

Possible response type:

  • HTTP Status 200 (Created) – The custom roles were successfully updated

  • HTTP Status 400 (Bad Request) – The request is invalid (e.g. one of the provided users does not exist, or one of the provided roles is not a custom role)

List the users of a particular custom role

Returns a JSON array of usernames as strings that contains all users associated with the provided custom role.

GET /rest/security/custom-roles/<customRole>

Possible response type:

  • HTTP Status 200 (OK) – The request was successful, and the response will contain an array of usernames as strings

  • HTTP Status 400 (Bad Request) – The request is invalid (e.g. the provided role is not a custom role)

Set custom role users

Replaces all users in <customRole> with the provided ones. Accepts a JSON array of usernames as strings.

PUT /rest/security/custom-roles/<customRole>

Possible response type:

  • HTTP Status 200 (OK) – The custom role was successfully updated

  • HTTP Status 400 (Bad Request) – The request is invalid (e.g. one of the provided users does not exist, or the provided role is not a custom role)

Grant custom role to user

Adds the provided users to <customRole>. Accepts a JSON array of usernames as strings.

POST /rest/security/custom-roles/<customRole>

Possible response type:

  • HTTP Status 200 (OK) – The custom role was granted to each of the provided users who was not already granted that role

  • HTTP Status 400 (Bad Request) – The request is invalid (e.g. one of the provided users does not exist, or the provided role is not a custom role)

Revoke custom role from user

Removes the provided users from <customRole>. Accepts a JSON array of usernames as strings.

DELETE /rest/security/custom-roles/<customRole>

Possible response type:

  • HTTP Status 204 (No Content) – The custom role was revoked if it was previously granted or no action was taken if the role was not already granted

  • HTTP Status 400 (Bad Request) – The request is invalid (e.g. one of the provided users does not exist, or the provided role is not a custom role)

List all roles associated with a user

Returns a JSON array of roles as strings with the custom roles granted to the provided user.

GET /rest/security/users/<username>/custom-roles

Possible response type:

  • HTTP Status 200 (OK) – The request was successful, and the response will contain a list of custom roles

ACL complete example

The following example describes how to add custom roles to users, ACL rules, and illustrates how rules are applied when evaluating SPARQL queries. The example shows how to do this using the Custom role management REST API and ACL management REST API with cURL. The same can also be achieved by using Workbench only.

Setup repository, data and users

First, you need to create a repository and some users:

  1. Create a repository called myrepo1

  2. Download starwars-data.ttl and import it into the repository

  3. Create a user test1 with read access to myrepo1 repository

  4. Create a user test2 with read access to myrepo1 repository

  5. Enable security

Note

All cURL examples below assume security was enabled and the default admin password was not changed.

Adding custom roles to users

Then, you need to add the users test1 and test2 to the custom role CUSTOM_ROLE1, and the user test2 to CUSTOM_ROLE2:

  1. Add users test1 and test2 to custom role CUSTOM_ROLE1:

    curl -u admin:root -H 'content-type: application/json' -X POST\
        http://localhost:7200/rest/security/custom-roles/custom_role1\
        -d '[ "test1", "test2" ]'
    
  2. Add user test2 to custom role CUSTOM_ROLE2:

    curl -u admin:root -H 'content-type: application/json' -X POST\
        http://localhost:7200/rest/security/custom-roles/custom_role2\
        -d '[ "test2" ]'
    

If you go to the Setup ‣ Users and Access view in Workbench you should the custom roles you just added to the users. Remember that the CUSTOM_ prefix is omitted when shown in Workbench.

_images/quad-based-acl-example-users.png

Adding ACL rules to the repository

Finally, add some ACL rules to the repository myrepo1:

curl -u admin:root -H 'content-type: application/json' -X POST\
    http://localhost:7200/rest/repositories/myrepo1/acl -d '[
        {
            "subject": "<https://swapi.co/resource/human/1>",
            "predicate": "*",
            "object": "*",
            "context": "*",
            "role": "CUSTOM_ROLE2",
            "policy": "allow"
        },
        {
            "subject": "*",
            "predicate": "<https://swapi.co/vocabulary/height>",
            "object": "*",
            "context": "*",
            "role": "CUSTOM_ROLE1",
            "policy": "deny"
        }
    ]'

In summary, this adds two rules:

  • Allow access to all statements whose subject is <https://swapi.co/resource/human/1> if the user has role CUSTOM_ROLE2

  • Deny access to all statements whose predicate is <https://swapi.co/vocabulary/height> if the user has role CUSTOM_ROLE1

If you navigate to Setup ‣ ACL Management in Workbench you should see the two rules you just added.

_images/quad-based-acl-example-rules.png

Accessing data with ACL

Let’s try running some queries as 3 different users: admin, test1 and test2. Each user will see a different view of the repository according to the user’s roles and defined ACL rules.

Query 1: Select all humans and their height
PREFIX voc: <https://swapi.co/vocabulary/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT * {
    ?human a voc:Human ;
          rdfs:label ?name .
    OPTIONAL {
        ?human voc:height ?height
    }
    FILTER(LANG(?name) = "en")
}

If you run this as admin, you will see a list of humans from Star Wars such as Obi-Wan Kenobi, Darth Vader and Luke Skywalker, and their respective height. This is because the user admin has unrestricted access to the repository.

If you run this as test1, you will see a list of humans from Star Wars such as Obi-Wan Kenobi, Darth Vader and Luke Skywalker, but the height will be empty. This is because of the second rule in the ACL you added. The first rule does not apply because the user test1 does not have the role CUSTOM_ROLE2.

If you run this as test2, you will see a list of humans from Star Wars such as Obi-Wan Kenobi, Darth Vader and Luke Skywalker, but the height will be empty for everyone but Luke Skywalker. This is because of the first rule in the ACL you added. The second rule will not be evaluated because another rule matched before it.

Query 2: Find the minimum and maximum height of every Star Wars character
PREFIX voc: <https://swapi.co/vocabulary/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT (MIN(?height) AS ?minHeight) (MAX(?height) AS ?maxHeight) {
    ?human a voc:Character .
    OPTIONAL {
        ?human voc:height ?height
    }
}

Again, the same rules will be applied and the result will be:

  • Running as admin: minimum height 66.0 and maximum 264.0

  • Running as test1: no result as there are no datapoints

  • Running as test2: both the minimum and maximum are 172.0 as there is only one data point

In summary, a user sees a restricted view of the repository according to the matching ACL rules and the user’s roles.