@authup/access 1.0.0-beta.26 → 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 +233 -210
- 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 +4 -4
- package/dist/permission/types.d.ts.map +1 -1
- package/dist/policy/built-in/attribute-names/evaluator.d.ts +4 -4
- package/dist/policy/built-in/attribute-names/evaluator.d.ts.map +1 -1
- package/dist/policy/built-in/attributes/evaluator.d.ts +4 -4
- package/dist/policy/built-in/attributes/evaluator.d.ts.map +1 -1
- package/dist/policy/built-in/composite/evaluator.d.ts +3 -3
- package/dist/policy/built-in/composite/evaluator.d.ts.map +1 -1
- package/dist/policy/built-in/date/evaluator.d.ts +3 -3
- package/dist/policy/built-in/date/evaluator.d.ts.map +1 -1
- package/dist/policy/built-in/identity/evaluator.d.ts +3 -3
- package/dist/policy/built-in/identity/evaluator.d.ts.map +1 -1
- package/dist/policy/built-in/permission-binding/module.d.ts +4 -4
- package/dist/policy/built-in/permission-binding/module.d.ts.map +1 -1
- package/dist/policy/built-in/realm-match/evaluator.d.ts +3 -3
- package/dist/policy/built-in/realm-match/evaluator.d.ts.map +1 -1
- package/dist/policy/built-in/time/evaluator.d.ts +3 -3
- package/dist/policy/built-in/time/evaluator.d.ts.map +1 -1
- package/dist/policy/error/module.d.ts +2 -2
- package/dist/policy/evaluator/data/validator.d.ts +2 -2
- package/dist/policy/evaluator/data/validator.d.ts.map +1 -1
- package/dist/policy/evaluator/types.d.ts +11 -11
- package/dist/policy/evaluator/types.d.ts.map +1 -1
- package/dist/policy/types.d.ts +1 -1
- package/dist/policy/types.d.ts.map +1 -1
- package/package.json +16 -13
- package/dist/index.cjs +0 -1055
- package/dist/index.cjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -6,20 +6,20 @@ import { z } from 'zod';
|
|
|
6
6
|
import { guard } from '@ucast/mongo2js';
|
|
7
7
|
|
|
8
8
|
class PolicyError extends AuthupError {
|
|
9
|
+
constructor(message, code){
|
|
10
|
+
super({
|
|
11
|
+
message,
|
|
12
|
+
code
|
|
13
|
+
});
|
|
14
|
+
}
|
|
9
15
|
static evaluatorNotFound(type) {
|
|
10
16
|
return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
|
|
11
17
|
}
|
|
12
18
|
static evaluatorNotProcessable() {
|
|
13
|
-
|
|
19
|
+
return new PolicyError('The evaluator can not process the policy.', ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE);
|
|
14
20
|
}
|
|
15
21
|
static evaluatorContextInvalid() {
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
constructor(message, code){
|
|
19
|
-
super({
|
|
20
|
-
message,
|
|
21
|
-
code
|
|
22
|
-
});
|
|
22
|
+
return new PolicyError('The evaluator context is not valid.', ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -83,34 +83,35 @@ class AttributeNamesPolicyValidator extends Container {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
class AttributeNamesPolicyEvaluator {
|
|
86
|
+
validator;
|
|
87
|
+
constructor(){
|
|
88
|
+
this.validator = new AttributeNamesPolicyValidator();
|
|
89
|
+
}
|
|
86
90
|
async can(ctx) {
|
|
87
|
-
return ctx.
|
|
91
|
+
return ctx.config.type === BuiltInPolicyType.ATTRIBUTE_NAMES;
|
|
88
92
|
}
|
|
89
|
-
async
|
|
90
|
-
return this.validator.run(ctx.
|
|
93
|
+
async validateConfig(ctx) {
|
|
94
|
+
return this.validator.run(ctx.config);
|
|
91
95
|
}
|
|
92
|
-
async
|
|
93
|
-
if (!isObject(ctx.
|
|
96
|
+
async validateInput(ctx) {
|
|
97
|
+
if (!isObject(ctx.input.attributes)) {
|
|
94
98
|
throw PolicyError.evaluatorContextInvalid();
|
|
95
99
|
}
|
|
96
|
-
return ctx.
|
|
100
|
+
return ctx.input;
|
|
97
101
|
}
|
|
98
102
|
async evaluate(ctx) {
|
|
99
|
-
if (!ctx.
|
|
103
|
+
if (!ctx.input.attributes) {
|
|
100
104
|
throw PolicyError.evaluatorContextInvalid();
|
|
101
105
|
}
|
|
102
|
-
const attributes = flattenObject(ctx.
|
|
106
|
+
const attributes = flattenObject(ctx.input.attributes);
|
|
103
107
|
const keys = Object.keys(attributes);
|
|
104
108
|
for(let i = 0; i < keys.length; i++){
|
|
105
|
-
const index = ctx.
|
|
109
|
+
const index = ctx.config.names.indexOf(keys[i]);
|
|
106
110
|
if (index === -1) {
|
|
107
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
111
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
111
|
-
}
|
|
112
|
-
constructor(){
|
|
113
|
-
this.validator = new AttributeNamesPolicyValidator();
|
|
114
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
|
|
@@ -132,46 +133,55 @@ class AttributesPolicyValidator extends Container {
|
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
class AttributesPolicyEvaluator {
|
|
136
|
+
validator;
|
|
137
|
+
constructor(){
|
|
138
|
+
this.validator = new AttributesPolicyValidator();
|
|
139
|
+
}
|
|
135
140
|
async can(ctx) {
|
|
136
|
-
return ctx.
|
|
141
|
+
return ctx.config.type === BuiltInPolicyType.ATTRIBUTES;
|
|
137
142
|
}
|
|
138
|
-
async
|
|
139
|
-
return this.validator.run(ctx.
|
|
143
|
+
async validateConfig(ctx) {
|
|
144
|
+
return this.validator.run(ctx.config);
|
|
140
145
|
}
|
|
141
|
-
async
|
|
142
|
-
if (!isObject(ctx.
|
|
146
|
+
async validateInput(ctx) {
|
|
147
|
+
if (!isObject(ctx.input.attributes)) {
|
|
143
148
|
throw PolicyError.evaluatorContextInvalid();
|
|
144
149
|
}
|
|
145
|
-
return ctx.
|
|
150
|
+
return ctx.input;
|
|
146
151
|
}
|
|
147
152
|
async evaluate(ctx) {
|
|
148
|
-
if (!ctx.
|
|
153
|
+
if (!ctx.input.attributes) {
|
|
149
154
|
throw PolicyError.evaluatorContextInvalid();
|
|
150
155
|
}
|
|
151
|
-
this.fixQuery(ctx.
|
|
152
|
-
const testIt = guard(ctx.
|
|
153
|
-
return maybeInvertPolicyOutcome(testIt(ctx.
|
|
156
|
+
this.fixQuery(ctx.config.query);
|
|
157
|
+
const testIt = guard(ctx.config.query);
|
|
158
|
+
return maybeInvertPolicyOutcome(testIt(ctx.input.attributes), ctx.config.invert);
|
|
154
159
|
}
|
|
155
160
|
fixQuery(query) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const value = query[key];
|
|
160
|
-
if (isObject(value) || Array.isArray(value)) {
|
|
161
|
-
this.fixQuery(value);
|
|
162
|
-
continue;
|
|
161
|
+
if (Array.isArray(query)) {
|
|
162
|
+
for(let i = 0; i < query.length; i++){
|
|
163
|
+
this.fixQuery(query[i]);
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (isObject(query)) {
|
|
168
|
+
const keys = Object.keys(query);
|
|
169
|
+
for(let i = 0; i < keys.length; i++){
|
|
170
|
+
const key = keys[i];
|
|
171
|
+
const value = query[key];
|
|
172
|
+
if (isObject(value) || Array.isArray(value)) {
|
|
173
|
+
this.fixQuery(value);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (key === '$regex' && typeof value === 'string') {
|
|
177
|
+
const fragments = value.match(/\/(.*?)\/([a-z]*)?$/i);
|
|
178
|
+
if (fragments) {
|
|
179
|
+
query[key] = new RegExp(fragments[1], fragments[2]);
|
|
180
|
+
}
|
|
168
181
|
}
|
|
169
182
|
}
|
|
170
183
|
}
|
|
171
184
|
}
|
|
172
|
-
constructor(){
|
|
173
|
-
this.validator = new AttributesPolicyValidator();
|
|
174
|
-
}
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
/*
|
|
@@ -238,31 +248,31 @@ class PolicyDataValidator extends Container {
|
|
|
238
248
|
}
|
|
239
249
|
|
|
240
250
|
async function evaluatePolicy(ctx) {
|
|
241
|
-
if (ctx.options.exclude && ctx.options.exclude.length > 0 && ctx.options.exclude.indexOf(ctx.
|
|
242
|
-
if (typeof ctx.
|
|
243
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
251
|
+
if (ctx.options.exclude && ctx.options.exclude.length > 0 && ctx.options.exclude.indexOf(ctx.config.type) !== -1) {
|
|
252
|
+
if (typeof ctx.config.invert === 'boolean') {
|
|
253
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
244
254
|
}
|
|
245
255
|
return true;
|
|
246
256
|
}
|
|
247
|
-
if (ctx.options.include && ctx.options.include.length > 0 && ctx.options.include.indexOf(ctx.
|
|
248
|
-
if (typeof ctx.
|
|
249
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
257
|
+
if (ctx.options.include && ctx.options.include.length > 0 && ctx.options.include.indexOf(ctx.config.type) === -1) {
|
|
258
|
+
if (typeof ctx.config.invert === 'boolean') {
|
|
259
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
250
260
|
}
|
|
251
261
|
return true;
|
|
252
262
|
}
|
|
253
|
-
const evaluator = ctx.evaluators[ctx.
|
|
263
|
+
const evaluator = ctx.evaluators[ctx.config.type];
|
|
254
264
|
if (!evaluator) {
|
|
255
|
-
throw PolicyError.evaluatorNotFound(ctx.
|
|
265
|
+
throw PolicyError.evaluatorNotFound(ctx.config.type);
|
|
256
266
|
}
|
|
257
267
|
try {
|
|
258
268
|
const canEvaluate = await evaluator.can(ctx);
|
|
259
269
|
if (canEvaluate) {
|
|
260
|
-
const
|
|
261
|
-
const
|
|
270
|
+
const config = await evaluator.validateConfig(ctx);
|
|
271
|
+
const input = await evaluator.validateInput(ctx);
|
|
262
272
|
return await evaluator.evaluate({
|
|
263
273
|
...ctx,
|
|
264
|
-
|
|
265
|
-
|
|
274
|
+
input,
|
|
275
|
+
config
|
|
266
276
|
});
|
|
267
277
|
}
|
|
268
278
|
} catch (e) {
|
|
@@ -295,48 +305,49 @@ class CompositePolicyValidator extends Container {
|
|
|
295
305
|
}
|
|
296
306
|
|
|
297
307
|
class CompositePolicyEvaluator {
|
|
308
|
+
validator;
|
|
309
|
+
constructor(){
|
|
310
|
+
this.validator = new CompositePolicyValidator();
|
|
311
|
+
}
|
|
298
312
|
async can(ctx) {
|
|
299
|
-
return isCompositePolicy(ctx.
|
|
313
|
+
return isCompositePolicy(ctx.config);
|
|
300
314
|
}
|
|
301
|
-
async
|
|
302
|
-
return this.validator.run(ctx.
|
|
315
|
+
async validateConfig(ctx) {
|
|
316
|
+
return this.validator.run(ctx.config);
|
|
303
317
|
}
|
|
304
|
-
async
|
|
305
|
-
return ctx.
|
|
318
|
+
async validateInput(ctx) {
|
|
319
|
+
return ctx.input;
|
|
306
320
|
}
|
|
307
321
|
async evaluate(ctx) {
|
|
308
322
|
let count = 0;
|
|
309
|
-
const decisionStrategy = ctx.
|
|
310
|
-
for(let i = 0; i < ctx.
|
|
311
|
-
const childPolicy = ctx.
|
|
323
|
+
const decisionStrategy = ctx.config.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
|
|
324
|
+
for(let i = 0; i < ctx.config.children.length; i++){
|
|
325
|
+
const childPolicy = ctx.config.children[i];
|
|
312
326
|
let outcome;
|
|
313
327
|
if (isCompositePolicy(childPolicy)) {
|
|
314
328
|
outcome = await this.evaluate({
|
|
315
329
|
...ctx,
|
|
316
|
-
|
|
330
|
+
config: childPolicy
|
|
317
331
|
});
|
|
318
332
|
} else {
|
|
319
333
|
outcome = await evaluatePolicy({
|
|
320
334
|
...ctx,
|
|
321
|
-
|
|
335
|
+
config: childPolicy
|
|
322
336
|
});
|
|
323
337
|
}
|
|
324
338
|
if (outcome) {
|
|
325
339
|
if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
|
|
326
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
340
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
327
341
|
}
|
|
328
342
|
count++;
|
|
329
343
|
} else {
|
|
330
344
|
if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
|
|
331
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
345
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
332
346
|
}
|
|
333
347
|
count--;
|
|
334
348
|
}
|
|
335
349
|
}
|
|
336
|
-
return maybeInvertPolicyOutcome(count > 0, ctx.
|
|
337
|
-
}
|
|
338
|
-
constructor(){
|
|
339
|
-
this.validator = new CompositePolicyValidator();
|
|
350
|
+
return maybeInvertPolicyOutcome(count > 0, ctx.config.invert);
|
|
340
351
|
}
|
|
341
352
|
}
|
|
342
353
|
|
|
@@ -362,38 +373,39 @@ function toDate$1(input) {
|
|
|
362
373
|
return input;
|
|
363
374
|
}
|
|
364
375
|
class DatePolicyEvaluator {
|
|
376
|
+
validator;
|
|
377
|
+
constructor(){
|
|
378
|
+
this.validator = new DatePolicyValidator();
|
|
379
|
+
}
|
|
365
380
|
async can(ctx) {
|
|
366
|
-
return ctx.
|
|
381
|
+
return ctx.config.type === BuiltInPolicyType.DATE;
|
|
367
382
|
}
|
|
368
|
-
async
|
|
369
|
-
return this.validator.run(ctx.
|
|
383
|
+
async validateConfig(ctx) {
|
|
384
|
+
return this.validator.run(ctx.config);
|
|
370
385
|
}
|
|
371
|
-
async
|
|
372
|
-
return ctx.
|
|
386
|
+
async validateInput(ctx) {
|
|
387
|
+
return ctx.input;
|
|
373
388
|
}
|
|
374
389
|
async evaluate(ctx) {
|
|
375
390
|
let now;
|
|
376
|
-
if (ctx.
|
|
377
|
-
now = normalizeDate$1(toDate$1(ctx.
|
|
391
|
+
if (ctx.input.dateTime) {
|
|
392
|
+
now = normalizeDate$1(toDate$1(ctx.input.dateTime));
|
|
378
393
|
} else {
|
|
379
394
|
now = normalizeDate$1(new Date());
|
|
380
395
|
}
|
|
381
|
-
if (ctx.
|
|
382
|
-
const start = normalizeDate$1(toDate$1(ctx.
|
|
396
|
+
if (ctx.config.start) {
|
|
397
|
+
const start = normalizeDate$1(toDate$1(ctx.config.start));
|
|
383
398
|
if (now < start) {
|
|
384
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
399
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
385
400
|
}
|
|
386
401
|
}
|
|
387
|
-
if (ctx.
|
|
388
|
-
const end = normalizeDate$1(toDate$1(ctx.
|
|
402
|
+
if (ctx.config.end) {
|
|
403
|
+
const end = normalizeDate$1(toDate$1(ctx.config.end));
|
|
389
404
|
if (now > end) {
|
|
390
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
405
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
391
406
|
}
|
|
392
407
|
}
|
|
393
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
394
|
-
}
|
|
395
|
-
constructor(){
|
|
396
|
-
this.validator = new DatePolicyValidator();
|
|
408
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
397
409
|
}
|
|
398
410
|
}
|
|
399
411
|
|
|
@@ -405,28 +417,29 @@ class IdentityPolicyValidator extends Container {
|
|
|
405
417
|
}
|
|
406
418
|
|
|
407
419
|
class IdentityPolicyEvaluator {
|
|
420
|
+
validator;
|
|
421
|
+
constructor(){
|
|
422
|
+
this.validator = new IdentityPolicyValidator();
|
|
423
|
+
}
|
|
408
424
|
async can(ctx) {
|
|
409
|
-
return ctx.
|
|
425
|
+
return ctx.config.type === BuiltInPolicyType.IDENTITY;
|
|
410
426
|
}
|
|
411
|
-
async
|
|
412
|
-
return this.validator.run(ctx.
|
|
427
|
+
async validateConfig(ctx) {
|
|
428
|
+
return this.validator.run(ctx.config);
|
|
413
429
|
}
|
|
414
|
-
async
|
|
415
|
-
return ctx.
|
|
430
|
+
async validateInput(ctx) {
|
|
431
|
+
return ctx.input;
|
|
416
432
|
}
|
|
417
433
|
async evaluate(ctx) {
|
|
418
|
-
if (!isObject(ctx.
|
|
419
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
434
|
+
if (!isObject(ctx.input.identity)) {
|
|
435
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
420
436
|
}
|
|
421
|
-
const types = ctx.
|
|
437
|
+
const types = ctx.config.types || [];
|
|
422
438
|
if (types.length === 0) {
|
|
423
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
439
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
424
440
|
}
|
|
425
|
-
const typeAllowed = types.indexOf(ctx.
|
|
426
|
-
return maybeInvertPolicyOutcome(typeAllowed, ctx.
|
|
427
|
-
}
|
|
428
|
-
constructor(){
|
|
429
|
-
this.validator = new IdentityPolicyValidator();
|
|
441
|
+
const typeAllowed = types.indexOf(ctx.input.identity.type) !== -1;
|
|
442
|
+
return maybeInvertPolicyOutcome(typeAllowed, ctx.config.invert);
|
|
430
443
|
}
|
|
431
444
|
}
|
|
432
445
|
|
|
@@ -435,24 +448,25 @@ class PermissionBindingPolicyValidator extends Container {
|
|
|
435
448
|
}
|
|
436
449
|
|
|
437
450
|
class PermissionBindingPolicyEvaluator {
|
|
451
|
+
validator;
|
|
452
|
+
constructor(){
|
|
453
|
+
this.validator = new PermissionBindingPolicyValidator();
|
|
454
|
+
}
|
|
438
455
|
async can(ctx) {
|
|
439
|
-
return ctx.
|
|
456
|
+
return ctx.config.type === BuiltInPolicyType.PERMISSION_BINDING;
|
|
440
457
|
}
|
|
441
|
-
async
|
|
442
|
-
return this.validator.run(ctx.
|
|
458
|
+
async validateConfig(ctx) {
|
|
459
|
+
return this.validator.run(ctx.config);
|
|
443
460
|
}
|
|
444
|
-
async
|
|
445
|
-
if (!isObject(ctx.
|
|
461
|
+
async validateInput(ctx) {
|
|
462
|
+
if (!isObject(ctx.input.identity) && !isObject(ctx.input.permission)) {
|
|
446
463
|
throw PolicyError.evaluatorContextInvalid();
|
|
447
464
|
}
|
|
448
|
-
return ctx.
|
|
465
|
+
return ctx.input;
|
|
449
466
|
}
|
|
450
467
|
async evaluate(ctx) {
|
|
451
468
|
// todo: this must be changed when the permission-checker not only checks owned permissions.
|
|
452
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
453
|
-
}
|
|
454
|
-
constructor(){
|
|
455
|
-
this.validator = new PermissionBindingPolicyValidator();
|
|
469
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
456
470
|
}
|
|
457
471
|
}
|
|
458
472
|
|
|
@@ -469,33 +483,37 @@ class RealmMatchPolicyValidator extends Container {
|
|
|
469
483
|
}
|
|
470
484
|
|
|
471
485
|
class RealmMatchPolicyEvaluator {
|
|
486
|
+
validator;
|
|
487
|
+
constructor(){
|
|
488
|
+
this.validator = new RealmMatchPolicyValidator();
|
|
489
|
+
}
|
|
472
490
|
async can(ctx) {
|
|
473
|
-
return ctx.
|
|
491
|
+
return ctx.config.type === BuiltInPolicyType.REALM_MATCH;
|
|
474
492
|
}
|
|
475
|
-
async
|
|
476
|
-
return this.validator.run(ctx.
|
|
493
|
+
async validateConfig(ctx) {
|
|
494
|
+
return this.validator.run(ctx.config);
|
|
477
495
|
}
|
|
478
|
-
async
|
|
479
|
-
if (!isObject(ctx.
|
|
496
|
+
async validateInput(ctx) {
|
|
497
|
+
if (!isObject(ctx.input.attributes) || !isObject(ctx.input.identity)) {
|
|
480
498
|
throw PolicyError.evaluatorContextInvalid();
|
|
481
499
|
}
|
|
482
|
-
return ctx.
|
|
500
|
+
return ctx.input;
|
|
483
501
|
}
|
|
484
502
|
async evaluate(ctx) {
|
|
485
|
-
if (!ctx.
|
|
503
|
+
if (!ctx.input.attributes || !ctx.input.identity) {
|
|
486
504
|
throw PolicyError.evaluatorContextInvalid();
|
|
487
505
|
}
|
|
488
|
-
const identityMasterMatchAll = ctx.
|
|
489
|
-
if (identityMasterMatchAll && ctx.
|
|
490
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
506
|
+
const identityMasterMatchAll = ctx.config.identityMasterMatchAll ?? true;
|
|
507
|
+
if (identityMasterMatchAll && ctx.input.identity.realmName && ctx.input.identity.realmName === 'master') {
|
|
508
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
491
509
|
}
|
|
492
510
|
let keys;
|
|
493
|
-
if (ctx.
|
|
494
|
-
if (Array.isArray(ctx.
|
|
495
|
-
keys = ctx.
|
|
511
|
+
if (ctx.config.attributeName) {
|
|
512
|
+
if (Array.isArray(ctx.config.attributeName)) {
|
|
513
|
+
keys = ctx.config.attributeName;
|
|
496
514
|
} else {
|
|
497
515
|
keys = [
|
|
498
|
-
ctx.
|
|
516
|
+
ctx.config.attributeName
|
|
499
517
|
];
|
|
500
518
|
}
|
|
501
519
|
} else {
|
|
@@ -505,11 +523,11 @@ class RealmMatchPolicyEvaluator {
|
|
|
505
523
|
'realmId',
|
|
506
524
|
'realmName'
|
|
507
525
|
];
|
|
508
|
-
ctx.
|
|
526
|
+
ctx.config.decisionStrategy = DecisionStrategy.CONSENSUS;
|
|
509
527
|
}
|
|
510
|
-
const attributeNameStrict = ctx.
|
|
528
|
+
const attributeNameStrict = ctx.config.attributeNameStrict ?? true;
|
|
511
529
|
if (!attributeNameStrict) {
|
|
512
|
-
const resourceKeys = Object.keys(ctx.
|
|
530
|
+
const resourceKeys = Object.keys(ctx.input.attributes);
|
|
513
531
|
const keysToAdd = [];
|
|
514
532
|
for(let i = 0; i < resourceKeys.length; i++){
|
|
515
533
|
let contains = false;
|
|
@@ -529,32 +547,29 @@ class RealmMatchPolicyEvaluator {
|
|
|
529
547
|
}
|
|
530
548
|
let count = 0;
|
|
531
549
|
for(let i = 0; i < keys.length; i++){
|
|
532
|
-
if (!hasOwnProperty(ctx.
|
|
550
|
+
if (!hasOwnProperty(ctx.input.attributes, keys[i])) {
|
|
533
551
|
continue;
|
|
534
552
|
}
|
|
535
553
|
let outcome = false;
|
|
536
|
-
const attributeValue = ctx.
|
|
537
|
-
if (attributeValue === null && ctx.
|
|
554
|
+
const attributeValue = ctx.input.attributes[keys[i]];
|
|
555
|
+
if (attributeValue === null && ctx.config.attributeNullMatchAll) {
|
|
538
556
|
outcome = true;
|
|
539
|
-
} else if (attributeValue === ctx.
|
|
557
|
+
} else if (attributeValue === ctx.input.identity.realmId || attributeValue === ctx.input.identity.realmName) {
|
|
540
558
|
outcome = true;
|
|
541
559
|
}
|
|
542
560
|
if (outcome) {
|
|
543
|
-
if (ctx.
|
|
544
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
561
|
+
if (ctx.config.decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
|
|
562
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
545
563
|
}
|
|
546
564
|
count++;
|
|
547
565
|
} else {
|
|
548
|
-
if (ctx.
|
|
549
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
566
|
+
if (ctx.config.decisionStrategy === DecisionStrategy.UNANIMOUS) {
|
|
567
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
550
568
|
}
|
|
551
569
|
count--;
|
|
552
570
|
}
|
|
553
571
|
}
|
|
554
|
-
return maybeInvertPolicyOutcome(count > 0, ctx.
|
|
555
|
-
}
|
|
556
|
-
constructor(){
|
|
557
|
-
this.validator = new RealmMatchPolicyValidator();
|
|
572
|
+
return maybeInvertPolicyOutcome(count > 0, ctx.config.invert);
|
|
558
573
|
}
|
|
559
574
|
}
|
|
560
575
|
|
|
@@ -586,7 +601,7 @@ class TimePolicyValidator extends Container {
|
|
|
586
601
|
super.initialize();
|
|
587
602
|
this.mount('dayOfWeek', createValidator(z.number().min(0).max(6).or(z.null()).or(z.undefined()).optional()));
|
|
588
603
|
this.mount('dayOfMonth', createValidator(z.number().min(1).max(31).or(z.null()).or(z.undefined()).optional()));
|
|
589
|
-
this.mount('dayOfYear', createValidator(z.number().min(1).max(
|
|
604
|
+
this.mount('dayOfYear', createValidator(z.number().min(1).max(365).or(z.null()).or(z.undefined()).optional()));
|
|
590
605
|
this.mount('start', createValidator(z.date().or(z.string().datetime()).or(z.string().time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
|
|
591
606
|
this.mount('end', createValidator(z.date().or(z.string().datetime()).or(z.string().time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
|
|
592
607
|
this.mount('interval', createValidator(z.nativeEnum(TimePolicyInterval).or(z.null()).or(z.undefined()).optional()));
|
|
@@ -616,59 +631,60 @@ function toDate(input, dateRef) {
|
|
|
616
631
|
return input;
|
|
617
632
|
}
|
|
618
633
|
class TimePolicyEvaluator {
|
|
634
|
+
validator;
|
|
635
|
+
constructor(){
|
|
636
|
+
this.validator = new TimePolicyValidator();
|
|
637
|
+
}
|
|
619
638
|
async can(ctx) {
|
|
620
|
-
return ctx.
|
|
639
|
+
return ctx.config.type === BuiltInPolicyType.TIME;
|
|
621
640
|
}
|
|
622
|
-
async
|
|
623
|
-
return this.validator.run(ctx.
|
|
641
|
+
async validateConfig(ctx) {
|
|
642
|
+
return this.validator.run(ctx.config);
|
|
624
643
|
}
|
|
625
|
-
async
|
|
626
|
-
return ctx.
|
|
644
|
+
async validateInput(ctx) {
|
|
645
|
+
return ctx.input;
|
|
627
646
|
}
|
|
628
647
|
async evaluate(ctx) {
|
|
629
648
|
let now;
|
|
630
|
-
if (ctx.
|
|
631
|
-
now = toDate(ctx.
|
|
649
|
+
if (ctx.input.dateTime) {
|
|
650
|
+
now = toDate(ctx.input.dateTime);
|
|
632
651
|
} else {
|
|
633
652
|
now = new Date();
|
|
634
653
|
}
|
|
635
|
-
if (ctx.
|
|
636
|
-
const start = normalizeDate(toDate(ctx.
|
|
654
|
+
if (ctx.config.start) {
|
|
655
|
+
const start = normalizeDate(toDate(ctx.config.start, now), now);
|
|
637
656
|
if (now < start) {
|
|
638
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
657
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
639
658
|
}
|
|
640
659
|
}
|
|
641
|
-
if (ctx.
|
|
642
|
-
const end = normalizeDate(toDate(ctx.
|
|
660
|
+
if (ctx.config.end) {
|
|
661
|
+
const end = normalizeDate(toDate(ctx.config.end, now), now);
|
|
643
662
|
if (now > end) {
|
|
644
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
663
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
645
664
|
}
|
|
646
665
|
}
|
|
647
|
-
if (ctx.
|
|
648
|
-
if (isIntervalForDayOfWeek(ctx.
|
|
649
|
-
if (now.getDay() !== ctx.
|
|
650
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
666
|
+
if (ctx.config.interval) {
|
|
667
|
+
if (isIntervalForDayOfWeek(ctx.config.interval) && ctx.config.dayOfWeek) {
|
|
668
|
+
if (now.getDay() !== ctx.config.dayOfWeek) {
|
|
669
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
651
670
|
}
|
|
652
671
|
}
|
|
653
|
-
if (isIntervalForDayOfMonth(ctx.
|
|
654
|
-
if (now.getDate() !== ctx.
|
|
655
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
672
|
+
if (isIntervalForDayOfMonth(ctx.config.interval) && ctx.config.dayOfMonth) {
|
|
673
|
+
if (now.getDate() !== ctx.config.dayOfMonth) {
|
|
674
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
656
675
|
}
|
|
657
676
|
}
|
|
658
|
-
if (isIntervalForDayOfYear(ctx.
|
|
677
|
+
if (isIntervalForDayOfYear(ctx.config.interval) && ctx.config.dayOfYear) {
|
|
659
678
|
const start = new Date(now.getFullYear(), 0, 0);
|
|
660
679
|
const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
|
|
661
680
|
const oneDay = 1000 * 60 * 60 * 24;
|
|
662
681
|
const dayOfYear = Math.floor(diff / oneDay);
|
|
663
|
-
if (dayOfYear !== ctx.
|
|
664
|
-
return maybeInvertPolicyOutcome(false, ctx.
|
|
682
|
+
if (dayOfYear !== ctx.config.dayOfYear) {
|
|
683
|
+
return maybeInvertPolicyOutcome(false, ctx.config.invert);
|
|
665
684
|
}
|
|
666
685
|
}
|
|
667
686
|
}
|
|
668
|
-
return maybeInvertPolicyOutcome(true, ctx.
|
|
669
|
-
}
|
|
670
|
-
constructor(){
|
|
671
|
-
this.validator = new TimePolicyValidator();
|
|
687
|
+
return maybeInvertPolicyOutcome(true, ctx.config.invert);
|
|
672
688
|
}
|
|
673
689
|
}
|
|
674
690
|
|
|
@@ -688,6 +704,12 @@ class TimePolicyEvaluator {
|
|
|
688
704
|
* The policy engine is a component that interprets defined policies and makes decisions
|
|
689
705
|
* on whether to allow or deny a particular access.
|
|
690
706
|
*/ class PolicyEngine {
|
|
707
|
+
evaluators;
|
|
708
|
+
constructor(evaluators = {}){
|
|
709
|
+
this.evaluators = {};
|
|
710
|
+
this.registerDefaultEvaluators();
|
|
711
|
+
this.registerEvaluators(evaluators);
|
|
712
|
+
}
|
|
691
713
|
registerEvaluator(type, evaluator) {
|
|
692
714
|
this.evaluators[type] = evaluator;
|
|
693
715
|
}
|
|
@@ -718,14 +740,18 @@ class TimePolicyEvaluator {
|
|
|
718
740
|
evaluators: this.evaluators
|
|
719
741
|
});
|
|
720
742
|
}
|
|
721
|
-
constructor(evaluators = {}){
|
|
722
|
-
this.evaluators = {};
|
|
723
|
-
this.registerDefaultEvaluators();
|
|
724
|
-
this.registerEvaluators(evaluators);
|
|
725
|
-
}
|
|
726
743
|
}
|
|
727
744
|
|
|
728
745
|
class PermissionError extends AuthupError {
|
|
746
|
+
policy;
|
|
747
|
+
policyError;
|
|
748
|
+
constructor(options = {}){
|
|
749
|
+
super({
|
|
750
|
+
...options,
|
|
751
|
+
message: options.message || 'A permission error occurred.',
|
|
752
|
+
statusCode: options.statusCode || 403
|
|
753
|
+
});
|
|
754
|
+
}
|
|
729
755
|
static notFound(name) {
|
|
730
756
|
return new PermissionError({
|
|
731
757
|
message: `The permission ${name} was not found.`,
|
|
@@ -760,13 +786,6 @@ class PermissionError extends AuthupError {
|
|
|
760
786
|
}
|
|
761
787
|
return error;
|
|
762
788
|
}
|
|
763
|
-
constructor(options = {}){
|
|
764
|
-
super({
|
|
765
|
-
...options,
|
|
766
|
-
message: options.message || 'A permission error occurred.',
|
|
767
|
-
statusCode: options.statusCode || 403
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
789
|
}
|
|
771
790
|
|
|
772
791
|
/*
|
|
@@ -828,6 +847,10 @@ function mergePermissionItems(input) {
|
|
|
828
847
|
}
|
|
829
848
|
|
|
830
849
|
class PermissionMemoryProvider {
|
|
850
|
+
items = {};
|
|
851
|
+
constructor(items = []){
|
|
852
|
+
this.setMany(items);
|
|
853
|
+
}
|
|
831
854
|
async get(options) {
|
|
832
855
|
return this.items[buildPermissionItemKey(options)];
|
|
833
856
|
}
|
|
@@ -837,13 +860,32 @@ class PermissionMemoryProvider {
|
|
|
837
860
|
return prev;
|
|
838
861
|
}, {});
|
|
839
862
|
}
|
|
840
|
-
constructor(items = []){
|
|
841
|
-
this.items = {};
|
|
842
|
-
this.setMany(items);
|
|
843
|
-
}
|
|
844
863
|
}
|
|
845
864
|
|
|
846
865
|
class PermissionChecker {
|
|
866
|
+
provider;
|
|
867
|
+
policyEngine;
|
|
868
|
+
clientId;
|
|
869
|
+
realmId;
|
|
870
|
+
// ----------------------------------------------
|
|
871
|
+
constructor(options = {}){
|
|
872
|
+
if (options.provider) {
|
|
873
|
+
this.provider = options.provider;
|
|
874
|
+
} else {
|
|
875
|
+
this.provider = new PermissionMemoryProvider();
|
|
876
|
+
}
|
|
877
|
+
if (options.clientId) {
|
|
878
|
+
this.clientId = options.clientId;
|
|
879
|
+
}
|
|
880
|
+
if (options.realmId) {
|
|
881
|
+
this.realmId = options.realmId;
|
|
882
|
+
}
|
|
883
|
+
if (options.policyEngine) {
|
|
884
|
+
this.policyEngine = options.policyEngine;
|
|
885
|
+
} else {
|
|
886
|
+
this.policyEngine = new PolicyEngine();
|
|
887
|
+
}
|
|
888
|
+
}
|
|
847
889
|
// ----------------------------------------------
|
|
848
890
|
/**
|
|
849
891
|
* Get a permission.
|
|
@@ -901,11 +943,11 @@ class PermissionChecker {
|
|
|
901
943
|
let outcome;
|
|
902
944
|
try {
|
|
903
945
|
outcome = await this.policyEngine.evaluate({
|
|
904
|
-
|
|
905
|
-
...ctx.
|
|
946
|
+
input: {
|
|
947
|
+
...ctx.input || {},
|
|
906
948
|
permission: entity
|
|
907
949
|
},
|
|
908
|
-
|
|
950
|
+
config: entity.policy,
|
|
909
951
|
options: {
|
|
910
952
|
include: options.policiesIncluded,
|
|
911
953
|
exclude: options.policiesExcluded
|
|
@@ -991,25 +1033,6 @@ class PermissionChecker {
|
|
|
991
1033
|
}
|
|
992
1034
|
});
|
|
993
1035
|
}
|
|
994
|
-
// ----------------------------------------------
|
|
995
|
-
constructor(options = {}){
|
|
996
|
-
if (options.provider) {
|
|
997
|
-
this.provider = options.provider;
|
|
998
|
-
} else {
|
|
999
|
-
this.provider = new PermissionMemoryProvider();
|
|
1000
|
-
}
|
|
1001
|
-
if (options.clientId) {
|
|
1002
|
-
this.clientId = options.clientId;
|
|
1003
|
-
}
|
|
1004
|
-
if (options.realmId) {
|
|
1005
|
-
this.realmId = options.realmId;
|
|
1006
|
-
}
|
|
1007
|
-
if (options.policyEngine) {
|
|
1008
|
-
this.policyEngine = options.policyEngine;
|
|
1009
|
-
} else {
|
|
1010
|
-
this.policyEngine = new PolicyEngine();
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
1036
|
}
|
|
1014
1037
|
|
|
1015
1038
|
export { AttributeNamesPolicyEvaluator, AttributeNamesPolicyValidator, AttributesPolicyEvaluator, AttributesPolicyValidator, BuiltInPolicyType, CompositePolicyEvaluator, CompositePolicyValidator, DatePolicyEvaluator, DatePolicyValidator, DecisionStrategy, IdentityPolicyEvaluator, IdentityPolicyValidator, PermissionBindingPolicyEvaluator, PermissionBindingPolicyValidator, PermissionChecker, PermissionError, PermissionMemoryProvider, PolicyDataIdentityValidator, PolicyDataPermissionValidator, PolicyDataValidator, PolicyEngine, PolicyError, RealmMatchPolicyEvaluator, RealmMatchPolicyValidator, TimePolicyEvaluator, TimePolicyInterval, TimePolicyValidator, buildPermissionItemKey, defineAttributesPolicy, definePolicyWithType, evaluatePolicy, isCompositePolicy, isIntervalForDayOfMonth, isIntervalForDayOfWeek, isIntervalForDayOfYear, isPermissionItemEqual, maybeInvertPolicyOutcome, mergePermissionItems };
|