@backstage-community/plugin-rbac-backend 6.0.1 → 6.1.0

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.
@@ -11,6 +11,8 @@ var roleMetadata = require('../database/role-metadata.cjs.js');
11
11
  var helper = require('../helper.cjs.js');
12
12
  var conditionValidation = require('../validation/condition-validation.cjs.js');
13
13
  var policiesValidation = require('../validation/policies-validation.cjs.js');
14
+ var conditions = require('../permissions/conditions.cjs.js');
15
+ var rules = require('../permissions/rules.cjs.js');
14
16
 
15
17
  class PoliciesServer {
16
18
  constructor(permissions, options, enforcer, conditionalStorage, pluginPermMetaData, roleMetadata, auditor, rbacProviders) {
@@ -23,7 +25,7 @@ class PoliciesServer {
23
25
  this.auditor = auditor;
24
26
  this.rbacProviders = rbacProviders;
25
27
  }
26
- async authorize(request, permission) {
28
+ async authorizeConditional(request, permission) {
27
29
  const credentials = await this.options.httpAuth.credentials(request, {
28
30
  allow: ["user", "service"]
29
31
  });
@@ -32,31 +34,43 @@ class PoliciesServer {
32
34
  `Only creadential principal with type 'user' permitted to modify permissions`
33
35
  );
34
36
  }
35
- const decision = (await this.permissions.authorize(
36
- [{ permission, resourceRef: permission.resourceType }],
37
- { credentials }
38
- ))[0];
37
+ let decision;
38
+ if (permission.type === "resource") {
39
+ decision = (await this.permissions.authorizeConditional([{ permission }], {
40
+ credentials
41
+ }))[0];
42
+ } else {
43
+ decision = (await this.permissions.authorize([{ permission }], {
44
+ credentials
45
+ }))[0];
46
+ }
39
47
  return decision;
40
48
  }
41
49
  async serve() {
42
50
  const router = await pluginPermissionBackend.createRouter(this.options);
43
- const { httpAuth } = this.options;
51
+ const { httpAuth, logger } = this.options;
44
52
  if (!httpAuth) {
45
53
  throw new errors.ServiceUnavailableError(
46
54
  "httpAuth not found, ensure the correct configuration for the RBAC plugin"
47
55
  );
48
56
  }
49
- const permissionsIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
57
+ const policyPermissionsIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
50
58
  resourceType: pluginRbacCommon.RESOURCE_TYPE_POLICY_ENTITY,
51
- permissions: pluginRbacCommon.policyEntityPermissions
59
+ getResources: (resourceRefs) => Promise.all(
60
+ resourceRefs.map((ref) => {
61
+ return this.roleMetadata.findRoleMetadata(ref);
62
+ })
63
+ ),
64
+ permissions: pluginRbacCommon.policyEntityPermissions,
65
+ rules: Object.values(rules.rules)
52
66
  });
53
- router.use(permissionsIntegrationRouter);
67
+ router.use(policyPermissionsIntegrationRouter);
54
68
  const isPluginEnabled = this.options.config.getOptionalBoolean("permission.enabled");
55
69
  if (!isPluginEnabled) {
56
70
  return router;
57
71
  }
58
72
  router.get("/", async (request, response) => {
59
- const decision = await this.authorize(
73
+ const decision = await this.authorizeConditional(
60
74
  request,
61
75
  pluginRbacCommon.policyEntityReadPermission
62
76
  );
@@ -69,25 +83,48 @@ class PoliciesServer {
69
83
  "/policies",
70
84
  restInterceptor.logAuditorEvent(this.auditor),
71
85
  async (request, response) => {
72
- const decision = await this.authorize(
86
+ let conditionsFilter;
87
+ const decision = await this.authorizeConditional(
73
88
  request,
74
89
  pluginRbacCommon.policyEntityReadPermission
75
90
  );
76
91
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
77
92
  throw new errors.NotAllowedError();
78
93
  }
79
- let policies;
94
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
95
+ conditionsFilter = conditions.transformConditions(decision.conditions);
96
+ }
97
+ const roleMetadata = await this.roleMetadata.filterForOwnerRoleMetadata(conditionsFilter);
98
+ let policies = [];
80
99
  if (this.isPolicyFilterEnabled(request)) {
81
100
  const entityRef = this.getFirstQuery(request.query.entityRef);
82
101
  const permission = this.getFirstQuery(request.query.permission);
83
102
  const policy = this.getFirstQuery(request.query.policy);
84
103
  const effect = this.getFirstQuery(request.query.effect);
104
+ const matchedRoleName = roleMetadata.flatMap(
105
+ (role) => role.roleEntityRef
106
+ );
85
107
  const filter = [entityRef, permission, policy, effect];
86
- policies = await this.enforcer.getFilteredPolicy(0, ...filter);
108
+ policies = matchedRoleName.includes(entityRef) ? await this.enforcer.getFilteredPolicy(0, ...filter) : [];
87
109
  } else {
88
- policies = await this.enforcer.getPolicy();
110
+ for (const role of roleMetadata) {
111
+ policies.push(
112
+ ...await this.enforcer.getFilteredPolicy(
113
+ 0,
114
+ ...[role.roleEntityRef]
115
+ )
116
+ );
117
+ }
89
118
  }
90
119
  const body = await this.transformPolicyArray(...policies);
120
+ body.map((policy) => {
121
+ if (policy.permission === "policy-entity" && policy.policy === "create") {
122
+ policy.permission = "policy.entity.create";
123
+ logger.warn(
124
+ `Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${[policy.entityReference, "policy-entity", policy.policy, policy.effect]} to use 'policy.entity.create' instead of 'policy-entity' from source ${policy.metadata?.source}`
125
+ );
126
+ }
127
+ });
91
128
  response.json(body);
92
129
  }
93
130
  );
@@ -95,17 +132,33 @@ class PoliciesServer {
95
132
  "/policies/:kind/:namespace/:name",
96
133
  restInterceptor.logAuditorEvent(this.auditor),
97
134
  async (request, response) => {
98
- const decision = await this.authorize(
135
+ let conditionsFilter;
136
+ const decision = await this.authorizeConditional(
99
137
  request,
100
138
  pluginRbacCommon.policyEntityReadPermission
101
139
  );
102
140
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
103
141
  throw new errors.NotAllowedError();
104
142
  }
143
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
144
+ conditionsFilter = conditions.transformConditions(decision.conditions);
145
+ }
146
+ const roleMetadata = await this.roleMetadata.filterForOwnerRoleMetadata(conditionsFilter);
147
+ const matchedRoleName = roleMetadata.flatMap((role) => {
148
+ return role.roleEntityRef;
149
+ });
105
150
  const entityRef = this.getEntityReference(request);
106
- const policy = await this.enforcer.getFilteredPolicy(0, entityRef);
151
+ const policy = matchedRoleName.includes(entityRef) ? await this.enforcer.getFilteredPolicy(0, entityRef) : [];
107
152
  if (policy.length !== 0) {
108
153
  const body = await this.transformPolicyArray(...policy);
154
+ body.map((bodyPolicy) => {
155
+ if (bodyPolicy.permission === "policy-entity" && bodyPolicy.policy === "create") {
156
+ bodyPolicy.permission = "policy.entity.create";
157
+ logger.warn(
158
+ `Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${[bodyPolicy.entityReference, "policy-entity", bodyPolicy.policy, bodyPolicy.effect]} to use 'policy.entity.create' instead of 'policy-entity' from source ${bodyPolicy.metadata?.source}`
159
+ );
160
+ }
161
+ });
109
162
  response.json(body);
110
163
  } else {
111
164
  throw new errors.NotFoundError();
@@ -116,13 +169,17 @@ class PoliciesServer {
116
169
  "/policies/:kind/:namespace/:name",
117
170
  restInterceptor.logAuditorEvent(this.auditor),
118
171
  async (request, response) => {
119
- const decision = await this.authorize(
172
+ let conditionsFilter;
173
+ const decision = await this.authorizeConditional(
120
174
  request,
121
175
  pluginRbacCommon.policyEntityDeletePermission
122
176
  );
123
177
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
124
178
  throw new errors.NotAllowedError();
125
179
  }
180
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
181
+ conditionsFilter = conditions.transformConditions(decision.conditions);
182
+ }
126
183
  const entityRef = this.getEntityReference(request);
127
184
  const policyRaw = request.body;
128
185
  if (lodash.isEmpty(policyRaw)) {
@@ -131,7 +188,12 @@ class PoliciesServer {
131
188
  policyRaw.forEach((element) => {
132
189
  element.entityReference = entityRef;
133
190
  });
134
- const processedPolicies = await this.processPolicies(policyRaw, true);
191
+ const processedPolicies = await this.processPolicies(
192
+ policyRaw,
193
+ true,
194
+ undefined,
195
+ conditionsFilter
196
+ );
135
197
  await this.enforcer.removePolicies(processedPolicies);
136
198
  response.locals.meta = { policies: processedPolicies };
137
199
  response.status(204).end();
@@ -141,7 +203,7 @@ class PoliciesServer {
141
203
  "/policies",
142
204
  restInterceptor.logAuditorEvent(this.auditor),
143
205
  async (request, response) => {
144
- const decision = await this.authorize(
206
+ const decision = await this.authorizeConditional(
145
207
  request,
146
208
  pluginRbacCommon.policyEntityCreatePermission
147
209
  );
@@ -152,7 +214,11 @@ class PoliciesServer {
152
214
  if (lodash.isEmpty(policyRaw)) {
153
215
  throw new errors.InputError(`permission policy must be present`);
154
216
  }
155
- const processedPolicies = await this.processPolicies(policyRaw);
217
+ const processedPolicies = await this.processPolicies(
218
+ policyRaw,
219
+ false,
220
+ undefined
221
+ );
156
222
  const entityRef = processedPolicies[0][0];
157
223
  const roleMetadata = await this.roleMetadata.findRoleMetadata(entityRef);
158
224
  if (entityRef.startsWith("role:default") && !roleMetadata) {
@@ -167,13 +233,17 @@ class PoliciesServer {
167
233
  "/policies/:kind/:namespace/:name",
168
234
  restInterceptor.logAuditorEvent(this.auditor),
169
235
  async (request, response) => {
170
- const decision = await this.authorize(
236
+ let conditionsFilter;
237
+ const decision = await this.authorizeConditional(
171
238
  request,
172
239
  pluginRbacCommon.policyEntityUpdatePermission
173
240
  );
174
241
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
175
242
  throw new errors.NotAllowedError();
176
243
  }
244
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
245
+ conditionsFilter = conditions.transformConditions(decision.conditions);
246
+ }
177
247
  const entityRef = this.getEntityReference(request);
178
248
  const oldPolicyRaw = request.body.oldPolicy;
179
249
  if (lodash.isEmpty(oldPolicyRaw)) {
@@ -189,7 +259,8 @@ class PoliciesServer {
189
259
  const processedOldPolicy = await this.processPolicies(
190
260
  oldPolicyRaw,
191
261
  true,
192
- "old policy"
262
+ "old policy",
263
+ conditionsFilter
193
264
  );
194
265
  oldPolicyRaw.sort(
195
266
  (a, b) => a.permission === b.permission ? this.nameSort(a.policy, b.policy) : this.nameSort(a.permission, b.permission)
@@ -207,7 +278,8 @@ class PoliciesServer {
207
278
  const processedNewPolicy = await this.processPolicies(
208
279
  newPolicyRaw,
209
280
  false,
210
- "new policy"
281
+ "new policy",
282
+ conditionsFilter
211
283
  );
212
284
  const roleMetadata = await this.roleMetadata.findRoleMetadata(entityRef);
213
285
  if (entityRef.startsWith("role:default") && !roleMetadata) {
@@ -225,15 +297,19 @@ class PoliciesServer {
225
297
  "/roles",
226
298
  restInterceptor.logAuditorEvent(this.auditor),
227
299
  async (request, response) => {
228
- const decision = await this.authorize(
300
+ let conditionsFilter;
301
+ const decision = await this.authorizeConditional(
229
302
  request,
230
303
  pluginRbacCommon.policyEntityReadPermission
231
304
  );
232
305
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
233
306
  throw new errors.NotAllowedError();
234
307
  }
308
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
309
+ conditionsFilter = conditions.transformConditions(decision.conditions);
310
+ }
235
311
  const roles = await this.enforcer.getGroupingPolicy();
236
- const body = await this.transformRoleArray(...roles);
312
+ const body = await this.transformRoleArray(conditionsFilter, ...roles);
237
313
  response.json(body);
238
314
  }
239
315
  );
@@ -241,20 +317,24 @@ class PoliciesServer {
241
317
  "/roles/:kind/:namespace/:name",
242
318
  restInterceptor.logAuditorEvent(this.auditor),
243
319
  async (request, response) => {
244
- const decision = await this.authorize(
320
+ let conditionsFilter;
321
+ const decision = await this.authorizeConditional(
245
322
  request,
246
323
  pluginRbacCommon.policyEntityReadPermission
247
324
  );
248
325
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
249
326
  throw new errors.NotAllowedError();
250
327
  }
328
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
329
+ conditionsFilter = conditions.transformConditions(decision.conditions);
330
+ }
251
331
  const roleEntityRef = this.getEntityReference(request, true);
252
332
  const role = await this.enforcer.getFilteredGroupingPolicy(
253
333
  1,
254
334
  roleEntityRef
255
335
  );
256
- if (role.length !== 0) {
257
- const body = await this.transformRoleArray(...role);
336
+ const body = await this.transformRoleArray(conditionsFilter, ...role);
337
+ if (body.length !== 0) {
258
338
  response.json(body);
259
339
  } else {
260
340
  throw new errors.NotFoundError();
@@ -266,7 +346,7 @@ class PoliciesServer {
266
346
  restInterceptor.logAuditorEvent(this.auditor),
267
347
  async (request, response) => {
268
348
  const uniqueItems = /* @__PURE__ */ new Set();
269
- const decision = await this.authorize(
349
+ const decision = await this.authorizeConditional(
270
350
  request,
271
351
  pluginRbacCommon.policyEntityCreatePermission
272
352
  );
@@ -314,7 +394,8 @@ class PoliciesServer {
314
394
  source: "rest",
315
395
  description: roleRaw.metadata?.description ?? "",
316
396
  author: modifiedBy,
317
- modifiedBy
397
+ modifiedBy,
398
+ owner: roleRaw.metadata?.owner ?? modifiedBy
318
399
  };
319
400
  await this.enforcer.addGroupingPolicies(roles, metadata);
320
401
  response.locals.meta = { ...metadata, members: roles.map((gp) => gp[0]) };
@@ -326,13 +407,17 @@ class PoliciesServer {
326
407
  restInterceptor.logAuditorEvent(this.auditor),
327
408
  async (request, response) => {
328
409
  const uniqueItems = /* @__PURE__ */ new Set();
329
- const decision = await this.authorize(
410
+ let conditionsFilter;
411
+ const decision = await this.authorizeConditional(
330
412
  request,
331
413
  pluginRbacCommon.policyEntityUpdatePermission
332
414
  );
333
415
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
334
416
  throw new errors.NotAllowedError();
335
417
  }
418
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
419
+ conditionsFilter = conditions.transformConditions(decision.conditions);
420
+ }
336
421
  const roleEntityRef = this.getEntityReference(request, true);
337
422
  const oldRoleRaw = request.body.oldRole;
338
423
  if (!oldRoleRaw) {
@@ -368,7 +453,8 @@ class PoliciesServer {
368
453
  ...newRoleRaw.metadata,
369
454
  source: newRoleRaw.metadata?.source ?? "rest",
370
455
  roleEntityRef: newRoleRaw.name,
371
- modifiedBy: credentials.principal.userEntityRef
456
+ modifiedBy: credentials.principal.userEntityRef,
457
+ owner: newRoleRaw.metadata?.owner ?? ""
372
458
  };
373
459
  const oldMetadata = await this.roleMetadata.findRoleMetadata(roleEntityRef);
374
460
  if (!oldMetadata) {
@@ -380,11 +466,15 @@ class PoliciesServer {
380
466
  if (err) {
381
467
  throw new errors.NotAllowedError(`Unable to edit role: ${err.message}`);
382
468
  }
469
+ if (!helper.matches(oldMetadata, conditionsFilter)) {
470
+ throw new errors.NotAllowedError();
471
+ }
383
472
  if (lodash.isEqual(oldRole, newRole) && helper.deepSortedEqual(oldMetadata, newMetadata, [
384
473
  "author",
385
474
  "modifiedBy",
386
475
  "createdAt",
387
- "lastModified"
476
+ "lastModified",
477
+ "owner"
388
478
  ])) {
389
479
  response.status(204).end();
390
480
  return;
@@ -447,14 +537,26 @@ class PoliciesServer {
447
537
  "/roles/:kind/:namespace/:name",
448
538
  restInterceptor.logAuditorEvent(this.auditor),
449
539
  async (request, response) => {
450
- const decision = await this.authorize(
540
+ let conditionsFilter;
541
+ const decision = await this.authorizeConditional(
451
542
  request,
452
543
  pluginRbacCommon.policyEntityDeletePermission
453
544
  );
454
545
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
455
546
  throw new errors.NotAllowedError();
456
547
  }
548
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
549
+ conditionsFilter = conditions.transformConditions(decision.conditions);
550
+ }
457
551
  const roleEntityRef = this.getEntityReference(request, true);
552
+ const currentMetadata = await this.roleMetadata.findRoleMetadata(roleEntityRef);
553
+ if (!helper.matches(currentMetadata, conditionsFilter)) {
554
+ throw new errors.NotAllowedError();
555
+ }
556
+ const err = await policiesValidation.validateSource("rest", currentMetadata);
557
+ if (err) {
558
+ throw new errors.NotAllowedError(`Unable to delete role: ${err.message}`);
559
+ }
458
560
  let roleMembers = [];
459
561
  if (request.query.memberReferences) {
460
562
  const memberReference = this.getFirstQuery(
@@ -483,11 +585,6 @@ class PoliciesServer {
483
585
  throw new errors.NotFoundError(`role member '${role[0]}' was not found`);
484
586
  }
485
587
  }
486
- const currentMetadata = await this.roleMetadata.findRoleMetadata(roleEntityRef);
487
- const err = await policiesValidation.validateSource("rest", currentMetadata);
488
- if (err) {
489
- throw new errors.NotAllowedError(`Unable to delete role: ${err.message}`);
490
- }
491
588
  const credentials = await httpAuth.credentials(request, {
492
589
  allow: ["user"]
493
590
  });
@@ -512,7 +609,7 @@ class PoliciesServer {
512
609
  "/plugins/policies",
513
610
  restInterceptor.logAuditorEvent(this.auditor),
514
611
  async (request, response) => {
515
- const decision = await this.authorize(
612
+ const decision = await this.authorizeConditional(
516
613
  request,
517
614
  pluginRbacCommon.policyEntityReadPermission
518
615
  );
@@ -529,7 +626,7 @@ class PoliciesServer {
529
626
  "/plugins/condition-rules",
530
627
  restInterceptor.logAuditorEvent(this.auditor),
531
628
  async (request, response) => {
532
- const decision = await this.authorize(
629
+ const decision = await this.authorizeConditional(
533
630
  request,
534
631
  pluginRbacCommon.policyEntityReadPermission
535
632
  );
@@ -546,26 +643,36 @@ class PoliciesServer {
546
643
  "/roles/conditions",
547
644
  restInterceptor.logAuditorEvent(this.auditor),
548
645
  async (request, response) => {
549
- const decision = await this.authorize(
646
+ let conditionsFilter;
647
+ const decision = await this.authorizeConditional(
550
648
  request,
551
649
  pluginRbacCommon.policyEntityReadPermission
552
650
  );
553
651
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
554
652
  throw new errors.NotAllowedError();
555
653
  }
556
- const conditions = await this.conditionalStorage.filterConditions(
654
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
655
+ conditionsFilter = conditions.transformConditions(decision.conditions);
656
+ }
657
+ const roleMetadata = await this.roleMetadata.filterForOwnerRoleMetadata(conditionsFilter);
658
+ const matchedRoleName = roleMetadata.flatMap((role) => {
659
+ return role.roleEntityRef;
660
+ });
661
+ const conditions$1 = await this.conditionalStorage.filterConditions(
557
662
  this.getFirstQuery(request.query.roleEntityRef),
558
663
  this.getFirstQuery(request.query.pluginId),
559
664
  this.getFirstQuery(request.query.resourceType),
560
665
  this.getActionQueries(request.query.actions)
561
666
  );
562
- const body = conditions.map((condition) => {
667
+ const body = conditions$1.map((condition) => {
563
668
  return {
564
669
  ...condition,
565
670
  permissionMapping: condition.permissionMapping.map(
566
671
  (pm) => pm.action
567
672
  )
568
673
  };
674
+ }).filter((condition) => {
675
+ return matchedRoleName.includes(condition.roleEntityRef);
569
676
  });
570
677
  response.json(body);
571
678
  }
@@ -574,7 +681,7 @@ class PoliciesServer {
574
681
  "/roles/conditions",
575
682
  restInterceptor.logAuditorEvent(this.auditor),
576
683
  async (request, response) => {
577
- const decision = await this.authorize(
684
+ const decision = await this.authorizeConditional(
578
685
  request,
579
686
  pluginRbacCommon.policyEntityCreatePermission
580
687
  );
@@ -598,7 +705,8 @@ class PoliciesServer {
598
705
  "/roles/conditions/:id",
599
706
  restInterceptor.logAuditorEvent(this.auditor),
600
707
  async (request, response) => {
601
- const decision = await this.authorize(
708
+ let conditionsFilter;
709
+ const decision = await this.authorizeConditional(
602
710
  request,
603
711
  pluginRbacCommon.policyEntityReadPermission
604
712
  );
@@ -613,10 +721,19 @@ class PoliciesServer {
613
721
  if (!condition) {
614
722
  throw new errors.NotFoundError();
615
723
  }
616
- const body = {
724
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
725
+ conditionsFilter = conditions.transformConditions(decision.conditions);
726
+ }
727
+ const roleMetadata = await this.roleMetadata.filterForOwnerRoleMetadata(conditionsFilter);
728
+ const matchedRoleName = roleMetadata.flatMap((role) => {
729
+ return role.roleEntityRef;
730
+ });
731
+ const body = matchedRoleName.includes(condition.roleEntityRef) ? {
617
732
  ...condition,
618
- permissionMapping: condition.permissionMapping.map((pm) => pm.action)
619
- };
733
+ permissionMapping: condition.permissionMapping.map(
734
+ (pm) => pm.action
735
+ )
736
+ } : [];
620
737
  response.json(body);
621
738
  }
622
739
  );
@@ -624,13 +741,17 @@ class PoliciesServer {
624
741
  "/roles/conditions/:id",
625
742
  restInterceptor.logAuditorEvent(this.auditor),
626
743
  async (request, response) => {
627
- const decision = await this.authorize(
744
+ let conditionsFilter;
745
+ const decision = await this.authorizeConditional(
628
746
  request,
629
747
  pluginRbacCommon.policyEntityDeletePermission
630
748
  );
631
749
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
632
750
  throw new errors.NotAllowedError();
633
751
  }
752
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
753
+ conditionsFilter = conditions.transformConditions(decision.conditions);
754
+ }
634
755
  const id = parseInt(request.params.id, 10);
635
756
  if (isNaN(id)) {
636
757
  throw new errors.InputError("Id is not a valid number.");
@@ -643,6 +764,12 @@ class PoliciesServer {
643
764
  ...condition,
644
765
  permissionMapping: condition.permissionMapping.map((pm) => pm.action)
645
766
  };
767
+ const roleMetadata = await this.roleMetadata.findRoleMetadata(
768
+ conditionToDelete.roleEntityRef
769
+ );
770
+ if (!helper.matches(roleMetadata, conditionsFilter)) {
771
+ throw new errors.NotAllowedError();
772
+ }
646
773
  await this.conditionalStorage.deleteCondition(id);
647
774
  response.locals.meta = { condition: conditionToDelete };
648
775
  response.status(204).end();
@@ -652,17 +779,31 @@ class PoliciesServer {
652
779
  "/roles/conditions/:id",
653
780
  restInterceptor.logAuditorEvent(this.auditor),
654
781
  async (request, response) => {
655
- const decision = await this.authorize(
782
+ let conditionsFilter;
783
+ const decision = await this.authorizeConditional(
656
784
  request,
657
785
  pluginRbacCommon.policyEntityUpdatePermission
658
786
  );
659
787
  if (decision.result === pluginPermissionCommon.AuthorizeResult.DENY) {
660
788
  throw new errors.NotAllowedError();
661
789
  }
790
+ if (decision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
791
+ conditionsFilter = conditions.transformConditions(decision.conditions);
792
+ }
662
793
  const id = parseInt(request.params.id, 10);
663
794
  if (isNaN(id)) {
664
795
  throw new errors.InputError("Id is not a valid number.");
665
796
  }
797
+ const condition = await this.conditionalStorage.getCondition(id);
798
+ if (!condition) {
799
+ throw new errors.NotFoundError(`Condition with id ${id} was not found`);
800
+ }
801
+ const roleMetadata = await this.roleMetadata.findRoleMetadata(
802
+ condition.roleEntityRef
803
+ );
804
+ if (!helper.matches(roleMetadata, conditionsFilter)) {
805
+ throw new errors.NotAllowedError();
806
+ }
666
807
  const roleConditionPolicy = request.body;
667
808
  conditionValidation.validateRoleCondition(roleConditionPolicy);
668
809
  const conditionToUpdate = await helper.processConditionMapping(
@@ -679,7 +820,7 @@ class PoliciesServer {
679
820
  "/refresh/:id",
680
821
  restInterceptor.logAuditorEvent(this.auditor),
681
822
  async (request, response) => {
682
- const decision = await this.authorize(
823
+ const decision = await this.authorizeConditional(
683
824
  request,
684
825
  pluginRbacCommon.policyEntityCreatePermission
685
826
  );
@@ -734,7 +875,7 @@ class PoliciesServer {
734
875
  }
735
876
  return roleBasedPolices;
736
877
  }
737
- async transformRoleArray(...roles) {
878
+ async transformRoleArray(filter, ...roles) {
738
879
  const combinedRoles = {};
739
880
  roles.forEach(([value, role]) => {
740
881
  if (combinedRoles.hasOwnProperty(role)) {
@@ -744,7 +885,7 @@ class PoliciesServer {
744
885
  }
745
886
  });
746
887
  const result = await Promise.all(
747
- Object.entries(combinedRoles).map(async ([role, value]) => {
888
+ Object.entries(combinedRoles).flatMap(async ([role, value]) => {
748
889
  const metadataDao = await this.roleMetadata.findRoleMetadata(role);
749
890
  const metadata = metadataDao ? roleMetadata.daoToMetadata(metadataDao) : undefined;
750
891
  return Promise.resolve({
@@ -754,7 +895,10 @@ class PoliciesServer {
754
895
  });
755
896
  })
756
897
  );
757
- return result;
898
+ const filteredResult = result.filter((role) => {
899
+ return role.metadata && helper.matches(role.metadata, filter);
900
+ });
901
+ return filteredResult;
758
902
  }
759
903
  transformPolicyToArray(policy) {
760
904
  return [
@@ -818,7 +962,7 @@ class PoliciesServer {
818
962
  isPolicyFilterEnabled(request) {
819
963
  return !!request.query.entityRef || !!request.query.permission || !!request.query.policy || !!request.query.effect;
820
964
  }
821
- async processPolicies(policyArray, isOld, errorMessage) {
965
+ async processPolicies(policyArray, isOld, errorMessage, filter) {
822
966
  const policies = [];
823
967
  const uniqueItems = /* @__PURE__ */ new Set();
824
968
  for (const policy of policyArray) {
@@ -831,6 +975,9 @@ class PoliciesServer {
831
975
  const metadata = await this.roleMetadata.findRoleMetadata(
832
976
  policy.entityReference
833
977
  );
978
+ if (!helper.matches(metadata, filter)) {
979
+ throw new errors.NotAllowedError();
980
+ }
834
981
  let action = errorMessage ? "edit" : "delete";
835
982
  action = isOld ? action : "add";
836
983
  err = await policiesValidation.validateSource("rest", metadata);