-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathOdrlAuthorizer.ts
More file actions
157 lines (145 loc) · 7.13 KB
/
OdrlAuthorizer.ts
File metadata and controls
157 lines (145 loc) · 7.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { BadRequestHttpError, DC, RDF } from '@solid/community-server';
import { getLoggerFor } from 'global-logger-factory';
import { DataFactory, Quad, Store, Writer } from 'n3';
import { EyelingReasoner, EyeReasoner, ODRLEngineMultipleSteps, ODRLEvaluator } from 'odrl-evaluator';
import { CLIENTID, WEBID } from '../../credentials/Claims';
import { ClaimSet } from '../../credentials/ClaimSet';
import { basicPolicy } from '../../ucp/policy/ODRL';
import { PrioritizeProhibitionStrategy } from '../../ucp/policy/PrioritizeProhibitionStrategy';
import { Strategy } from '../../ucp/policy/Strategy';
import { UCPPolicy } from '../../ucp/policy/UsageControlPolicy';
import { UCRulesStorage } from '../../ucp/storage/UCRulesStorage';
import { ODRL } from '../../ucp/util/Vocabularies';
import { Permission } from '../../views/Permission';
import { Authorizer } from './Authorizer';
const { quad, namedNode, literal, blankNode } = DataFactory
/**
* Permission evaluation is performed as follows:
*
* 1. Conversion of Permission queries to ODRL Requests.
* - A translation is performed to transform CSS actions to ODRL actions.
* - One ODRL Request per Action and target Resource.
*
* 2. ODRL Evaluator performs ODRL Evaluation
* - No policy selection is performed (all policies are inserted rather than all relevant).
* - No conflict resolution strategy is present (Prohibition policies are ignored).
* - No duties are checked.
*
* 3. Conversion from ODRL Policy Compliance Reports to Permissions
* - Selecting the ODRL actions from Active Permission Reports
* - Translation from ODRL actions to CSS actions
*/
export class OdrlAuthorizer implements Authorizer {
protected readonly logger = getLoggerFor(this);
private readonly odrlEvaluator: ODRLEvaluator;
private readonly strategy: Strategy;
/**
* Creates a OdrlAuthorizer enforcing policies using ODRL with the ODRL Evaluator.
*
*
* @param policies - A store containing the ODRL policy rules.
*/
constructor(
private readonly policies: UCRulesStorage,
) {
this.odrlEvaluator = new ODRLEvaluator(new ODRLEngineMultipleSteps({ reasoner: new EyelingReasoner()}));
this.strategy = new PrioritizeProhibitionStrategy();
}
public async permissions(claims: ClaimSet, query?: Permission[]): Promise<Permission[]> {
this.logger.info(`Calculating permissions. ${JSON.stringify({ claims, query })}`);
if (!query) {
this.logger.warn('The OdrlAuthorizer can only calculate permissions for explicit queries.')
return [];
}
// key value store for building the permissions to be granted on a resource
const grantedPermissions: { [key: string]: string[] } = {};
// prepare policy
const policyStore = (await this.policies.getStore())
// prepare sotw
const sotw = new Store();
sotw.add(quad(
namedNode('http://example.com/request/currentTime'),
namedNode('http://purl.org/dc/terms/issued'),
literal(new Date().toISOString(), namedNode("http://www.w3.org/2001/XMLSchema#dateTime"))),
);
const subject = typeof claims[WEBID] === 'string' ? claims[WEBID] : 'urn:solidlab:uma:id:anonymous';
const clientQuads: Quad[] = [];
const clientSubject = blankNode();
if (typeof claims[CLIENTID] === 'string') {
clientQuads.push(
quad(clientSubject, RDF.terms.type, ODRL.terms.Constraint),
// TODO: using purpose as other constraints are not supported in current version of ODRL evaluator
// https://github.com/SolidLabResearch/ODRL-Evaluator/blob/v0.5.0/ODRL-Support.md#left-operands
quad(clientSubject, ODRL.terms.leftOperand, namedNode(ODRL.namespace + 'purpose')),
quad(clientSubject, ODRL.terms.operator, ODRL.terms.eq),
quad(clientSubject, ODRL.terms.rightOperand, namedNode(claims[CLIENTID])),
);
// constraints.push({
// type: ODRL.namespace + 'deliveryChannel',
// operator: ODRL.eq,
// value: namedNode(claims[CLIENTID]),
// });
}
for (const { resource_id, resource_scopes } of query) {
grantedPermissions[resource_id] = [];
for (const scope of resource_scopes) {
// TODO: why is this transformation happening (here)?
// IMO this should either happen on the RS,
// or the policies should just use the "CSS" modes (not really though)
const action = scopeCssToOdrl.get(scope) ?? scope;
this.logger.info(`Evaluating Request [S R AR]: [${subject} ${resource_id} ${action}]`);
const requestPolicy: UCPPolicy = {
type: ODRL.Request,
rules: [
{
action: action,
resource: resource_id,
requestingParty: subject
}
]
}
const request = basicPolicy(requestPolicy);
const requestStore = request.representation
// Adding context triples for the client identifier, if there is one
if (clientQuads.length > 0) {
requestStore.addQuad(quad(
namedNode(request.ruleIRIs[0]),
namedNode('https://w3id.org/force/sotw#context'),
clientSubject,
));
requestStore.addQuads(clientQuads);
}
// evaluate policies
const reports = await this.odrlEvaluator.evaluate(
[...policyStore],
[...requestStore],
[...sotw]);
// handle potential conflicts with a strategy
const allowed = await this.strategy.handleSafe({
request: {
request: [...requestStore],
identifier: namedNode(request.policyIRI)
},
policies: [...policyStore],
reports: reports
})
if (allowed) {
grantedPermissions[resource_id].push(scope);
}
}
}
const permissions: Permission[] = []
Object.keys(grantedPermissions).forEach(
resource_id => permissions.push({
resource_id,
resource_scopes: grantedPermissions[resource_id],
}));
return permissions;
}
}
const scopeCssToOdrl: Map<string, string> = new Map();
scopeCssToOdrl.set('urn:example:css:modes:read', 'http://www.w3.org/ns/odrl/2/read');
scopeCssToOdrl.set('urn:example:css:modes:append', 'http://www.w3.org/ns/odrl/2/append');
scopeCssToOdrl.set('urn:example:css:modes:create', 'http://www.w3.org/ns/odrl/2/create');
scopeCssToOdrl.set('urn:example:css:modes:delete', 'http://www.w3.org/ns/odrl/2/delete');
scopeCssToOdrl.set('urn:example:css:modes:write', 'http://www.w3.org/ns/odrl/2/write');