-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
2,128 additions
and
14 deletions.
There are no files selected for viewing
This file contains 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 @@ | ||
debug |
This file contains 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,76 @@ | ||
@prefix odrl: <http://www.w3.org/ns/odrl/2/> . | ||
@prefix : <http://example.org/> . | ||
@prefix acl: <http://www.w3.org/ns/auth/acl#>. | ||
@prefix fno: <https://w3id.org/function/ontology#> . | ||
@prefix log: <http://www.w3.org/2000/10/swap/log#> . | ||
@prefix string: <http://www.w3.org/2000/10/swap/string#> . | ||
@prefix list: <http://www.w3.org/2000/10/swap/list#> . | ||
# Read ODRL rule | ||
{ | ||
?permission a odrl:Permission; | ||
odrl:action ?action ; | ||
odrl:target ?targetResource ; | ||
odrl:assignee ?requestedParty; | ||
odrl:assigner ?resourceOwner . | ||
|
||
?action list:in (odrl:use odrl:read) . # multiple options | ||
|
||
?SCOPE log:notIncludes { ?permission odrl:constraint ?anything }. # No odrl:constraints may be present | ||
# context of a request | ||
?context | ||
:resourceOwner ?resourceOwner; | ||
:requestingParty ?requestedParty; | ||
:target ?targetResource; | ||
:requestPermission acl:Read. | ||
|
||
:uuid5 log:uuid ?uuidStringdataUsagePolicyExecution. | ||
( "urn:uuid:" ?uuidStringdataUsagePolicyExecution) string:concatenation ?urnUuidStringdataUsagePolicyExecution. | ||
?dataUsagePolicyExecution log:uri ?urnUuidStringdataUsagePolicyExecution . | ||
} => | ||
{ | ||
?dataUsagePolicyExecution a fno:Execution; | ||
fno:executes <http://example.org/dataUsage> ; | ||
:accessModesAllowed acl:Read. | ||
}. | ||
|
||
# Update ODRL Rule (odrl:modify: new asset is not created, not same as acl:write) | ||
{ | ||
?permission a odrl:Permission; | ||
odrl:action ?action ; | ||
odrl:target ?targetResource ; | ||
odrl:assignee ?requestedParty; | ||
odrl:assigner ?resourceOwner . | ||
|
||
?action list:in (odrl:use odrl:modify). # multiple options | ||
|
||
?SCOPE log:notIncludes { ?permission odrl:constraint ?anything }. # No odrl:constraints may be present | ||
|
||
# context of a request | ||
?context | ||
:resourceOwner ?resourceOwner; | ||
:requestingParty ?requestedParty; | ||
:target ?targetResource; | ||
:requestPermission acl:Write. | ||
|
||
:uuid5 log:uuid ?uuidStringdataUsagePolicyExecution. | ||
( "urn:uuid:" ?uuidStringdataUsagePolicyExecution) string:concatenation ?urnUuidStringdataUsagePolicyExecution. | ||
?dataUsagePolicyExecution log:uri ?urnUuidStringdataUsagePolicyExecution . | ||
} => | ||
{ | ||
?dataUsagePolicyExecution a fno:Execution; | ||
fno:executes <http://example.org/dataUsage> ; | ||
:accessModesAllowed acl:Write. | ||
}. | ||
<http://example.org/1705937573496#usagePolicy> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/ns/odrl/2/Agreement> . | ||
<http://example.org/1705937573496#usagePolicy> <http://www.w3.org/ns/odrl/2/permission> <http://example.org/1705937573496#permission> . | ||
<http://example.org/1705937573496#permission> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/ns/odrl/2/Permission> . | ||
<http://example.org/1705937573496#permission> <http://www.w3.org/ns/odrl/2/action> <http://www.w3.org/ns/odrl/2/use> . | ||
<http://example.org/1705937573496#permission> <http://www.w3.org/ns/odrl/2/target> <http://localhost:3000/test.ttl> . | ||
<http://example.org/1705937573496#permission> <http://www.w3.org/ns/odrl/2/assignee> <https://woslabbi.pod.knows.idlab.ugent.be/profile/card#me> . | ||
<http://example.org/1705937573496#permission> <http://www.w3.org/ns/odrl/2/assigner> <https://pod.woutslabbinck.com/profile/card#me> . | ||
|
||
# <http://example.org/1705937573496#permission> odrl:constraint <test>. # Note: uncommenting this rule leads to error | ||
<http://example.org/context> <http://example.org/resourceOwner> <https://pod.woutslabbinck.com/profile/card#me> . | ||
<http://example.org/context> <http://example.org/requestingParty> <https://woslabbi.pod.knows.idlab.ugent.be/profile/card#me> . | ||
<http://example.org/context> <http://example.org/target> <http://localhost:3000/test.ttl> . | ||
<http://example.org/context> <http://example.org/requestPermission> <http://www.w3.org/ns/auth/acl#Write> . |
This file contains 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,174 @@ | ||
This tutorial is about how to install and use the [@solidlab/ucp](https://github.com/SolidLabResearch/user-managed-access/tree/main/packages/ucp) library utilities. | ||
|
||
## Installing | ||
|
||
As of today (2 Februari 2024), this package is not on npm. | ||
Which means installing via `npm install @solidlab/ucp` does **not** work yet. | ||
|
||
However, it can still easily installed by adding `"@solidlab/ucp": "https://gitpkg.now.sh/SolidLabResearch/user-managed-access/packages/css?main"` to your dependencies in package.json, or executing the corresponding command of your favourite package manager, e.g. `yarn add @solidlab/ucp@"https://gitpkg.now.sh/SolidLabResearch/user-managed-access/packages/css?main"`. | ||
|
||
## Using the library | ||
|
||
First, a brief reminder of what the goal is of this library. | ||
What this library gives is a set of tools for creating **usage control decision** engines that are fully customizable. | ||
A **usage control decision** engine evaluates an *action request* against a set of *Usage Control Policies* to get a conclusion of *access grants*. | ||
|
||
### Example | ||
|
||
As an example, imagine that Ruben wants to know Wout his age. | ||
The age of Wout can be found in a *resource*, `urn:wout:age` (a unique identifier), and is safeguarded by Wout his *policy* that says Ruben has read access to the *resource*. | ||
oncretely, this policy could be modelled as a tuple (Requesting Party (RP), action, target resource, resource owner), which in this example would be (`urn:ruben`, `urn:modes:read`, `urn:wout:age`, `urn:wout`). | ||
The **usage control decision** engine, would then be able to interpret both the request and the policy to give as conclusion a grant: `urn:modes:read`. | ||
This means Ruben is able to know Wout his age and we know that the access is allowed conforming to the policies of Wout thanks to the engine. | ||
|
||
Note: that this example does not contain any usage control yet, but is rather access control. | ||
When a policy has additional to the current tuple expression and enforcement for e.g. Ruben has to delete the data after 30 days and/or that he can only use it for the purpose of for example buying a gift for Wout his Birthday, then we are talking about Usage Control. | ||
Though, you could see the current use case as preventive usage control without purposes. | ||
|
||
### High level Architecture | ||
|
||
There are two functions implemented to calculate the grants, both are part of the interface `UconEnforcementDecision`. | ||
|
||
1. `calculateAccessModes`: Calculate the *access grants* based on the set of *Usage Control Policies* , the *request* and how to *interpret the policies* (the algorithm). | ||
2. `calculateAndExplainAccessModes`: The same as `calculateAccessModes`, but also provides an **Explanation** of how the *access grants* are calculated. | ||
|
||
Both functions have as input a `UconRequest`. This is an interface that formalizes the action request e.g. (RP, requested action, resource) (`urn:ruben`, `urn:modes:read`, `urn:wout:age`). | ||
|
||
As output, `calculateAccessModes` has a list of strings (*access grants*) and `calculateAndExplainAccessModes` has an `Explanation` (which will be elaborated later). | ||
|
||
### The first usage control decision engine | ||
|
||
The implementation of the `UconEnforcementDecision` interface that this library provides is `UcpPatternEnforcement`. | ||
|
||
The first instantiation of this interface is what is referred here as the first **usage control decision** engine. | ||
Before this instantiation is given, an explanation of how it works is given in [the following section](#usage-control-decision-engine). | ||
|
||
#### Usage Control Decision engine | ||
|
||
The (`UcpPatternEnforcement`) engine has three components and can be consulted with the methods described in [the high level architecture](#high-level-architecture). | ||
|
||
The three components: | ||
|
||
- A **[storage](https://github.com/SolidLabResearch/user-managed-access/tree/main/packages/ucp/src/plugins)** to the set of *Usage Control Policies* | ||
- A **storage** to the set of [Notation3](https://w3c.github.io/N3/spec/) (N3) [interpretation rules](https://github.com/SolidLabResearch/user-managed-access/tree/main/packages/ucp/rules) | ||
- A configured instance of **[Koreografeye](https://github.com/eyereasoner/Koreografeye)** consisting of: | ||
- An **N3 reasoner** ([eye-js](https://github.com/eyereasoner/eye-js)) | ||
- A [Koreografeye policy/plugin executor](https://github.com/SolidLabResearch/user-managed-access/blob/main/packages/ucp/src/PolicyExecutor.ts) + [plugins](https://github.com/SolidLabResearch/user-managed-access/tree/main/packages/ucp/src/plugins) | ||
|
||
When a method (e.g. `calculateAccessModes`) is then called with an *action request* the following steps are then executed: | ||
|
||
1. The N3 Reasoner runs with as input: | ||
1. The set of *Usage Control Policies* | ||
2. The request (`UconRequest` serialized as RDF) | ||
3. The N3 *interpretation rules* | ||
2. The conclusion from the Reasoner is then extracted by the Koreografeye policy/plugin executor (configured with plugins) | ||
3. The result is then returned | ||
|
||
This modular approach allows for fast prototyping of a formal Usage Control Policy language, which can then immediately be evaluated. | ||
|
||
#### Instantiation | ||
|
||
This first policy engine instantiation can perform an evaluation of policies modelled with [Open Digital Rights Language (ODRL)](https://www.w3.org/TR/odrl-model/). | ||
More specifically, with a subset that only can interpret `odrl:Permission`s with as **action** `odrl:modify`, `odrl:read` and `odrl:use` (which means both modify and read) against action requests and where there are **no Constraints**. | ||
|
||
To initialise `UcpPatternEnforcement` as this engine, the following code is required: | ||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/simple-engine.ts#L1-L18 | ||
|
||
|
||
At this point, the engine is ready to be used. Which means that now you can use the `calculateAccessModes` function to request the **grants** for following *action request*: "Ruben wants to know the age of Wout". | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/simple-engine.ts#L20-L27 | ||
|
||
Unfortunately, this results into an empty list `[]`. Which means no **grants** are given and thus Ruben cannot know the age of Wout. | ||
|
||
The reason for this is very simple, there is **no** *Usage Control Policy* in the storage. | ||
|
||
This can however be resolved by simply adding such a policy to the **Usage Control Rule Storage**: | ||
|
||
```ttl | ||
@prefix odrl: <http://www.w3.org/ns/odrl/2/> . | ||
@prefix : <http://example.org/usageControlRule> . | ||
:permission | ||
a odrl:Permission ; | ||
odrl:action odrl:read ; | ||
odrl:target <urn:wout:age> ; | ||
odrl:assignee <https://pod.rubendedecker.be/profile/card#me> ; | ||
odrl:assigner <https://pod.woutslabbinck.com/profile/card#me> . | ||
``` | ||
|
||
To add this rule to the storage, the following code can be used: | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/simple-engine.ts#L30-L41 | ||
|
||
|
||
From now on, when the access modes are calculated again, the following list of grants is received: | ||
|
||
```sh | ||
[ 'http://www.w3.org/ns/auth/acl#Read' ] | ||
``` | ||
|
||
With current initialisation of the **UC Decision engine**, grants are modelled with the [Access Control List (ACL)](https://www.w3.org/ns/auth/acl) Ontology. | ||
The reason for this is that this component is going to be used in an Authorisation Server (AS) for a [Solid](https://solidproject.org/) Resource Server (RS) using the [User-Managed Access (UMA)](https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html) specification. In the [Solid Protocol](https://solidproject.org/TR/protocol), ACL is the ontology used for **access modes** both its authorization specifications: the [Web Access Control (WAC)](https://solidproject.org/TR/wac) specification and the [Access Control Policy (ACP)](https://solidproject.org/TR/acp) specification. | ||
|
||
In the engine, this grant is calculated within the N3 interpretation rules, more specifically [here](https://github.com/SolidLabResearch/user-managed-access/blob/949917faa015195369e430f77200bf3273f79283/packages/ucp/rules/data-crud-rules.n3#L12-L38). | ||
|
||
The full code sample for this example can be found in [appendix I](#appendix-I-Full-code-snippet) | ||
|
||
### <!--Temporal Policy engine--> | ||
|
||
<!--TODO:--> | ||
|
||
### Engine with explanation | ||
|
||
First an elaboration is given for what is meant by explanation. | ||
<!--Note: after implementation, similarities have been found with the idea of **ODRL Evaluator** from the [ODRL Formal Semantics Community Group](https://w3c.github.io/odrl/formal-semantics/).--> | ||
|
||
#### Explanation | ||
|
||
So what is the explanation exactly? It is an interface which contains four components: | ||
|
||
|
||
An `Explanation` consists of four components: | ||
|
||
- `decision`: This is the same as the grants (array of access modes) from `calculateAccessModes`. It is the **result** of the evaluation | ||
- `request`: The input *action request* | ||
- `conclusions`: The conclusions of the reasoner. A conclusion itself consists of four parts: the **Rule Identifier**, the **Interpration N3 Rule Identifier**, the **grants** allowed (the actual conclusion) and the **timestamp** at which the conclusion was generated. A conclusion can be seen as the proof of following function: $interpretation(rule, context, timestamp) -> grants$ | ||
- `algorithm`: Which algorithm is used to interpret the set of conclusions | ||
- Note: only the **union** operator is currently implemented. That is: $\forall c \in C. grant \in c \Rightarrow grant \in D$ </br> | ||
For all conclusions in `conclusions`, if a grant is in conclusion, then it is part of the list of grants in `decision`. | ||
|
||
Having the **Explanation** after an evaluation thus allows for logging with provenance/proof of why a certain action was granted at a certain time. | ||
|
||
#### Instantiation | ||
|
||
To have a **usage control decision** engine that can give **Explanations**, it needs to be instantiated correctly. This can be done with following code: | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/log-engine.ts#L1-L18 | ||
|
||
Not that compared to the previous engines, a different **plugin** and a different **N3 interpretation rules** are used. | ||
These allow for retrieving a proper explanation during the calculation of the requests. | ||
|
||
Another difference is the fact that know the method `calculateAndExplainAccessModes` has to be used. | ||
Luckily, this still uses a `UconRequest` as input: | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/log-engine.ts#L34-L41 | ||
When a policy is added to the storage, the above code print out a Javascript Object, which is not very nice. | ||
|
||
Luckily, it is possible to have a nice RDF serialization as output: | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/log-engine.ts#L46-L49 | ||
|
||
Or to be used as RDF in code with the N3 Store: | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/log-engine.ts#L43-L44 | ||
|
||
|
||
## appendix I: Full code snippet | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/simple-engine.ts#L1-L52 | ||
|
||
|
||
## appendix III: Full code snippet Explanation | ||
|
||
https://github.com/SolidLabResearch/user-managed-access/blob/1c0410b6f1c3f133843430f60d4f8c690273dff0/packages/ucp/docs/log-engine.ts#L1-L51 |
This file contains 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,51 @@ | ||
import { PolicyExecutor, UcpPatternEnforcement, UCPLogPlugin, MemoryUCRulesStorage, explanationToRdf, serializeFullExplanation, turtleStringToStore } from "@solidlab/ucp"; | ||
import { EyeJsReasoner } from "koreografeye"; | ||
|
||
async function main() { | ||
// load plugin(s) | ||
const plugins = { "http://example.org/dataUsageLog": new UCPLogPlugin() } | ||
// instantiate koreografeye policy executor | ||
const policyExecutor = new PolicyExecutor(plugins) | ||
// ucon storage | ||
const uconRulesStorage = new MemoryUCRulesStorage() | ||
// load N3 Rules from a directory | ||
const response = await fetch('https://raw.githubusercontent.com/woutslabbinck/ucp-enforcement/main/rules/log-usage-rule.n3'); // loading from the github repo | ||
const n3Rules: string[] = [await response.text()] | ||
// instantiate the enforcer using the policy executor, | ||
const ucpEvaluator = new UcpPatternEnforcement(uconRulesStorage, n3Rules, new EyeJsReasoner([ | ||
"--quiet", | ||
"--nope", | ||
"--pass"]), policyExecutor) | ||
|
||
// add Usage Control Rule to Usage Control Rule Storage | ||
const ucr = `@prefix odrl: <http://www.w3.org/ns/odrl/2/> . | ||
@prefix : <http://example.org/usageControlRule> . | ||
:permission | ||
a odrl:Permission ; | ||
odrl:action odrl:read ; | ||
odrl:target <urn:wout:age> ; | ||
odrl:assignee <https://pod.rubendedecker.be/profile/card#me> ; | ||
odrl:assigner <https://pod.woutslabbinck.com/profile/card#me> . | ||
` | ||
const policyStore = await turtleStringToStore(ucr); | ||
await uconRulesStorage.addRule(policyStore); | ||
|
||
// calculate grants based on a request | ||
const explanation = await ucpEvaluator.calculateAndExplainAccessModes({ | ||
subject: "https://pod.rubendedecker.be/profile/card#me", | ||
action: ["http://www.w3.org/ns/auth/acl#Read"], | ||
resource: "urn:wout:age", | ||
owner: "https://pod.woutslabbinck.com/profile/card#me" | ||
}); | ||
console.log(explanation); | ||
|
||
// use of explanationToRdf | ||
const explanationStore = explanationToRdf(explanation); | ||
|
||
// use of serializeFullExplanation | ||
const uconRules = await uconRulesStorage.getStore(); | ||
const serialized = serializeFullExplanation(explanation, uconRules, n3Rules.join('\n')); | ||
console.log(serialized); | ||
} | ||
main() |
This file contains 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,52 @@ | ||
import { PolicyExecutor, UcpPatternEnforcement, UcpPlugin, MemoryUCRulesStorage, turtleStringToStore } from "@solidlab/ucp"; | ||
import { EyeJsReasoner } from "koreografeye"; | ||
|
||
async function main() { | ||
// load plugin(s) | ||
const plugins = { "http://example.org/dataUsage": new UcpPlugin() } | ||
// Initialise koreografeye policy executor | ||
const policyExecutor = new PolicyExecutor(plugins) | ||
// Initialise Usage Control Rule Storage | ||
const uconRulesStorage = new MemoryUCRulesStorage(); | ||
// load N3 Rules | ||
const response = await fetch('https://raw.githubusercontent.com/woutslabbinck/ucp-enforcement/main/rules/data-crud-rules.n3'); // loading from the github repo | ||
const n3Rules: string[] = [await response.text()] | ||
// instantiate the enforcer using the policy executor, | ||
const ucpEvaluator = new UcpPatternEnforcement(uconRulesStorage, n3Rules, new EyeJsReasoner([ | ||
"--quiet", | ||
"--nope", | ||
"--pass"]), policyExecutor) | ||
|
||
// calculate grants based on a request | ||
const noAccessModes = await ucpEvaluator.calculateAccessModes({ | ||
subject: "https://pod.rubendedecker.be/profile/card#me", | ||
action: ["http://www.w3.org/ns/auth/acl#Read"], | ||
resource: "urn:wout:age", | ||
owner: "https://pod.woutslabbinck.com/profile/card#me" | ||
}); | ||
console.log(noAccessModes); | ||
|
||
// add Usage Control Rule to Usage Control Rule Storage | ||
const ucr = `@prefix odrl: <http://www.w3.org/ns/odrl/2/> . | ||
@prefix : <http://example.org/usageControlRule> . | ||
:permission | ||
a odrl:Permission ; | ||
odrl:action odrl:read ; | ||
odrl:target <urn:wout:age> ; | ||
odrl:assignee <https://pod.rubendedecker.be/profile/card#me> ; | ||
odrl:assigner <https://pod.woutslabbinck.com/profile/card#me> . | ||
` | ||
const policyStore = await turtleStringToStore(ucr); | ||
await uconRulesStorage.addRule(policyStore); | ||
|
||
// calculate grants based on a request | ||
const accessModes = await ucpEvaluator.calculateAccessModes({ | ||
subject: "https://pod.rubendedecker.be/profile/card#me", | ||
action: ["http://www.w3.org/ns/auth/acl#Read"], | ||
resource: "urn:wout:age", | ||
owner: "https://pod.woutslabbinck.com/profile/card#me" | ||
}); | ||
console.log(accessModes); | ||
} | ||
main() |
Oops, something went wrong.