Manage Access to Data (ACP)

Access Control Policies (ACP) determine the access to Resources stored in Solid Pods. ACP is an alternative to Access Control Lists and is being proposed for inclusion in the Solid specifications.

Solid Server Support

Access Control Resource (ACR)

Every Resource has an associated Access Control Resource (ACR). The Access Control Resource contains the Access Policies that apply to its associated Resource. If the Resource is a Container, its ACR can include Policies that apply to its children (i.e., Member Policies).

Access Policy

An Access Policy defines the agents’ access to a resource. Specifically, the Access Policy allows or denies the specified access modes to agents’ and client apps based on how they match the conditions in the listed access rules; i.e.,

If <all | any | none> of the access rules are true for an agent or client app, < allow | deny > the specified access modes to a resource.

ACP Access Rules

Access Rules specify the conditions under which the Access Policy applies. Access Rules can specify the following conditions:

  • Agent is in a list of WebIDs (See Authentication for verifying user identity)

  • Agent is the creator of the resource.

  • Agent has authenticated.

  • Agent can be anyone (i.e., Public).

  • Agent is a member of one of the listed groups.

  • Client application is in a list of WebIDs (See Authenticate Client Applications (Browser & Node.JS) for verifying application identity)

  • Client application can be any app.

A policy specifies its rules as part of allOf(), anyOf(), and noneOf() operator expressions:

allOf(<rules>)

Evaluates to true if all of its listed rules evaluate to true; i.e., a logical AND of its listed rules.

anyOf(<rules>)

Evaluates to true if any of its listed rules evaluate to true; i.e., a logical OR of its listed rules.

noneOf(<rules>)

Evaluates to true if none of its listed rules evaluate to true; i.e., a logical NOT of its listed rules.

Examples

Given the following rules:

FriendsRule

Agent is one of the following WebIDs:

  • https://pod.example.net/AlliGator/profile/card

  • https://pod.example.net/MissySippy/profile/card

  • https://pod.example.net/ChiKadee/profile/card#me

ColleaguesRule

Agent is one of the following WebIDs:

  • https://pod.example.net/AlliGator/profile/card

AppListRule

Client app is one of the following WebIDs:

  • https://my-app.example.com/profile#app

Then, the following sample policies specify the rules in various combinations of allOf(), anyOf(), and noneOf() operator expressions:

Example 1: A policy specifies allOf(FriendsRule).

The policy applies if:

  • The agent’s WebID is listed in the FriendsRule.

Example 2: A policy specifies allOf(FriendsRule, AppListRule).

The policy applies if:

  • The agent’s WebID is listed in the FriendsRule AND the agent is using an app listed in the the AppListRule.

Example 3: A policy specifies both anyOf(FriendsRule,ColleaguesRule) and allOf(AppListRule).

The policy applies if:

  • The agent’s WebID is listed in the FriendsRule OR the agent’s WebID is listed in the ColleaguesRule, and

  • The agent is using an app listed in the AppListRule.

Example 4: A policy specifies both allOf(FriendsRule) and noneOf(ColleaguesRule, AppListRule).

The policy applies if:

  • The agent is one of the listed WebIDs in the FriendsRule, and

  • The agent is NOT listed in ColleaguesRule AND the agent is NOT using an app listed in the AppListRule.

ACP Access Modes

Access Modes describe the type of permissions (i.e., access) to a resource. The following Access Modes are available:

Access Mode

Description

Read

View data.

Append

Add data.

Write

Add, update, and delete data.

Accessing the APIs

Tip

The solid-client library provides universal access control APIs that can be used with either Access Control Policies (ACP) proposal or Web Access Control (WAC).

When possible, use the universal access control APIs instead of the ACP-specific APIs or WAC-specific APIs. For situations that require ACP-specific or WAC-specific APIs, see Mechanism-Specific Access Control APIs.

The ACP-specific functions are exported as properties on the acp_v3 export. That is, to use the function(s), you import them with an import of acp_v3.

For example, to use the getAcrPolicyUrlAll, you import acp_v3:

import {
  acp_v3
} from "@inrupt/solid-client";

// ...
const acrPolicyUrl = acp_v3.getAcrPolicyUrlAll(resource);
// ...

Managing Access Controls

The API provides the following WithAcr functions to retrieve the Access Control Resource (ACR) with the Resource: getSolidDatasetWithAcr, getFileWithAcr, and getResourceInfoWithAcr.

To the retrieved Resource with ACR, you can use addPolicyUrl function to make that Policy apply to the Resource, or use the addMemberPolicyUrl function to make the Policy apply to the Resource’s children. For example:

import {
  acp_v3
} from "@inrupt/solid-client";

const resourceWithAcr = await acp_v3.getSolidDatasetWithAcr(
  "https://example.pod/resource",
);
let changedResourceWithAcr = acp_v3.addPolicyUrl(
  resourceWithAcr,
  "https://example.pod/policies#policy",
);
changedResourceWithAcr = acp_v3.addMemberPolicyUrl(
  changedResourceWithAcr,
  "https://example.pod/policies#member-policy",
);

To access existing Policies that apply to a Resource or to its children, use getPolicyUrlAll and getMemberPolicyUrlAll, respectively.

To remove existing Policies, use removePolicyUrl and removeMemberPolicyUrl (for individual Policies) or removePolicyUrlAll and removeMemberPolicyUrlAll (for all currently applied Policies).

You can apply policies to the ACR itself using similar functions. Use addAcrPolicyUrl function to add the Policy to the Resource’s ACR or use the addMemberAcrPolicyUrl function to add the Policy to the ACR of the Resource’s children. For example:

import {
  acp_v3
} from "@inrupt/solid-client";

const resourceWithAcr = await acp_v3.getSolidDatasetWithAcr(
  "https://example.pod/resource",
);
let changedResourceWithAcr = acp_v3.addAcrPolicyUrl(
  resourceWithAcr,
  "https://example.pod/policies#acr-policy",
);
changedResourceWithAcr = acp_v3.addMemberAcrPolicyUrl(
  changedResourceWithAcr,
  "https://example.pod/policies#acr-member-policy",
);

To access existing Policies that apply to an ACR or to the Resource’s children’s ACRs, use getAcrPolicyUrlAll and getMemberAcrPolicyUrlAll, respectively.

To remove existing Policies, use removeAcrPolicyUrl and removeMemberAcrPolicyUrl (for individual Policies) or removeAcrPolicyUrlAll and removeMemberAcrPolicyUrlAll (for all currently applied Policies).

Then, to save the Access Control Resource back to the Pod, you can use saveAcrFor as in the following example:

import {
  acp_v3
} from "@inrupt/solid-client";

const resourceWithAcr = await acp_v3.getSolidDatasetWithAcr(
  "https://example.pod/resource",
);
let changedResourceWithAcr = acp_v3.addAcrPolicyUrl(
  resourceWithAcr,
  "https://example.pod/policies#acr-policy",
);
changedResourceWithAcr = acp_v3.addMemberAcrPolicyUrl(
  changedResourceWithAcr,
  "https://example.pod/policies#acr-member-policy",
);

changedResourceWithAcr = acp_v3.addPolicyUrl(
  changedResourceWithAcr,
  "https://example.pod/policies#a-policy",
);

const updatedResourceWithAcr = await saveAcrFor(changedResourceWithAcr);

Managing Access Policies

To manage Access Policies, the following functions are available: createPolicy to create Access Policies, getPolicy and getPolicyAll to retrieve Access Policies, removePolicy to remove Access Policy from a Resource, and setPolicy to add the Policy to a Resource.

Note

Access Controls require that a Policy has a full, known URL by which it can be referred. You must specify this URL to createPolicy when creating a Policy.

View Modes

To view what Modes (Read, Append, or Write) are allowed by a Policy, use the getAllowModes function. The function returns an object with the boolean properties read, append and write:

const policy = acp_v3.getPolicy(
  solidDataset,
  "https://example.pod/policies#a-policy",
);
const allowedModes = acp_v3.getAllowModes(policy);
// e.g. =>
// { read: true, append: false, write: false }

Similarly, you can use getDenyModes to obtain a similar object describing which Modes are denied by a Policy.

Modify Modes

To change which Modes a Policy allows, use the setAllowModes function, passing it an object with boolean properties read, append and write:

const policy = acp_v3.createPolicy("https://example.pod/policies#a-policy");
const updatedPolicy = acp_v3.setAllowModes(
  policy,
  { read: true, append: false, write: false },
);

Similarly, you can use setDenyModes to change which Modes a Policy denies.

Managing Access Rules

To manage Access Rules, the following functions are available: createRule to create Access Rules, getRule and getRuleAll to retrieve Access Rules from a Resource, removeRule to remove Access Rule from a Resource, and setRule to add the Rule to a Resource.

Note

Access Controls require that a Rule has a full, known URL by which it can be referred. You must specify this URL to createRule when creating a Rule.

Manage Rules for Specific Agents/Groups

For Rules that specify a list of specific Agents (i.e., these Rules apply to their listed Agents), you can use getAgentAll, addAgent, setAgent, and removeAgent to manage the list:

const rule = acp_v3.createRule("https://example.pod/rules#a-rule");
const changedRule = acp_v3.addAgent(
  rule,
  "https://other.pod/profile/card#me",
);
const addedAgents = acp_v3.getAgentAll(changedRule);
// => ["https://other.pod/profile/card#me"]

To manage the Groups for a Rule, you can use the Group variants of the functions, e.g., getGroupAll, etc.

Manage Rules for Public, Any Authenticated User, or the Creator of a Resource

Additionally, to inspect whether a Rule applies to everybody, to any authenticated user, or just the creator of a Resource, you can use the hasPublic function, the hasAuthenticated function and the hasCreator function, respectively. To set whether a Rule applies to everybody, any authenticated user, or the creator of a Resource, use the corresponding setPublic, setAuthenticated and setCreator functions and their respective remove counterparts:

const rule = acp_v3.getRule(
  solidDataset,
  "https://example.pod/rules#a-rule",
);
let changedRule = acp_v3.removePublic(rule);
changedRule = acp_v3.setAuthenticated(changedRule);
changedRule = acp_v3.removeCreator(changedRule);
// `changedRule` does not include everybody,
// but it does include everybody who is authenticated.

Manage Rules for Specific Client Applications

For Rules that specify a list of specific Client applications (i.e., these Rules apply to their listed Client applications), you can use getClientAll, addClient, setClient, and removeClient:

const rule = acp_v3.createRule("https://example.pod/rules#a-rule");
const changedRule = acp_v3.addClient(
  rule,
  "https://my-app.domain/profile#app",
);
const addedClients = acp_v3.getClientAll(changedRule);
// => ["https://my-app.domain/profile#app"]

To manage whether a Rule applies to any client application, you can use setAnyClient or removeAnyClient.

Manage AllOf/AnyOf/NoneOf Rules

A policy can specify that <all | any | none> of the access rules match an agent.

To access rules that the policy specifies with the all condition, use the AllOf rule functions; e.g., getAllOfRuleUrlAll, addAllOfRuleUrl, setAllOfRuleUrl, and removeAllOfRuleUrl.

To access rules that the policy specifies with the any condition, use the AnyOf variants of the functions; e.g., getAnyOfRuleUrlAll.

To access rules that the policy specifies with the none condition, use the NoneOf variants of the functions; e.g., setNoneOfRuleUrl.

const policy = acp_v3.policy(
  solidDataset,
  "https://example.pod/policies#a-policy",
);

// Replace existing AllOf Rules with the Rule at
// https://example.pod/rules#a-rule
let changedPolicy = acp_v3.setAllOfRuleUrl(
  policy,
  "https://example.pod/rules#a-rule",
);

// Add the Rule at
// https://example.pod/rules#another-rule
// to the existing AnyOf Rules:
changedPolicy = acp_v3.addAnyOfRuleUrl(
  changedPolicy,
  "https://example.pod/rules#another-rule",
);

Resource-specific Rules and Policies

Access Control Policies allow you to set up access configurations that can be applied to multiple Resources. However, in some instances, you may want to set up Policies and Rules that apply to a single Resource.

To set up Policies and Rules that apply to a single Resource, use the universal access control APIs when possible. When not possible, you can use the ACP API to store Rules and Policies directly in the single Resource’s Access Control Resource (ACR).

To store Rules and Policies directly in a Resource’s ACR using the ACP API:

  • Retrieve a Resource with an ACR (see Managing Access Controls for the available withACR functions).

  • Initialize Resource-specific Policies and Rules using createResourcePolicyFor and createResourceRuleFor. Pass into the functions the Resource and an identifier for your Rule or Policy.

  • Modify these Resource-specific Policies and Rules using the same functions as with other Policies and Rules (see Managing Access Policies and Managing Access Rules)

  • Add the Policies and Rules to the Resource’s ACR:

    • To add a Resource-specific Rule to the ACR, use setResourceRule.

    • To add a Policy to the ACR that applies to that ACR’s Resource, use setResourcePolicy.

    • To add a Policy to the ACR that applies to that ACR itself, use setResourceAcrPolicy.

Note

Whereas regular Policies have to be applied explicitly to a Resource using various functions (e.g., addPolicyURL, addMemberPolicyUrl), Resource-specific Policies are applied automatically to their Resource or their Resource’s ACR.

// Fetch the Resource and its Access Control Resource
const resourceWithAcr = await acp_v3.getSolidDatasetWithAcr("https://example.pod/policies");

// Create the Resource-specific Rule
let resourceRule = acp_v3.createResourceRuleFor(resourceWithAcr, "rule-public")
resourceRule = acp_v3.setPublic(resourceRule);

// Create the Resource-specific Policy, and add the Rule to it:
let resourcePolicy = acp_v3.createResourcePolicyFor(
  resourceWithAcr,
  "policy-public",
);
resourcePolicy = acp_v3.setAllOfRuleUrl(
  resourcePolicy,
  resourceRule,
);
resourcePolicy = acp_v3.setAllowModes(
  resourcePolicy,
  { read: true, append: false, write: false },
);

// Save both the new Rule and the new Policy in the Access Control Resource:
let updatedResourceWithAcr = acp_v3.setResourceRule(
  resourceWithAcr,
  resourceRule,
);
updatedResourceWithAcr = acp_v3.setResourcePolicy(
  updatedResourceWithAcr,
  resourcePolicy,
);

// Save the updated Access Control Resource:
await acp_v3.saveAcrFor(updatedResourceWithAcr);