@authup/access 1.0.0-beta.27 → 1.0.0-beta.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -201
- package/dist/index.mjs +102 -79
- package/dist/index.mjs.map +1 -1
- package/dist/permission/module.d.ts +2 -2
- package/dist/permission/module.d.ts.map +1 -1
- package/dist/permission/provider/memory.d.ts +2 -2
- package/dist/permission/provider/memory.d.ts.map +1 -1
- package/dist/permission/provider/types.d.ts +1 -1
- package/dist/permission/provider/types.d.ts.map +1 -1
- package/dist/permission/types.d.ts +2 -2
- package/dist/permission/types.d.ts.map +1 -1
- package/dist/policy/built-in/attributes/evaluator.d.ts +1 -1
- package/dist/policy/built-in/attributes/evaluator.d.ts.map +1 -1
- package/dist/policy/error/module.d.ts +2 -2
- package/package.json +15 -12
- package/dist/index.cjs +0 -1055
- package/dist/index.cjs.map +0 -1
package/dist/index.cjs
DELETED
|
@@ -1,1055 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var errors = require('@authup/errors');
|
|
4
|
-
var kit = require('@authup/kit');
|
|
5
|
-
var adapterZod = require('@validup/adapter-zod');
|
|
6
|
-
var validup = require('validup');
|
|
7
|
-
var zod = require('zod');
|
|
8
|
-
var mongo2js = require('@ucast/mongo2js');
|
|
9
|
-
|
|
10
|
-
class PolicyError extends errors.AuthupError {
|
|
11
|
-
static evaluatorNotFound(type) {
|
|
12
|
-
return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, errors.ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
|
|
13
|
-
}
|
|
14
|
-
static evaluatorNotProcessable() {
|
|
15
|
-
throw new PolicyError('The evaluator can not process the policy.', errors.ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE);
|
|
16
|
-
}
|
|
17
|
-
static evaluatorContextInvalid() {
|
|
18
|
-
throw new PolicyError('The evaluator context is not valid.', errors.ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
|
|
19
|
-
}
|
|
20
|
-
constructor(message, code){
|
|
21
|
-
super({
|
|
22
|
-
message,
|
|
23
|
-
code
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/*
|
|
29
|
-
* Copyright (c) 2024-2024.
|
|
30
|
-
* Author Peter Placzek (tada5hi)
|
|
31
|
-
* For the full copyright and license information,
|
|
32
|
-
* view the LICENSE file that was distributed with this source code.
|
|
33
|
-
*/ function maybeInvertPolicyOutcome(outcome, invert) {
|
|
34
|
-
if (typeof invert === 'undefined') {
|
|
35
|
-
return outcome;
|
|
36
|
-
}
|
|
37
|
-
if (typeof invert === 'function') {
|
|
38
|
-
return invert(outcome);
|
|
39
|
-
}
|
|
40
|
-
if (!invert) {
|
|
41
|
-
return outcome;
|
|
42
|
-
}
|
|
43
|
-
return !outcome;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/*
|
|
47
|
-
* Copyright (c) 2024-2024.
|
|
48
|
-
* Author Peter Placzek (tada5hi)
|
|
49
|
-
* For the full copyright and license information,
|
|
50
|
-
* view the LICENSE file that was distributed with this source code.
|
|
51
|
-
*/ var BuiltInPolicyType = /*#__PURE__*/ function(BuiltInPolicyType) {
|
|
52
|
-
/**
|
|
53
|
-
* Bundles different policies.
|
|
54
|
-
*/ BuiltInPolicyType["COMPOSITE"] = "composite";
|
|
55
|
-
/**
|
|
56
|
-
* Date Based Access Control (DBAC)
|
|
57
|
-
*/ BuiltInPolicyType["DATE"] = "date";
|
|
58
|
-
/**
|
|
59
|
-
* Time Based Access Control (TBAC)
|
|
60
|
-
*/ BuiltInPolicyType["TIME"] = "time";
|
|
61
|
-
/**
|
|
62
|
-
* Attribute Name Based Access Control (ANBAC)
|
|
63
|
-
*/ BuiltInPolicyType["ATTRIBUTE_NAMES"] = "attributeNames";
|
|
64
|
-
/**
|
|
65
|
-
* Attribute Based Access Control (ABAC)
|
|
66
|
-
*/ BuiltInPolicyType["ATTRIBUTES"] = "attributes";
|
|
67
|
-
/**
|
|
68
|
-
* Realm of Identity is for attribute realm.
|
|
69
|
-
*/ BuiltInPolicyType["REALM_MATCH"] = "realmMatch";
|
|
70
|
-
/**
|
|
71
|
-
* Restriction based on identity (type, id, ...)
|
|
72
|
-
*/ BuiltInPolicyType["IDENTITY"] = "identity";
|
|
73
|
-
/**
|
|
74
|
-
* Restriction based on a binding between identity <-> permission
|
|
75
|
-
*/ BuiltInPolicyType["PERMISSION_BINDING"] = "permissionBinding";
|
|
76
|
-
return BuiltInPolicyType;
|
|
77
|
-
}({});
|
|
78
|
-
|
|
79
|
-
class AttributeNamesPolicyValidator extends validup.Container {
|
|
80
|
-
initialize() {
|
|
81
|
-
super.initialize();
|
|
82
|
-
this.mount('names', adapterZod.createValidator(zod.z.array(zod.z.string().min(3).max(128))));
|
|
83
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
class AttributeNamesPolicyEvaluator {
|
|
88
|
-
async can(ctx) {
|
|
89
|
-
return ctx.config.type === BuiltInPolicyType.ATTRIBUTE_NAMES;
|
|
90
|
-
}
|
|
91
|
-
async validateConfig(ctx) {
|
|
92
|
-
return this.validator.run(ctx.config);
|
|
93
|
-
}
|
|
94
|
-
async validateInput(ctx) {
|
|
95
|
-
if (!kit.isObject(ctx.input.attributes)) {
|
|
96
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
97
|
-
}
|
|
98
|
-
return ctx.input;
|
|
99
|
-
}
|
|
100
|
-
async evaluate(ctx) {
|
|
101
|
-
if (!ctx.input.attributes) {
|
|
102
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
103
|
-
}
|
|
104
|
-
const attributes = kit.flattenObject(ctx.input.attributes);
|
|
105
|
-
const keys = Object.keys(attributes);
|
|
106
|
-
for(let i = 0; i < keys.length; i++){
|
|
107
|
-
const index = ctx.config.names.indexOf(keys[i]);
|
|
108
|
-
if (index === -1) {
|
|
109
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
113
|
-
}
|
|
114
|
-
constructor(){
|
|
115
|
-
this.validator = new AttributeNamesPolicyValidator();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/*
|
|
120
|
-
* Copyright (c) 2025.
|
|
121
|
-
* Author Peter Placzek (tada5hi)
|
|
122
|
-
* For the full copyright and license information,
|
|
123
|
-
* view the LICENSE file that was distributed with this source code.
|
|
124
|
-
*/ function defineAttributesPolicy(data) {
|
|
125
|
-
return data;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
class AttributesPolicyValidator extends validup.Container {
|
|
129
|
-
initialize() {
|
|
130
|
-
super.initialize();
|
|
131
|
-
this.mount('query', adapterZod.createValidator(zod.z.object({}).passthrough()));
|
|
132
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
class AttributesPolicyEvaluator {
|
|
137
|
-
async can(ctx) {
|
|
138
|
-
return ctx.config.type === BuiltInPolicyType.ATTRIBUTES;
|
|
139
|
-
}
|
|
140
|
-
async validateConfig(ctx) {
|
|
141
|
-
return this.validator.run(ctx.config);
|
|
142
|
-
}
|
|
143
|
-
async validateInput(ctx) {
|
|
144
|
-
if (!kit.isObject(ctx.input.attributes)) {
|
|
145
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
146
|
-
}
|
|
147
|
-
return ctx.input;
|
|
148
|
-
}
|
|
149
|
-
async evaluate(ctx) {
|
|
150
|
-
if (!ctx.input.attributes) {
|
|
151
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
152
|
-
}
|
|
153
|
-
this.fixQuery(ctx.config.query);
|
|
154
|
-
const testIt = mongo2js.guard(ctx.config.query);
|
|
155
|
-
return maybeInvertPolicyOutcome(testIt(ctx.input.attributes), ctx.config.invert);
|
|
156
|
-
}
|
|
157
|
-
fixQuery(query) {
|
|
158
|
-
const keys = Object.keys(query);
|
|
159
|
-
for(let i = 0; i < keys.length; i++){
|
|
160
|
-
const key = keys[i];
|
|
161
|
-
const value = query[key];
|
|
162
|
-
if (kit.isObject(value) || Array.isArray(value)) {
|
|
163
|
-
this.fixQuery(value);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (key === '$regex' && typeof value === 'string') {
|
|
167
|
-
const fragments = value.match(/\/(.*?)\/([a-z]*)?$/i);
|
|
168
|
-
if (fragments) {
|
|
169
|
-
query[key] = new RegExp(fragments[1], fragments[2]);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
constructor(){
|
|
175
|
-
this.validator = new AttributesPolicyValidator();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/*
|
|
180
|
-
* Copyright (c) 2024-2024.
|
|
181
|
-
* Author Peter Placzek (tada5hi)
|
|
182
|
-
* For the full copyright and license information,
|
|
183
|
-
* view the LICENSE file that was distributed with this source code.
|
|
184
|
-
*/ var DecisionStrategy = /*#__PURE__*/ function(DecisionStrategy) {
|
|
185
|
-
/**
|
|
186
|
-
* One or more positive
|
|
187
|
-
*/ DecisionStrategy["AFFIRMATIVE"] = "affirmative";
|
|
188
|
-
/**
|
|
189
|
-
* All positive
|
|
190
|
-
*/ DecisionStrategy["UNANIMOUS"] = "unanimous";
|
|
191
|
-
/**
|
|
192
|
-
* More positive than negative
|
|
193
|
-
*/ DecisionStrategy["CONSENSUS"] = "consensus";
|
|
194
|
-
return DecisionStrategy;
|
|
195
|
-
}({});
|
|
196
|
-
|
|
197
|
-
class PolicyDataIdentityValidator extends validup.Container {
|
|
198
|
-
initialize() {
|
|
199
|
-
super.initialize();
|
|
200
|
-
this.mount('type', adapterZod.createValidator(zod.z.string().min(3).max(128)));
|
|
201
|
-
this.mount('id', adapterZod.createValidator(zod.z.string().uuid()));
|
|
202
|
-
this.mount('clientId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
203
|
-
this.mount('realmId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
204
|
-
this.mount('realmName', adapterZod.createValidator(zod.z.string().min(3).max(128).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
class PolicyDataPermissionValidator extends validup.Container {
|
|
209
|
-
initialize() {
|
|
210
|
-
super.initialize();
|
|
211
|
-
this.mount('name', adapterZod.createValidator(zod.z.string().min(3).max(256)));
|
|
212
|
-
this.mount('clientId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
213
|
-
this.mount('realmId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
214
|
-
this.mount('policy', adapterZod.createValidator(zod.z.object({
|
|
215
|
-
type: zod.z.string()
|
|
216
|
-
}).optional()));
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
class PolicyDataValidator extends validup.Container {
|
|
221
|
-
initialize() {
|
|
222
|
-
super.initialize();
|
|
223
|
-
// todo: optionalValue should be null
|
|
224
|
-
const identity = new PolicyDataIdentityValidator();
|
|
225
|
-
this.mount('identity', {
|
|
226
|
-
optional: true,
|
|
227
|
-
optionalValue: 'undefined',
|
|
228
|
-
optionalInclude: true
|
|
229
|
-
}, identity);
|
|
230
|
-
// todo: optionalValue should be null
|
|
231
|
-
const permission = new PolicyDataPermissionValidator();
|
|
232
|
-
this.mount('permission', {
|
|
233
|
-
optional: true,
|
|
234
|
-
optionalValue: 'undefined',
|
|
235
|
-
optionalInclude: true
|
|
236
|
-
}, permission);
|
|
237
|
-
this.mount('attributes', adapterZod.createValidator(zod.z.object({}).optional()));
|
|
238
|
-
this.mount('dateTime', adapterZod.createValidator(zod.z.date().or(zod.z.string()).or(zod.z.number()).optional()));
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async function evaluatePolicy(ctx) {
|
|
243
|
-
if (ctx.options.exclude && ctx.options.exclude.length > 0 && ctx.options.exclude.indexOf(ctx.config.type) !== -1) {
|
|
244
|
-
if (typeof ctx.config.invert === 'boolean') {
|
|
245
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
246
|
-
}
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
if (ctx.options.include && ctx.options.include.length > 0 && ctx.options.include.indexOf(ctx.config.type) === -1) {
|
|
250
|
-
if (typeof ctx.config.invert === 'boolean') {
|
|
251
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
252
|
-
}
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
const evaluator = ctx.evaluators[ctx.config.type];
|
|
256
|
-
if (!evaluator) {
|
|
257
|
-
throw PolicyError.evaluatorNotFound(ctx.config.type);
|
|
258
|
-
}
|
|
259
|
-
try {
|
|
260
|
-
const canEvaluate = await evaluator.can(ctx);
|
|
261
|
-
if (canEvaluate) {
|
|
262
|
-
const config = await evaluator.validateConfig(ctx);
|
|
263
|
-
const input = await evaluator.validateInput(ctx);
|
|
264
|
-
return await evaluator.evaluate({
|
|
265
|
-
...ctx,
|
|
266
|
-
input,
|
|
267
|
-
config
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
} catch (e) {
|
|
271
|
-
if (e instanceof PolicyError) {
|
|
272
|
-
throw e;
|
|
273
|
-
}
|
|
274
|
-
if (e instanceof Error) {
|
|
275
|
-
const error = new PolicyError(e.message);
|
|
276
|
-
error.stack = e.stack;
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
throw new PolicyError();
|
|
280
|
-
}
|
|
281
|
-
throw PolicyError.evaluatorNotProcessable();
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function isCompositePolicy(input) {
|
|
285
|
-
return input.type === BuiltInPolicyType.COMPOSITE;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
class CompositePolicyValidator extends validup.Container {
|
|
289
|
-
initialize() {
|
|
290
|
-
super.initialize();
|
|
291
|
-
this.mount('decisionStrategy', adapterZod.createValidator(zod.z.nativeEnum(DecisionStrategy).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
292
|
-
this.mount('children', adapterZod.createValidator(zod.z.array(zod.z.object({
|
|
293
|
-
type: zod.z.string().min(3)
|
|
294
|
-
}).passthrough())));
|
|
295
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
class CompositePolicyEvaluator {
|
|
300
|
-
async can(ctx) {
|
|
301
|
-
return isCompositePolicy(ctx.config);
|
|
302
|
-
}
|
|
303
|
-
async validateConfig(ctx) {
|
|
304
|
-
return this.validator.run(ctx.config);
|
|
305
|
-
}
|
|
306
|
-
async validateInput(ctx) {
|
|
307
|
-
return ctx.input;
|
|
308
|
-
}
|
|
309
|
-
async evaluate(ctx) {
|
|
310
|
-
let count = 0;
|
|
311
|
-
const decisionStrategy = ctx.config.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
|
|
312
|
-
for(let i = 0; i < ctx.config.children.length; i++){
|
|
313
|
-
const childPolicy = ctx.config.children[i];
|
|
314
|
-
let outcome;
|
|
315
|
-
if (isCompositePolicy(childPolicy)) {
|
|
316
|
-
outcome = await this.evaluate({
|
|
317
|
-
...ctx,
|
|
318
|
-
config: childPolicy
|
|
319
|
-
});
|
|
320
|
-
} else {
|
|
321
|
-
outcome = await evaluatePolicy({
|
|
322
|
-
...ctx,
|
|
323
|
-
config: childPolicy
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
if (outcome) {
|
|
327
|
-
if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
|
|
328
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
329
|
-
}
|
|
330
|
-
count++;
|
|
331
|
-
} else {
|
|
332
|
-
if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
|
|
333
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
334
|
-
}
|
|
335
|
-
count--;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return maybeInvertPolicyOutcome(count > 0, ctx.config.invert);
|
|
339
|
-
}
|
|
340
|
-
constructor(){
|
|
341
|
-
this.validator = new CompositePolicyValidator();
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
class DatePolicyValidator extends validup.Container {
|
|
346
|
-
initialize() {
|
|
347
|
-
super.initialize();
|
|
348
|
-
this.mount('start', adapterZod.createValidator(zod.z.date().or(zod.z.string().date()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
349
|
-
this.mount('end', adapterZod.createValidator(zod.z.date().or(zod.z.string().date()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
350
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.undefined()).or(zod.z.null()).optional()));
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
function normalizeDate$1(input) {
|
|
355
|
-
return new Date(input.getFullYear(), input.getMonth(), input.getDate());
|
|
356
|
-
}
|
|
357
|
-
function toDate$1(input) {
|
|
358
|
-
if (typeof input === 'string') {
|
|
359
|
-
return new Date(input);
|
|
360
|
-
}
|
|
361
|
-
if (typeof input === 'number') {
|
|
362
|
-
return new Date(input);
|
|
363
|
-
}
|
|
364
|
-
return input;
|
|
365
|
-
}
|
|
366
|
-
class DatePolicyEvaluator {
|
|
367
|
-
async can(ctx) {
|
|
368
|
-
return ctx.config.type === BuiltInPolicyType.DATE;
|
|
369
|
-
}
|
|
370
|
-
async validateConfig(ctx) {
|
|
371
|
-
return this.validator.run(ctx.config);
|
|
372
|
-
}
|
|
373
|
-
async validateInput(ctx) {
|
|
374
|
-
return ctx.input;
|
|
375
|
-
}
|
|
376
|
-
async evaluate(ctx) {
|
|
377
|
-
let now;
|
|
378
|
-
if (ctx.input.dateTime) {
|
|
379
|
-
now = normalizeDate$1(toDate$1(ctx.input.dateTime));
|
|
380
|
-
} else {
|
|
381
|
-
now = normalizeDate$1(new Date());
|
|
382
|
-
}
|
|
383
|
-
if (ctx.config.start) {
|
|
384
|
-
const start = normalizeDate$1(toDate$1(ctx.config.start));
|
|
385
|
-
if (now < start) {
|
|
386
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
if (ctx.config.end) {
|
|
390
|
-
const end = normalizeDate$1(toDate$1(ctx.config.end));
|
|
391
|
-
if (now > end) {
|
|
392
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
396
|
-
}
|
|
397
|
-
constructor(){
|
|
398
|
-
this.validator = new DatePolicyValidator();
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
class IdentityPolicyValidator extends validup.Container {
|
|
403
|
-
initialize() {
|
|
404
|
-
this.mount('types', adapterZod.createValidator(zod.z.array(zod.z.string()).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
405
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
class IdentityPolicyEvaluator {
|
|
410
|
-
async can(ctx) {
|
|
411
|
-
return ctx.config.type === BuiltInPolicyType.IDENTITY;
|
|
412
|
-
}
|
|
413
|
-
async validateConfig(ctx) {
|
|
414
|
-
return this.validator.run(ctx.config);
|
|
415
|
-
}
|
|
416
|
-
async validateInput(ctx) {
|
|
417
|
-
return ctx.input;
|
|
418
|
-
}
|
|
419
|
-
async evaluate(ctx) {
|
|
420
|
-
if (!kit.isObject(ctx.input.identity)) {
|
|
421
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
422
|
-
}
|
|
423
|
-
const types = ctx.config.types || [];
|
|
424
|
-
if (types.length === 0) {
|
|
425
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
426
|
-
}
|
|
427
|
-
const typeAllowed = types.indexOf(ctx.input.identity.type) !== -1;
|
|
428
|
-
return maybeInvertPolicyOutcome(typeAllowed, ctx.config.invert);
|
|
429
|
-
}
|
|
430
|
-
constructor(){
|
|
431
|
-
this.validator = new IdentityPolicyValidator();
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
class PermissionBindingPolicyValidator extends validup.Container {
|
|
436
|
-
initialize() {}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
class PermissionBindingPolicyEvaluator {
|
|
440
|
-
async can(ctx) {
|
|
441
|
-
return ctx.config.type === BuiltInPolicyType.PERMISSION_BINDING;
|
|
442
|
-
}
|
|
443
|
-
async validateConfig(ctx) {
|
|
444
|
-
return this.validator.run(ctx.config);
|
|
445
|
-
}
|
|
446
|
-
async validateInput(ctx) {
|
|
447
|
-
if (!kit.isObject(ctx.input.identity) && !kit.isObject(ctx.input.permission)) {
|
|
448
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
449
|
-
}
|
|
450
|
-
return ctx.input;
|
|
451
|
-
}
|
|
452
|
-
async evaluate(ctx) {
|
|
453
|
-
// todo: this must be changed when the permission-checker not only checks owned permissions.
|
|
454
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
455
|
-
}
|
|
456
|
-
constructor(){
|
|
457
|
-
this.validator = new PermissionBindingPolicyValidator();
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
class RealmMatchPolicyValidator extends validup.Container {
|
|
462
|
-
initialize() {
|
|
463
|
-
super.initialize();
|
|
464
|
-
this.mount('decisionStrategy', adapterZod.createValidator(zod.z.nativeEnum(DecisionStrategy).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
465
|
-
this.mount('attributeName', adapterZod.createValidator(zod.z.string().min(3).or(zod.z.array(zod.z.string().min(3))).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
466
|
-
this.mount('attributeNameStrict', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
467
|
-
this.mount('attributeNullMatchAll', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
468
|
-
this.mount('identityMasterMatchAll', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
469
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
class RealmMatchPolicyEvaluator {
|
|
474
|
-
async can(ctx) {
|
|
475
|
-
return ctx.config.type === BuiltInPolicyType.REALM_MATCH;
|
|
476
|
-
}
|
|
477
|
-
async validateConfig(ctx) {
|
|
478
|
-
return this.validator.run(ctx.config);
|
|
479
|
-
}
|
|
480
|
-
async validateInput(ctx) {
|
|
481
|
-
if (!kit.isObject(ctx.input.attributes) || !kit.isObject(ctx.input.identity)) {
|
|
482
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
483
|
-
}
|
|
484
|
-
return ctx.input;
|
|
485
|
-
}
|
|
486
|
-
async evaluate(ctx) {
|
|
487
|
-
if (!ctx.input.attributes || !ctx.input.identity) {
|
|
488
|
-
throw PolicyError.evaluatorContextInvalid();
|
|
489
|
-
}
|
|
490
|
-
const identityMasterMatchAll = ctx.config.identityMasterMatchAll ?? true;
|
|
491
|
-
if (identityMasterMatchAll && ctx.input.identity.realmName && ctx.input.identity.realmName === 'master') {
|
|
492
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
493
|
-
}
|
|
494
|
-
let keys;
|
|
495
|
-
if (ctx.config.attributeName) {
|
|
496
|
-
if (Array.isArray(ctx.config.attributeName)) {
|
|
497
|
-
keys = ctx.config.attributeName;
|
|
498
|
-
} else {
|
|
499
|
-
keys = [
|
|
500
|
-
ctx.config.attributeName
|
|
501
|
-
];
|
|
502
|
-
}
|
|
503
|
-
} else {
|
|
504
|
-
keys = [
|
|
505
|
-
'realm_id',
|
|
506
|
-
'realm_name',
|
|
507
|
-
'realmId',
|
|
508
|
-
'realmName'
|
|
509
|
-
];
|
|
510
|
-
ctx.config.decisionStrategy = DecisionStrategy.CONSENSUS;
|
|
511
|
-
}
|
|
512
|
-
const attributeNameStrict = ctx.config.attributeNameStrict ?? true;
|
|
513
|
-
if (!attributeNameStrict) {
|
|
514
|
-
const resourceKeys = Object.keys(ctx.input.attributes);
|
|
515
|
-
const keysToAdd = [];
|
|
516
|
-
for(let i = 0; i < resourceKeys.length; i++){
|
|
517
|
-
let contains = false;
|
|
518
|
-
for(let j = 0; j < keys.length; j++){
|
|
519
|
-
if (resourceKeys[i] !== keys[j] && resourceKeys[i].includes(keys[j])) {
|
|
520
|
-
contains = true;
|
|
521
|
-
break;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (contains) {
|
|
525
|
-
keysToAdd.push(resourceKeys[i]);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
if (keysToAdd.length > 0) {
|
|
529
|
-
keys.push(...keysToAdd);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
let count = 0;
|
|
533
|
-
for(let i = 0; i < keys.length; i++){
|
|
534
|
-
if (!kit.hasOwnProperty(ctx.input.attributes, keys[i])) {
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
|
-
let outcome = false;
|
|
538
|
-
const attributeValue = ctx.input.attributes[keys[i]];
|
|
539
|
-
if (attributeValue === null && ctx.config.attributeNullMatchAll) {
|
|
540
|
-
outcome = true;
|
|
541
|
-
} else if (attributeValue === ctx.input.identity.realmId || attributeValue === ctx.input.identity.realmName) {
|
|
542
|
-
outcome = true;
|
|
543
|
-
}
|
|
544
|
-
if (outcome) {
|
|
545
|
-
if (ctx.config.decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
|
|
546
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
547
|
-
}
|
|
548
|
-
count++;
|
|
549
|
-
} else {
|
|
550
|
-
if (ctx.config.decisionStrategy === DecisionStrategy.UNANIMOUS) {
|
|
551
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
552
|
-
}
|
|
553
|
-
count--;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
return maybeInvertPolicyOutcome(count > 0, ctx.config.invert);
|
|
557
|
-
}
|
|
558
|
-
constructor(){
|
|
559
|
-
this.validator = new RealmMatchPolicyValidator();
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/*
|
|
564
|
-
* Copyright (c) 2024-2024.
|
|
565
|
-
* Author Peter Placzek (tada5hi)
|
|
566
|
-
* For the full copyright and license information,
|
|
567
|
-
* view the LICENSE file that was distributed with this source code.
|
|
568
|
-
*/ var TimePolicyInterval = /*#__PURE__*/ function(TimePolicyInterval) {
|
|
569
|
-
TimePolicyInterval["DAILY"] = "daily";
|
|
570
|
-
TimePolicyInterval["WEEKLY"] = "weekly";
|
|
571
|
-
TimePolicyInterval["MONTHLY"] = "monthly";
|
|
572
|
-
TimePolicyInterval["YEARLY"] = "yearly";
|
|
573
|
-
return TimePolicyInterval;
|
|
574
|
-
}({});
|
|
575
|
-
|
|
576
|
-
function isIntervalForDayOfWeek(interval) {
|
|
577
|
-
return interval === TimePolicyInterval.WEEKLY || interval === TimePolicyInterval.MONTHLY || interval === TimePolicyInterval.YEARLY;
|
|
578
|
-
}
|
|
579
|
-
function isIntervalForDayOfMonth(interval) {
|
|
580
|
-
return interval === TimePolicyInterval.MONTHLY || interval === TimePolicyInterval.YEARLY;
|
|
581
|
-
}
|
|
582
|
-
function isIntervalForDayOfYear(interval) {
|
|
583
|
-
return interval === TimePolicyInterval.YEARLY;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
class TimePolicyValidator extends validup.Container {
|
|
587
|
-
initialize() {
|
|
588
|
-
super.initialize();
|
|
589
|
-
this.mount('dayOfWeek', adapterZod.createValidator(zod.z.number().min(0).max(6).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
590
|
-
this.mount('dayOfMonth', adapterZod.createValidator(zod.z.number().min(1).max(31).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
591
|
-
this.mount('dayOfYear', adapterZod.createValidator(zod.z.number().min(1).max(366).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
592
|
-
this.mount('start', adapterZod.createValidator(zod.z.date().or(zod.z.string().datetime()).or(zod.z.string().time()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
593
|
-
this.mount('end', adapterZod.createValidator(zod.z.date().or(zod.z.string().datetime()).or(zod.z.string().time()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
594
|
-
this.mount('interval', adapterZod.createValidator(zod.z.nativeEnum(TimePolicyInterval).or(zod.z.null()).or(zod.z.undefined()).optional()));
|
|
595
|
-
this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.undefined()).or(zod.z.null()).optional()));
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
const timeRegex = /^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/;
|
|
600
|
-
function normalizeDate(input, dateRef) {
|
|
601
|
-
const date = dateRef ? new Date(dateRef) : new Date();
|
|
602
|
-
date.setHours(input.getHours(), input.getMinutes());
|
|
603
|
-
return date;
|
|
604
|
-
}
|
|
605
|
-
function toDate(input, dateRef) {
|
|
606
|
-
if (typeof input === 'string') {
|
|
607
|
-
if (timeRegex.test(input)) {
|
|
608
|
-
const [startHours, startMinutes] = input.split(':').map(Number);
|
|
609
|
-
const date = dateRef ? new Date(dateRef) : new Date();
|
|
610
|
-
date.setHours(startHours, startMinutes);
|
|
611
|
-
return date;
|
|
612
|
-
}
|
|
613
|
-
return new Date(input);
|
|
614
|
-
}
|
|
615
|
-
if (typeof input === 'number') {
|
|
616
|
-
return new Date(input);
|
|
617
|
-
}
|
|
618
|
-
return input;
|
|
619
|
-
}
|
|
620
|
-
class TimePolicyEvaluator {
|
|
621
|
-
async can(ctx) {
|
|
622
|
-
return ctx.config.type === BuiltInPolicyType.TIME;
|
|
623
|
-
}
|
|
624
|
-
async validateConfig(ctx) {
|
|
625
|
-
return this.validator.run(ctx.config);
|
|
626
|
-
}
|
|
627
|
-
async validateInput(ctx) {
|
|
628
|
-
return ctx.input;
|
|
629
|
-
}
|
|
630
|
-
async evaluate(ctx) {
|
|
631
|
-
let now;
|
|
632
|
-
if (ctx.input.dateTime) {
|
|
633
|
-
now = toDate(ctx.input.dateTime);
|
|
634
|
-
} else {
|
|
635
|
-
now = new Date();
|
|
636
|
-
}
|
|
637
|
-
if (ctx.config.start) {
|
|
638
|
-
const start = normalizeDate(toDate(ctx.config.start, now), now);
|
|
639
|
-
if (now < start) {
|
|
640
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
if (ctx.config.end) {
|
|
644
|
-
const end = normalizeDate(toDate(ctx.config.end, now), now);
|
|
645
|
-
if (now > end) {
|
|
646
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
if (ctx.config.interval) {
|
|
650
|
-
if (isIntervalForDayOfWeek(ctx.config.interval) && ctx.config.dayOfWeek) {
|
|
651
|
-
if (now.getDay() !== ctx.config.dayOfWeek) {
|
|
652
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
if (isIntervalForDayOfMonth(ctx.config.interval) && ctx.config.dayOfMonth) {
|
|
656
|
-
if (now.getDate() !== ctx.config.dayOfMonth) {
|
|
657
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
if (isIntervalForDayOfYear(ctx.config.interval) && ctx.config.dayOfYear) {
|
|
661
|
-
const start = new Date(now.getFullYear(), 0, 0);
|
|
662
|
-
const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
|
|
663
|
-
const oneDay = 1000 * 60 * 60 * 24;
|
|
664
|
-
const dayOfYear = Math.floor(diff / oneDay);
|
|
665
|
-
if (dayOfYear !== ctx.config.dayOfYear) {
|
|
666
|
-
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
671
|
-
}
|
|
672
|
-
constructor(){
|
|
673
|
-
this.validator = new TimePolicyValidator();
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
/*
|
|
678
|
-
* Copyright (c) 2025.
|
|
679
|
-
* Author Peter Placzek (tada5hi)
|
|
680
|
-
* For the full copyright and license information,
|
|
681
|
-
* view the LICENSE file that was distributed with this source code.
|
|
682
|
-
*/ function definePolicyWithType(type, data) {
|
|
683
|
-
return {
|
|
684
|
-
...data,
|
|
685
|
-
type
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
/**
|
|
690
|
-
* The policy engine is a component that interprets defined policies and makes decisions
|
|
691
|
-
* on whether to allow or deny a particular access.
|
|
692
|
-
*/ class PolicyEngine {
|
|
693
|
-
registerEvaluator(type, evaluator) {
|
|
694
|
-
this.evaluators[type] = evaluator;
|
|
695
|
-
}
|
|
696
|
-
registerEvaluators(evaluators) {
|
|
697
|
-
const keys = Object.keys(evaluators);
|
|
698
|
-
for(let i = 0; i < keys.length; i++){
|
|
699
|
-
this.registerEvaluator(keys[i], evaluators[keys[i]]);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
registerDefaultEvaluators() {
|
|
703
|
-
this.registerEvaluator(BuiltInPolicyType.COMPOSITE, new CompositePolicyEvaluator());
|
|
704
|
-
this.registerEvaluator(BuiltInPolicyType.ATTRIBUTES, new AttributesPolicyEvaluator());
|
|
705
|
-
this.registerEvaluator(BuiltInPolicyType.ATTRIBUTE_NAMES, new AttributeNamesPolicyEvaluator());
|
|
706
|
-
this.registerEvaluator(BuiltInPolicyType.DATE, new DatePolicyEvaluator());
|
|
707
|
-
this.registerEvaluator(BuiltInPolicyType.IDENTITY, new IdentityPolicyEvaluator());
|
|
708
|
-
this.registerEvaluator(BuiltInPolicyType.PERMISSION_BINDING, new PermissionBindingPolicyEvaluator());
|
|
709
|
-
this.registerEvaluator(BuiltInPolicyType.REALM_MATCH, new RealmMatchPolicyEvaluator());
|
|
710
|
-
this.registerEvaluator(BuiltInPolicyType.TIME, new TimePolicyEvaluator());
|
|
711
|
-
}
|
|
712
|
-
/**
|
|
713
|
-
* @throws PolicyError
|
|
714
|
-
*
|
|
715
|
-
* @param ctx
|
|
716
|
-
*/ async evaluate(ctx) {
|
|
717
|
-
return evaluatePolicy({
|
|
718
|
-
...ctx,
|
|
719
|
-
options: ctx.options || {},
|
|
720
|
-
evaluators: this.evaluators
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
constructor(evaluators = {}){
|
|
724
|
-
this.evaluators = {};
|
|
725
|
-
this.registerDefaultEvaluators();
|
|
726
|
-
this.registerEvaluators(evaluators);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
class PermissionError extends errors.AuthupError {
|
|
731
|
-
static notFound(name) {
|
|
732
|
-
return new PermissionError({
|
|
733
|
-
message: `The permission ${name} was not found.`,
|
|
734
|
-
code: errors.ErrorCode.PERMISSION_NOT_FOUND
|
|
735
|
-
});
|
|
736
|
-
}
|
|
737
|
-
static denied(name) {
|
|
738
|
-
return new PermissionError({
|
|
739
|
-
message: `The permission ${name} has not been granted.`,
|
|
740
|
-
code: errors.ErrorCode.PERMISSION_DENIED
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
static deniedAll(names) {
|
|
744
|
-
return new PermissionError({
|
|
745
|
-
message: `None of the permissions ${names.join(', ')} has been granted.`,
|
|
746
|
-
code: errors.ErrorCode.PERMISSION_DENIED
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
static evaluationFailed(options) {
|
|
750
|
-
const error = new PermissionError({
|
|
751
|
-
message: `The evaluation of permission ${options.name} failed.`,
|
|
752
|
-
code: errors.ErrorCode.PERMISSION_EVALUATION_FAILED
|
|
753
|
-
});
|
|
754
|
-
if (options.policy) {
|
|
755
|
-
error.policy = options.policy;
|
|
756
|
-
if (options.policy.type === BuiltInPolicyType.IDENTITY) {
|
|
757
|
-
error.statusCode = 401;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
if (options.policyError) {
|
|
761
|
-
error.policyError = options.policyError;
|
|
762
|
-
}
|
|
763
|
-
return error;
|
|
764
|
-
}
|
|
765
|
-
constructor(options = {}){
|
|
766
|
-
super({
|
|
767
|
-
...options,
|
|
768
|
-
message: options.message || 'A permission error occurred.',
|
|
769
|
-
statusCode: options.statusCode || 403
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
/*
|
|
775
|
-
* Copyright (c) 2025.
|
|
776
|
-
* Author Peter Placzek (tada5hi)
|
|
777
|
-
* For the full copyright and license information,
|
|
778
|
-
* view the LICENSE file that was distributed with this source code.
|
|
779
|
-
*/ function buildPermissionItemKey(input) {
|
|
780
|
-
return `${input.realmId || '_'}/${input.clientId || '_'}/${input.name}`;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
/*
|
|
784
|
-
* Copyright (c) 2024-2024.
|
|
785
|
-
* Author Peter Placzek (tada5hi)
|
|
786
|
-
* For the full copyright and license information,
|
|
787
|
-
* view the LICENSE file that was distributed with this source code.
|
|
788
|
-
*/ function isPermissionItemEqual(a, b) {
|
|
789
|
-
if (a.name !== b.name) {
|
|
790
|
-
return false;
|
|
791
|
-
}
|
|
792
|
-
if (typeof a.realmId === 'string' || typeof b.realmId === 'string') {
|
|
793
|
-
return a.realmId === b.realmId;
|
|
794
|
-
}
|
|
795
|
-
if (typeof a.clientId === 'string' || typeof b.clientId === 'string') {
|
|
796
|
-
return a.clientId === b.clientId;
|
|
797
|
-
}
|
|
798
|
-
return !!a.realmId === !!b.realmId && !!a.clientId === !!b.clientId;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
function mergePermissionItems(input) {
|
|
802
|
-
const grouped = input.reduce((previous, current)=>{
|
|
803
|
-
const key = buildPermissionItemKey(current);
|
|
804
|
-
if (!previous[key]) {
|
|
805
|
-
previous[key] = [];
|
|
806
|
-
}
|
|
807
|
-
previous[key].push(current);
|
|
808
|
-
return previous;
|
|
809
|
-
}, {});
|
|
810
|
-
const output = [];
|
|
811
|
-
const keys = Object.keys(grouped);
|
|
812
|
-
for(let i = 0; i < keys.length; i++){
|
|
813
|
-
const [permission, ...permissions] = grouped[keys[i]];
|
|
814
|
-
if (permissions.length > 0) {
|
|
815
|
-
const policy = {
|
|
816
|
-
type: BuiltInPolicyType.COMPOSITE,
|
|
817
|
-
decisionStrategy: DecisionStrategy.AFFIRMATIVE,
|
|
818
|
-
children: permissions.map((el)=>el.policy).filter((el)=>typeof el !== 'undefined')
|
|
819
|
-
};
|
|
820
|
-
if (permission.policy) {
|
|
821
|
-
policy.children.push(permission.policy);
|
|
822
|
-
}
|
|
823
|
-
if (policy.children.length > 0) {
|
|
824
|
-
permission.policy = policy;
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
output.push(permission);
|
|
828
|
-
}
|
|
829
|
-
return output;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
class PermissionMemoryProvider {
|
|
833
|
-
async get(options) {
|
|
834
|
-
return this.items[buildPermissionItemKey(options)];
|
|
835
|
-
}
|
|
836
|
-
setMany(input) {
|
|
837
|
-
this.items = mergePermissionItems(input).reduce((prev, current)=>{
|
|
838
|
-
prev[buildPermissionItemKey(current)] = current;
|
|
839
|
-
return prev;
|
|
840
|
-
}, {});
|
|
841
|
-
}
|
|
842
|
-
constructor(items = []){
|
|
843
|
-
this.items = {};
|
|
844
|
-
this.setMany(items);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
class PermissionChecker {
|
|
849
|
-
// ----------------------------------------------
|
|
850
|
-
/**
|
|
851
|
-
* Get a permission.
|
|
852
|
-
*
|
|
853
|
-
* @param input
|
|
854
|
-
*/ async get(input) {
|
|
855
|
-
const options = {
|
|
856
|
-
name: input
|
|
857
|
-
};
|
|
858
|
-
if (this.clientId) {
|
|
859
|
-
options.clientId = this.clientId;
|
|
860
|
-
}
|
|
861
|
-
if (this.realmId) {
|
|
862
|
-
options.realmId = this.realmId;
|
|
863
|
-
}
|
|
864
|
-
return this.provider.get(options);
|
|
865
|
-
}
|
|
866
|
-
// ----------------------------------------------
|
|
867
|
-
/**
|
|
868
|
-
* Verify if one or more possible owned permissions satisfy their conditions.
|
|
869
|
-
*
|
|
870
|
-
* @throws PermissionError
|
|
871
|
-
*
|
|
872
|
-
* @param ctx
|
|
873
|
-
*/ async check(ctx) {
|
|
874
|
-
if (!Array.isArray(ctx.name)) {
|
|
875
|
-
await this.check({
|
|
876
|
-
...ctx,
|
|
877
|
-
name: [
|
|
878
|
-
ctx.name
|
|
879
|
-
]
|
|
880
|
-
});
|
|
881
|
-
return;
|
|
882
|
-
}
|
|
883
|
-
const { options = {} } = ctx;
|
|
884
|
-
const decisionStrategy = options.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
|
|
885
|
-
let lastError;
|
|
886
|
-
let count = 0;
|
|
887
|
-
for(let i = 0; i < ctx.name.length; i++){
|
|
888
|
-
const entity = await this.get(ctx.name[i]);
|
|
889
|
-
if (!entity) {
|
|
890
|
-
lastError = PermissionError.notFound(ctx.name[i]);
|
|
891
|
-
if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
|
|
892
|
-
throw lastError;
|
|
893
|
-
}
|
|
894
|
-
continue;
|
|
895
|
-
}
|
|
896
|
-
if (!entity.policy) {
|
|
897
|
-
if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
|
|
898
|
-
return;
|
|
899
|
-
}
|
|
900
|
-
count++;
|
|
901
|
-
continue;
|
|
902
|
-
}
|
|
903
|
-
let outcome;
|
|
904
|
-
try {
|
|
905
|
-
outcome = await this.policyEngine.evaluate({
|
|
906
|
-
input: {
|
|
907
|
-
...ctx.input || {},
|
|
908
|
-
permission: entity
|
|
909
|
-
},
|
|
910
|
-
config: entity.policy,
|
|
911
|
-
options: {
|
|
912
|
-
include: options.policiesIncluded,
|
|
913
|
-
exclude: options.policiesExcluded
|
|
914
|
-
}
|
|
915
|
-
});
|
|
916
|
-
} catch (e) {
|
|
917
|
-
if (e instanceof PolicyError) {
|
|
918
|
-
lastError = PermissionError.evaluationFailed({
|
|
919
|
-
name: entity.name,
|
|
920
|
-
policy: entity.policy,
|
|
921
|
-
policyError: e
|
|
922
|
-
});
|
|
923
|
-
} else {
|
|
924
|
-
lastError = PermissionError.evaluationFailed({
|
|
925
|
-
name: entity.name,
|
|
926
|
-
policy: entity.policy
|
|
927
|
-
});
|
|
928
|
-
}
|
|
929
|
-
outcome = false;
|
|
930
|
-
}
|
|
931
|
-
if (outcome) {
|
|
932
|
-
if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
count++;
|
|
936
|
-
} else {
|
|
937
|
-
if (!lastError) {
|
|
938
|
-
lastError = PermissionError.evaluationFailed({
|
|
939
|
-
name: entity.name,
|
|
940
|
-
policy: entity.policy
|
|
941
|
-
});
|
|
942
|
-
}
|
|
943
|
-
if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
|
|
944
|
-
throw lastError;
|
|
945
|
-
}
|
|
946
|
-
count--;
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
if (count > 0) {
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
if (count > 1 || !lastError) {
|
|
953
|
-
throw PermissionError.deniedAll(ctx.name);
|
|
954
|
-
} else {
|
|
955
|
-
throw lastError;
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
|
-
* Verify if one of the permissions evaluates to true.
|
|
960
|
-
*
|
|
961
|
-
* @throws PermissionError
|
|
962
|
-
*
|
|
963
|
-
* @param ctx
|
|
964
|
-
*/ async checkOneOf(ctx) {
|
|
965
|
-
return this.check({
|
|
966
|
-
...ctx,
|
|
967
|
-
options: {
|
|
968
|
-
...ctx.options || {},
|
|
969
|
-
decisionStrategy: DecisionStrategy.AFFIRMATIVE
|
|
970
|
-
}
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
// ----------------------------------------------
|
|
974
|
-
async preCheck(ctx) {
|
|
975
|
-
return this.check({
|
|
976
|
-
...ctx,
|
|
977
|
-
options: {
|
|
978
|
-
...ctx.options || {},
|
|
979
|
-
policiesExcluded: [
|
|
980
|
-
BuiltInPolicyType.ATTRIBUTES,
|
|
981
|
-
BuiltInPolicyType.ATTRIBUTE_NAMES,
|
|
982
|
-
BuiltInPolicyType.REALM_MATCH
|
|
983
|
-
]
|
|
984
|
-
}
|
|
985
|
-
});
|
|
986
|
-
}
|
|
987
|
-
async preCheckOneOf(ctx) {
|
|
988
|
-
return this.preCheck({
|
|
989
|
-
...ctx,
|
|
990
|
-
options: {
|
|
991
|
-
...ctx.options || {},
|
|
992
|
-
decisionStrategy: DecisionStrategy.AFFIRMATIVE
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
}
|
|
996
|
-
// ----------------------------------------------
|
|
997
|
-
constructor(options = {}){
|
|
998
|
-
if (options.provider) {
|
|
999
|
-
this.provider = options.provider;
|
|
1000
|
-
} else {
|
|
1001
|
-
this.provider = new PermissionMemoryProvider();
|
|
1002
|
-
}
|
|
1003
|
-
if (options.clientId) {
|
|
1004
|
-
this.clientId = options.clientId;
|
|
1005
|
-
}
|
|
1006
|
-
if (options.realmId) {
|
|
1007
|
-
this.realmId = options.realmId;
|
|
1008
|
-
}
|
|
1009
|
-
if (options.policyEngine) {
|
|
1010
|
-
this.policyEngine = options.policyEngine;
|
|
1011
|
-
} else {
|
|
1012
|
-
this.policyEngine = new PolicyEngine();
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
exports.AttributeNamesPolicyEvaluator = AttributeNamesPolicyEvaluator;
|
|
1018
|
-
exports.AttributeNamesPolicyValidator = AttributeNamesPolicyValidator;
|
|
1019
|
-
exports.AttributesPolicyEvaluator = AttributesPolicyEvaluator;
|
|
1020
|
-
exports.AttributesPolicyValidator = AttributesPolicyValidator;
|
|
1021
|
-
exports.BuiltInPolicyType = BuiltInPolicyType;
|
|
1022
|
-
exports.CompositePolicyEvaluator = CompositePolicyEvaluator;
|
|
1023
|
-
exports.CompositePolicyValidator = CompositePolicyValidator;
|
|
1024
|
-
exports.DatePolicyEvaluator = DatePolicyEvaluator;
|
|
1025
|
-
exports.DatePolicyValidator = DatePolicyValidator;
|
|
1026
|
-
exports.DecisionStrategy = DecisionStrategy;
|
|
1027
|
-
exports.IdentityPolicyEvaluator = IdentityPolicyEvaluator;
|
|
1028
|
-
exports.IdentityPolicyValidator = IdentityPolicyValidator;
|
|
1029
|
-
exports.PermissionBindingPolicyEvaluator = PermissionBindingPolicyEvaluator;
|
|
1030
|
-
exports.PermissionBindingPolicyValidator = PermissionBindingPolicyValidator;
|
|
1031
|
-
exports.PermissionChecker = PermissionChecker;
|
|
1032
|
-
exports.PermissionError = PermissionError;
|
|
1033
|
-
exports.PermissionMemoryProvider = PermissionMemoryProvider;
|
|
1034
|
-
exports.PolicyDataIdentityValidator = PolicyDataIdentityValidator;
|
|
1035
|
-
exports.PolicyDataPermissionValidator = PolicyDataPermissionValidator;
|
|
1036
|
-
exports.PolicyDataValidator = PolicyDataValidator;
|
|
1037
|
-
exports.PolicyEngine = PolicyEngine;
|
|
1038
|
-
exports.PolicyError = PolicyError;
|
|
1039
|
-
exports.RealmMatchPolicyEvaluator = RealmMatchPolicyEvaluator;
|
|
1040
|
-
exports.RealmMatchPolicyValidator = RealmMatchPolicyValidator;
|
|
1041
|
-
exports.TimePolicyEvaluator = TimePolicyEvaluator;
|
|
1042
|
-
exports.TimePolicyInterval = TimePolicyInterval;
|
|
1043
|
-
exports.TimePolicyValidator = TimePolicyValidator;
|
|
1044
|
-
exports.buildPermissionItemKey = buildPermissionItemKey;
|
|
1045
|
-
exports.defineAttributesPolicy = defineAttributesPolicy;
|
|
1046
|
-
exports.definePolicyWithType = definePolicyWithType;
|
|
1047
|
-
exports.evaluatePolicy = evaluatePolicy;
|
|
1048
|
-
exports.isCompositePolicy = isCompositePolicy;
|
|
1049
|
-
exports.isIntervalForDayOfMonth = isIntervalForDayOfMonth;
|
|
1050
|
-
exports.isIntervalForDayOfWeek = isIntervalForDayOfWeek;
|
|
1051
|
-
exports.isIntervalForDayOfYear = isIntervalForDayOfYear;
|
|
1052
|
-
exports.isPermissionItemEqual = isPermissionItemEqual;
|
|
1053
|
-
exports.maybeInvertPolicyOutcome = maybeInvertPolicyOutcome;
|
|
1054
|
-
exports.mergePermissionItems = mergePermissionItems;
|
|
1055
|
-
//# sourceMappingURL=index.cjs.map
|