@backstage-community/plugin-rbac-backend 7.2.0 → 7.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ### Dependencies
2
2
 
3
+ ## 7.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 232a84d: Backstage version bump to v1.42.5
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [232a84d]
12
+ - @backstage-community/plugin-rbac-common@1.20.0
13
+ - @backstage-community/plugin-rbac-node@1.14.0
14
+
15
+ ## 7.3.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 5260b5c: support config to set permission vs conditional policy evaluation order
20
+
3
21
  ## 7.2.0
4
22
 
5
23
  ### Minor Changes
package/README.md CHANGED
@@ -279,3 +279,17 @@ More information about group hierarchy can be found in the doc: [Group hierarchy
279
279
  ### Optional RBAC provider module support
280
280
 
281
281
  We also include the ability to create and load in RBAC backend plugin modules that can be used to make connections to third part access management tools. For more information, consult the [RBAC Providers documentation](./docs/providers.md).
282
+
283
+ ### Optional configuration to control policy decision precedence
284
+
285
+ Controls the evaluation order between permission policies (basic) and conditional policies for resource permissions.
286
+
287
+ - Default: `conditional` (conditional policies take precedence when present)
288
+ - Set to `basic` to evaluate basic permission policy first
289
+
290
+ ```YAML
291
+ permission:
292
+ enabled: true
293
+ rbac:
294
+ policyDecisionPrecedence: basic # or conditional
295
+ ```
package/config.d.ts CHANGED
@@ -63,6 +63,14 @@ export interface Config {
63
63
  * @visibility frontend
64
64
  */
65
65
  maxDepth?: number;
66
+ /**
67
+ * An optional value that controls evaluation order between basic permission policy and conditional policy for permissions.
68
+ * - Default: "conditional"
69
+ * - "basic": prefer permission policy first
70
+ * - "conditional": prefer conditional policies first
71
+ * @visibility frontend
72
+ */
73
+ policyDecisionPrecedence?: 'basic' | 'conditional';
66
74
  };
67
75
  };
68
76
  }
@@ -9,13 +9,15 @@ var csvFileWatcher = require('../file-permissions/csv-file-watcher.cjs.js');
9
9
  var yamlConditionalFileWatcher = require('../file-permissions/yaml-conditional-file-watcher.cjs.js');
10
10
 
11
11
  class RBACPermissionPolicy {
12
- constructor(enforcer, auditor, conditionStorage, superUserList) {
12
+ constructor(enforcer, auditor, conditionStorage, preferPermissionPolicy, superUserList) {
13
13
  this.enforcer = enforcer;
14
14
  this.auditor = auditor;
15
15
  this.conditionStorage = conditionStorage;
16
16
  this.superUserList = superUserList;
17
+ this.preferPermissionPolicy = preferPermissionPolicy;
17
18
  }
18
19
  superUserList;
20
+ preferPermissionPolicy;
19
21
  static async build(logger, auditor, configApi, conditionalStorage, enforcerDelegate, roleMetadataStorage, knex, pluginMetadataCollector, auth) {
20
22
  const superUserList = [];
21
23
  const adminUsers = configApi.getOptionalConfigArray(
@@ -31,6 +33,9 @@ class RBACPermissionPolicy {
31
33
  const conditionalPoliciesFile = configApi.getOptionalString(
32
34
  "permission.rbac.conditionalPoliciesFile"
33
35
  );
36
+ const preferPermissionPolicy = (configApi.getOptionalString(
37
+ "permission.rbac.policyDecisionPrecedence"
38
+ ) ?? "conditional") === "basic";
34
39
  if (superUsers && superUsers.length > 0) {
35
40
  for (const user of superUsers) {
36
41
  const userName = user.getString("name");
@@ -83,6 +88,7 @@ class RBACPermissionPolicy {
83
88
  enforcerDelegate,
84
89
  auditor,
85
90
  conditionalStorage,
91
+ preferPermissionPolicy,
86
92
  superUserList
87
93
  );
88
94
  }
@@ -110,7 +116,7 @@ class RBACPermissionPolicy {
110
116
  }
111
117
  const permissionName = request.permission.name;
112
118
  const roles = await this.enforcer.getRolesForUser(userEntityRef);
113
- const hasNamedPermission = await this.hasImplicitPermissionSpecifiedByName(
119
+ const hasNamedPermission = await this.hasImplicitPermission(
114
120
  permissionName,
115
121
  action,
116
122
  roles
@@ -125,20 +131,29 @@ class RBACPermissionPolicy {
125
131
  }
126
132
  if (pluginPermissionCommon.isResourcePermission(request.permission)) {
127
133
  const resourceType = request.permission.resourceType;
128
- if (user) {
129
- const conditionResult = await this.handleConditions(
130
- auditorEvent,
131
- userEntityRef,
132
- request,
133
- roles,
134
- user.info
134
+ const obj = hasNamedPermission ? permissionName : resourceType;
135
+ const conditionResult = await this.handleConditions(
136
+ auditorEvent,
137
+ userEntityRef,
138
+ request,
139
+ roles,
140
+ user.info
141
+ );
142
+ if (this.preferPermissionPolicy) {
143
+ const hasResourcedPermission = await this.hasImplicitPermission(
144
+ resourceType,
145
+ action,
146
+ roles
135
147
  );
136
- if (conditionResult) {
148
+ if (hasNamedPermission || hasResourcedPermission) {
149
+ status = await this.isAuthorized(userEntityRef, obj, action, roles);
150
+ } else if (conditionResult) {
137
151
  return conditionResult;
138
152
  }
153
+ } else {
154
+ if (conditionResult) return conditionResult;
155
+ status = await this.isAuthorized(userEntityRef, obj, action, roles);
139
156
  }
140
- const obj = hasNamedPermission ? permissionName : resourceType;
141
- status = await this.isAuthorized(userEntityRef, obj, action, roles);
142
157
  } else {
143
158
  status = await this.isAuthorized(
144
159
  userEntityRef,
@@ -158,7 +173,7 @@ class RBACPermissionPolicy {
158
173
  return { result: pluginPermissionCommon.AuthorizeResult.DENY };
159
174
  }
160
175
  }
161
- async hasImplicitPermissionSpecifiedByName(permissionName, action, roles) {
176
+ async hasImplicitPermission(permissionName, action, roles) {
162
177
  for (const role of roles) {
163
178
  const perms = await this.enforcer.getFilteredPolicy(
164
179
  0,
@@ -1 +1 @@
1
- {"version":3,"file":"permission-policy.cjs.js","sources":["../../src/policies/permission-policy.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type {\n AuditorService,\n AuditorServiceEvent,\n AuthService,\n BackstageUserInfo,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\nimport {\n AuthorizeResult,\n ConditionalPolicyDecision,\n isResourcePermission,\n PermissionCondition,\n PermissionCriteria,\n PermissionRuleParams,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type {\n PermissionPolicy,\n PolicyQuery,\n PolicyQueryUser,\n} from '@backstage/plugin-permission-node';\n\nimport type { Knex } from 'knex';\n\nimport {\n NonEmptyArray,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nimport {\n setAdminPermissions,\n useAdminsFromConfig,\n} from '../admin-permissions/admin-creation';\nimport { createPermissionEvaluationAuditorEvent } from '../auditor/auditor';\nimport { replaceAliases } from '../conditional-aliases/alias-resolver';\nimport { ConditionalStorage } from '../database/conditional-storage';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { CSVFileWatcher } from '../file-permissions/csv-file-watcher';\nimport { YamlConditinalPoliciesFileWatcher } from '../file-permissions/yaml-conditional-file-watcher';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from '../service/plugin-endpoints';\n\nexport class RBACPermissionPolicy implements PermissionPolicy {\n private readonly superUserList?: string[];\n\n public static async build(\n logger: LoggerService,\n auditor: AuditorService,\n configApi: ConfigApi,\n conditionalStorage: ConditionalStorage,\n enforcerDelegate: EnforcerDelegate,\n roleMetadataStorage: RoleMetadataStorage,\n knex: Knex,\n pluginMetadataCollector: PluginPermissionMetadataCollector,\n auth: AuthService,\n ): Promise<RBACPermissionPolicy> {\n const superUserList: string[] = [];\n const adminUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.users',\n );\n\n const superUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.superUsers',\n );\n\n const policiesFile = configApi.getOptionalString(\n 'permission.rbac.policies-csv-file',\n );\n\n const allowReload =\n configApi.getOptionalBoolean('permission.rbac.policyFileReload') || false;\n\n const conditionalPoliciesFile = configApi.getOptionalString(\n 'permission.rbac.conditionalPoliciesFile',\n );\n\n if (superUsers && superUsers.length > 0) {\n for (const user of superUsers) {\n const userName = user.getString('name');\n superUserList.push(userName);\n }\n }\n\n await useAdminsFromConfig(\n adminUsers || [],\n enforcerDelegate,\n auditor,\n roleMetadataStorage,\n knex,\n );\n await setAdminPermissions(enforcerDelegate, auditor);\n\n if (\n (!adminUsers || adminUsers.length === 0) &&\n (!superUsers || superUsers.length === 0)\n ) {\n logger.warn(\n 'There are no admins or super admins configured for the RBAC-backend plugin.',\n );\n }\n\n const csvFile = new CSVFileWatcher(\n policiesFile,\n allowReload,\n logger,\n enforcerDelegate,\n roleMetadataStorage,\n auditor,\n );\n await csvFile.initialize();\n\n const conditionalFile = new YamlConditinalPoliciesFileWatcher(\n conditionalPoliciesFile,\n allowReload,\n logger,\n conditionalStorage,\n auditor,\n auth,\n pluginMetadataCollector,\n roleMetadataStorage,\n enforcerDelegate,\n );\n await conditionalFile.initialize();\n\n if (!conditionalPoliciesFile) {\n // clean up conditional policies corresponding to roles from csv file\n logger.info('conditional policies file feature was disabled');\n await conditionalFile.cleanUpConditionalPolicies();\n }\n if (!policiesFile) {\n // remove roles and policies from csv file\n logger.info('csv policies file feature was disabled');\n await csvFile.cleanUpRolesAndPolicies();\n }\n\n return new RBACPermissionPolicy(\n enforcerDelegate,\n auditor,\n conditionalStorage,\n superUserList,\n );\n }\n\n private constructor(\n private readonly enforcer: EnforcerDelegate,\n private readonly auditor: AuditorService,\n private readonly conditionStorage: ConditionalStorage,\n superUserList?: string[],\n ) {\n this.superUserList = superUserList;\n }\n\n async handle(\n request: PolicyQuery,\n user?: PolicyQueryUser,\n ): Promise<PolicyDecision> {\n const userEntityRef = user?.info.userEntityRef ?? `user without entity`;\n\n const auditorEvent = await createPermissionEvaluationAuditorEvent(\n this.auditor,\n userEntityRef,\n request,\n );\n\n try {\n let status = false;\n const action = toPermissionAction(request.permission.attributes);\n\n if (!user) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n\n if (this.superUserList!.includes(userEntityRef)) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.ALLOW },\n });\n return { result: AuthorizeResult.ALLOW };\n }\n\n const permissionName = request.permission.name;\n const roles = await this.enforcer.getRolesForUser(userEntityRef);\n // handle permission with 'resource' type\n const hasNamedPermission =\n await this.hasImplicitPermissionSpecifiedByName(\n permissionName,\n action,\n roles,\n );\n\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n if (\n request.permission.name === 'policy.entity.create' &&\n !hasNamedPermission\n ) {\n request.permission = {\n attributes: { action: 'create' },\n type: 'resource',\n resourceType: 'policy-entity',\n name: 'policy.entity.create',\n };\n }\n\n if (isResourcePermission(request.permission)) {\n const resourceType = request.permission.resourceType;\n\n // handle conditions if they are present\n if (user) {\n const conditionResult = await this.handleConditions(\n auditorEvent,\n userEntityRef,\n request,\n roles,\n user.info,\n );\n if (conditionResult) {\n return conditionResult;\n }\n }\n\n // Let's set up higher priority for permission specified by name, than by resource type\n const obj = hasNamedPermission ? permissionName : resourceType;\n\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n } else {\n // handle permission with 'basic' type\n status = await this.isAuthorized(\n userEntityRef,\n permissionName,\n action,\n roles,\n );\n }\n\n const result = status ? AuthorizeResult.ALLOW : AuthorizeResult.DENY;\n\n await auditorEvent.success({ meta: { result } });\n return { result };\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n }\n\n private async hasImplicitPermissionSpecifiedByName(\n permissionName: string,\n action: string,\n roles: string[],\n ): Promise<boolean> {\n for (const role of roles) {\n const perms = await this.enforcer.getFilteredPolicy(\n 0,\n role,\n permissionName,\n action,\n );\n if (perms.length > 0) {\n return true;\n }\n }\n\n return false;\n }\n\n private isAuthorized = async (\n userIdentity: string,\n permission: string,\n action: string,\n roles: string[],\n ): Promise<boolean> => {\n return await this.enforcer.enforce(userIdentity, permission, action, roles);\n };\n\n private async handleConditions(\n auditorEvent: AuditorServiceEvent,\n userEntityRef: string,\n request: PolicyQuery,\n roles: string[],\n userInfo: BackstageUserInfo,\n ): Promise<PolicyDecision | undefined> {\n const permissionName = request.permission.name;\n const resourceType = (request.permission as ResourcePermission)\n .resourceType;\n const action = toPermissionAction(request.permission.attributes);\n\n const conditions: PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >[] = [];\n let pluginId = '';\n for (const role of roles) {\n const conditionalDecisions = await this.conditionStorage.filterConditions(\n role,\n undefined,\n resourceType,\n [action],\n [permissionName],\n );\n\n if (conditionalDecisions.length === 1) {\n pluginId = conditionalDecisions[0].pluginId;\n conditions.push(conditionalDecisions[0].conditions);\n }\n\n // this error is unexpected and should not happen, but just in case handle it.\n if (conditionalDecisions.length > 1) {\n await auditorEvent.fail({\n error: new Error(\n `Detected ${JSON.stringify(\n conditionalDecisions,\n )} collisions for conditional policies. Expected to find a stored single condition for permission with name ${permissionName}, resource type ${resourceType}, action ${action} for user ${userEntityRef}`,\n ),\n meta: { result: AuthorizeResult.DENY },\n });\n return {\n result: AuthorizeResult.DENY,\n };\n }\n }\n\n if (conditions.length > 0) {\n const result: ConditionalPolicyDecision = {\n pluginId,\n result: AuthorizeResult.CONDITIONAL,\n resourceType,\n conditions: {\n anyOf: conditions as NonEmptyArray<\n PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >\n >,\n },\n };\n\n replaceAliases(result.conditions, userInfo);\n\n await auditorEvent.success({ meta: { ...result } });\n return result;\n }\n return undefined;\n }\n}\n"],"names":["useAdminsFromConfig","setAdminPermissions","CSVFileWatcher","YamlConditinalPoliciesFileWatcher","createPermissionEvaluationAuditorEvent","toPermissionAction","AuthorizeResult","isResourcePermission","replaceAliases"],"mappings":";;;;;;;;;;AA2DO,MAAM,oBAAiD,CAAA;AAAA,EAqGpD,WACW,CAAA,QAAA,EACA,OACA,EAAA,gBAAA,EACjB,aACA,EAAA;AAJiB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA;AAGjB,IAAA,IAAA,CAAK,aAAgB,GAAA,aAAA;AAAA;AACvB,EA3GiB,aAAA;AAAA,EAEjB,aAAoB,KAClB,CAAA,MAAA,EACA,OACA,EAAA,SAAA,EACA,oBACA,gBACA,EAAA,mBAAA,EACA,IACA,EAAA,uBAAA,EACA,IAC+B,EAAA;AAC/B,IAAA,MAAM,gBAA0B,EAAC;AACjC,IAAA,MAAM,aAAa,SAAU,CAAA,sBAAA;AAAA,MAC3B;AAAA,KACF;AAEA,IAAA,MAAM,aAAa,SAAU,CAAA,sBAAA;AAAA,MAC3B;AAAA,KACF;AAEA,IAAA,MAAM,eAAe,SAAU,CAAA,iBAAA;AAAA,MAC7B;AAAA,KACF;AAEA,IAAA,MAAM,WACJ,GAAA,SAAA,CAAU,kBAAmB,CAAA,kCAAkC,CAAK,IAAA,KAAA;AAEtE,IAAA,MAAM,0BAA0B,SAAU,CAAA,iBAAA;AAAA,MACxC;AAAA,KACF;AAEA,IAAI,IAAA,UAAA,IAAc,UAAW,CAAA,MAAA,GAAS,CAAG,EAAA;AACvC,MAAA,KAAA,MAAW,QAAQ,UAAY,EAAA;AAC7B,QAAM,MAAA,QAAA,GAAW,IAAK,CAAA,SAAA,CAAU,MAAM,CAAA;AACtC,QAAA,aAAA,CAAc,KAAK,QAAQ,CAAA;AAAA;AAC7B;AAGF,IAAM,MAAAA,iCAAA;AAAA,MACJ,cAAc,EAAC;AAAA,MACf,gBAAA;AAAA,MACA,OAAA;AAAA,MACA,mBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAM,MAAAC,iCAAA,CAAoB,kBAAkB,OAAO,CAAA;AAEnD,IACG,IAAA,CAAA,CAAC,cAAc,UAAW,CAAA,MAAA,KAAW,OACrC,CAAC,UAAA,IAAc,UAAW,CAAA,MAAA,KAAW,CACtC,CAAA,EAAA;AACA,MAAO,MAAA,CAAA,IAAA;AAAA,QACL;AAAA,OACF;AAAA;AAGF,IAAA,MAAM,UAAU,IAAIC,6BAAA;AAAA,MAClB,YAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,gBAAA;AAAA,MACA,mBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,MAAM,QAAQ,UAAW,EAAA;AAEzB,IAAA,MAAM,kBAAkB,IAAIC,4DAAA;AAAA,MAC1B,uBAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,kBAAA;AAAA,MACA,OAAA;AAAA,MACA,IAAA;AAAA,MACA,uBAAA;AAAA,MACA,mBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,MAAM,gBAAgB,UAAW,EAAA;AAEjC,IAAA,IAAI,CAAC,uBAAyB,EAAA;AAE5B,MAAA,MAAA,CAAO,KAAK,gDAAgD,CAAA;AAC5D,MAAA,MAAM,gBAAgB,0BAA2B,EAAA;AAAA;AAEnD,IAAA,IAAI,CAAC,YAAc,EAAA;AAEjB,MAAA,MAAA,CAAO,KAAK,wCAAwC,CAAA;AACpD,MAAA,MAAM,QAAQ,uBAAwB,EAAA;AAAA;AAGxC,IAAA,OAAO,IAAI,oBAAA;AAAA,MACT,gBAAA;AAAA,MACA,OAAA;AAAA,MACA,kBAAA;AAAA,MACA;AAAA,KACF;AAAA;AACF,EAWA,MAAM,MACJ,CAAA,OAAA,EACA,IACyB,EAAA;AACzB,IAAM,MAAA,aAAA,GAAgB,IAAM,EAAA,IAAA,CAAK,aAAiB,IAAA,CAAA,mBAAA,CAAA;AAElD,IAAA,MAAM,eAAe,MAAMC,8CAAA;AAAA,MACzB,IAAK,CAAA,OAAA;AAAA,MACL,aAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAI,IAAA;AACF,MAAA,IAAI,MAAS,GAAA,KAAA;AACb,MAAA,MAAM,MAAS,GAAAC,mCAAA,CAAmB,OAAQ,CAAA,UAAA,CAAW,UAAU,CAAA;AAE/D,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,MAAM,aAAa,OAAQ,CAAA;AAAA,UACzB,IAAM,EAAA,EAAE,MAAQ,EAAAC,sCAAA,CAAgB,IAAK;AAAA,SACtC,CAAA;AACD,QAAO,OAAA,EAAE,MAAQ,EAAAA,sCAAA,CAAgB,IAAK,EAAA;AAAA;AAGxC,MAAA,IAAI,IAAK,CAAA,aAAA,CAAe,QAAS,CAAA,aAAa,CAAG,EAAA;AAC/C,QAAA,MAAM,aAAa,OAAQ,CAAA;AAAA,UACzB,IAAM,EAAA,EAAE,MAAQ,EAAAA,sCAAA,CAAgB,KAAM;AAAA,SACvC,CAAA;AACD,QAAO,OAAA,EAAE,MAAQ,EAAAA,sCAAA,CAAgB,KAAM,EAAA;AAAA;AAGzC,MAAM,MAAA,cAAA,GAAiB,QAAQ,UAAW,CAAA,IAAA;AAC1C,MAAA,MAAM,KAAQ,GAAA,MAAM,IAAK,CAAA,QAAA,CAAS,gBAAgB,aAAa,CAAA;AAE/D,MAAM,MAAA,kBAAA,GACJ,MAAM,IAAK,CAAA,oCAAA;AAAA,QACT,cAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACF;AAGF,MAAA,IACE,OAAQ,CAAA,UAAA,CAAW,IAAS,KAAA,sBAAA,IAC5B,CAAC,kBACD,EAAA;AACA,QAAA,OAAA,CAAQ,UAAa,GAAA;AAAA,UACnB,UAAA,EAAY,EAAE,MAAA,EAAQ,QAAS,EAAA;AAAA,UAC/B,IAAM,EAAA,UAAA;AAAA,UACN,YAAc,EAAA,eAAA;AAAA,UACd,IAAM,EAAA;AAAA,SACR;AAAA;AAGF,MAAI,IAAAC,2CAAA,CAAqB,OAAQ,CAAA,UAAU,CAAG,EAAA;AAC5C,QAAM,MAAA,YAAA,GAAe,QAAQ,UAAW,CAAA,YAAA;AAGxC,QAAA,IAAI,IAAM,EAAA;AACR,UAAM,MAAA,eAAA,GAAkB,MAAM,IAAK,CAAA,gBAAA;AAAA,YACjC,YAAA;AAAA,YACA,aAAA;AAAA,YACA,OAAA;AAAA,YACA,KAAA;AAAA,YACA,IAAK,CAAA;AAAA,WACP;AACA,UAAA,IAAI,eAAiB,EAAA;AACnB,YAAO,OAAA,eAAA;AAAA;AACT;AAIF,QAAM,MAAA,GAAA,GAAM,qBAAqB,cAAiB,GAAA,YAAA;AAElD,QAAA,MAAA,GAAS,MAAM,IAAK,CAAA,YAAA,CAAa,aAAe,EAAA,GAAA,EAAK,QAAQ,KAAK,CAAA;AAAA,OAC7D,MAAA;AAEL,QAAA,MAAA,GAAS,MAAM,IAAK,CAAA,YAAA;AAAA,UAClB,aAAA;AAAA,UACA,cAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACF;AAAA;AAGF,MAAA,MAAM,MAAS,GAAA,MAAA,GAASD,sCAAgB,CAAA,KAAA,GAAQA,sCAAgB,CAAA,IAAA;AAEhE,MAAA,MAAM,aAAa,OAAQ,CAAA,EAAE,MAAM,EAAE,MAAA,IAAU,CAAA;AAC/C,MAAA,OAAO,EAAE,MAAO,EAAA;AAAA,aACT,KAAO,EAAA;AACd,MAAA,MAAM,aAAa,IAAK,CAAA;AAAA,QACtB,KAAA;AAAA,QACA,IAAM,EAAA,EAAE,MAAQ,EAAAA,sCAAA,CAAgB,IAAK;AAAA,OACtC,CAAA;AACD,MAAO,OAAA,EAAE,MAAQ,EAAAA,sCAAA,CAAgB,IAAK,EAAA;AAAA;AACxC;AACF,EAEA,MAAc,oCAAA,CACZ,cACA,EAAA,MAAA,EACA,KACkB,EAAA;AAClB,IAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,MAAM,MAAA,KAAA,GAAQ,MAAM,IAAA,CAAK,QAAS,CAAA,iBAAA;AAAA,QAChC,CAAA;AAAA,QACA,IAAA;AAAA,QACA,cAAA;AAAA,QACA;AAAA,OACF;AACA,MAAI,IAAA,KAAA,CAAM,SAAS,CAAG,EAAA;AACpB,QAAO,OAAA,IAAA;AAAA;AACT;AAGF,IAAO,OAAA,KAAA;AAAA;AACT,EAEQ,YAAe,GAAA,OACrB,YACA,EAAA,UAAA,EACA,QACA,KACqB,KAAA;AACrB,IAAA,OAAO,MAAM,IAAK,CAAA,QAAA,CAAS,QAAQ,YAAc,EAAA,UAAA,EAAY,QAAQ,KAAK,CAAA;AAAA,GAC5E;AAAA,EAEA,MAAc,gBACZ,CAAA,YAAA,EACA,aACA,EAAA,OAAA,EACA,OACA,QACqC,EAAA;AACrC,IAAM,MAAA,cAAA,GAAiB,QAAQ,UAAW,CAAA,IAAA;AAC1C,IAAM,MAAA,YAAA,GAAgB,QAAQ,UAC3B,CAAA,YAAA;AACH,IAAA,MAAM,MAAS,GAAAD,mCAAA,CAAmB,OAAQ,CAAA,UAAA,CAAW,UAAU,CAAA;AAE/D,IAAA,MAAM,aAEA,EAAC;AACP,IAAA,IAAI,QAAW,GAAA,EAAA;AACf,IAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,MAAM,MAAA,oBAAA,GAAuB,MAAM,IAAA,CAAK,gBAAiB,CAAA,gBAAA;AAAA,QACvD,IAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA;AAAA,QACA,CAAC,MAAM,CAAA;AAAA,QACP,CAAC,cAAc;AAAA,OACjB;AAEA,MAAI,IAAA,oBAAA,CAAqB,WAAW,CAAG,EAAA;AACrC,QAAW,QAAA,GAAA,oBAAA,CAAqB,CAAC,CAAE,CAAA,QAAA;AACnC,QAAA,UAAA,CAAW,IAAK,CAAA,oBAAA,CAAqB,CAAC,CAAA,CAAE,UAAU,CAAA;AAAA;AAIpD,MAAI,IAAA,oBAAA,CAAqB,SAAS,CAAG,EAAA;AACnC,QAAA,MAAM,aAAa,IAAK,CAAA;AAAA,UACtB,OAAO,IAAI,KAAA;AAAA,YACT,YAAY,IAAK,CAAA,SAAA;AAAA,cACf;AAAA,aACD,6GAA6G,cAAc,CAAA,gBAAA,EAAmB,YAAY,CAAY,SAAA,EAAA,MAAM,aAAa,aAAa,CAAA;AAAA,WACzM;AAAA,UACA,IAAM,EAAA,EAAE,MAAQ,EAAAC,sCAAA,CAAgB,IAAK;AAAA,SACtC,CAAA;AACD,QAAO,OAAA;AAAA,UACL,QAAQA,sCAAgB,CAAA;AAAA,SAC1B;AAAA;AACF;AAGF,IAAI,IAAA,UAAA,CAAW,SAAS,CAAG,EAAA;AACzB,MAAA,MAAM,MAAoC,GAAA;AAAA,QACxC,QAAA;AAAA,QACA,QAAQA,sCAAgB,CAAA,WAAA;AAAA,QACxB,YAAA;AAAA,QACA,UAAY,EAAA;AAAA,UACV,KAAO,EAAA;AAAA;AAKT,OACF;AAEA,MAAeE,4BAAA,CAAA,MAAA,CAAO,YAAY,QAAQ,CAAA;AAE1C,MAAM,MAAA,YAAA,CAAa,QAAQ,EAAE,IAAA,EAAM,EAAE,GAAG,MAAA,IAAU,CAAA;AAClD,MAAO,OAAA,MAAA;AAAA;AAET,IAAO,OAAA,SAAA;AAAA;AAEX;;;;"}
1
+ {"version":3,"file":"permission-policy.cjs.js","sources":["../../src/policies/permission-policy.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type {\n AuditorService,\n AuditorServiceEvent,\n AuthService,\n BackstageUserInfo,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\nimport {\n AuthorizeResult,\n ConditionalPolicyDecision,\n isResourcePermission,\n PermissionCondition,\n PermissionCriteria,\n PermissionRuleParams,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type {\n PermissionPolicy,\n PolicyQuery,\n PolicyQueryUser,\n} from '@backstage/plugin-permission-node';\n\nimport type { Knex } from 'knex';\n\nimport {\n NonEmptyArray,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nimport {\n setAdminPermissions,\n useAdminsFromConfig,\n} from '../admin-permissions/admin-creation';\nimport { createPermissionEvaluationAuditorEvent } from '../auditor/auditor';\nimport { replaceAliases } from '../conditional-aliases/alias-resolver';\nimport { ConditionalStorage } from '../database/conditional-storage';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { CSVFileWatcher } from '../file-permissions/csv-file-watcher';\nimport { YamlConditinalPoliciesFileWatcher } from '../file-permissions/yaml-conditional-file-watcher';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from '../service/plugin-endpoints';\n\nexport class RBACPermissionPolicy implements PermissionPolicy {\n private readonly superUserList?: string[];\n private readonly preferPermissionPolicy: boolean;\n\n public static async build(\n logger: LoggerService,\n auditor: AuditorService,\n configApi: ConfigApi,\n conditionalStorage: ConditionalStorage,\n enforcerDelegate: EnforcerDelegate,\n roleMetadataStorage: RoleMetadataStorage,\n knex: Knex,\n pluginMetadataCollector: PluginPermissionMetadataCollector,\n auth: AuthService,\n ): Promise<RBACPermissionPolicy> {\n const superUserList: string[] = [];\n const adminUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.users',\n );\n\n const superUsers = configApi.getOptionalConfigArray(\n 'permission.rbac.admin.superUsers',\n );\n\n const policiesFile = configApi.getOptionalString(\n 'permission.rbac.policies-csv-file',\n );\n\n const allowReload =\n configApi.getOptionalBoolean('permission.rbac.policyFileReload') || false;\n\n const conditionalPoliciesFile = configApi.getOptionalString(\n 'permission.rbac.conditionalPoliciesFile',\n );\n\n const preferPermissionPolicy =\n (configApi.getOptionalString(\n 'permission.rbac.policyDecisionPrecedence',\n ) ?? 'conditional') === 'basic';\n\n if (superUsers && superUsers.length > 0) {\n for (const user of superUsers) {\n const userName = user.getString('name');\n superUserList.push(userName);\n }\n }\n\n await useAdminsFromConfig(\n adminUsers || [],\n enforcerDelegate,\n auditor,\n roleMetadataStorage,\n knex,\n );\n await setAdminPermissions(enforcerDelegate, auditor);\n\n if (\n (!adminUsers || adminUsers.length === 0) &&\n (!superUsers || superUsers.length === 0)\n ) {\n logger.warn(\n 'There are no admins or super admins configured for the RBAC-backend plugin.',\n );\n }\n\n const csvFile = new CSVFileWatcher(\n policiesFile,\n allowReload,\n logger,\n enforcerDelegate,\n roleMetadataStorage,\n auditor,\n );\n await csvFile.initialize();\n\n const conditionalFile = new YamlConditinalPoliciesFileWatcher(\n conditionalPoliciesFile,\n allowReload,\n logger,\n conditionalStorage,\n auditor,\n auth,\n pluginMetadataCollector,\n roleMetadataStorage,\n enforcerDelegate,\n );\n await conditionalFile.initialize();\n\n if (!conditionalPoliciesFile) {\n // clean up conditional policies corresponding to roles from csv file\n logger.info('conditional policies file feature was disabled');\n await conditionalFile.cleanUpConditionalPolicies();\n }\n if (!policiesFile) {\n // remove roles and policies from csv file\n logger.info('csv policies file feature was disabled');\n await csvFile.cleanUpRolesAndPolicies();\n }\n\n return new RBACPermissionPolicy(\n enforcerDelegate,\n auditor,\n conditionalStorage,\n preferPermissionPolicy,\n superUserList,\n );\n }\n\n private constructor(\n private readonly enforcer: EnforcerDelegate,\n private readonly auditor: AuditorService,\n private readonly conditionStorage: ConditionalStorage,\n preferPermissionPolicy: boolean,\n superUserList?: string[],\n ) {\n this.superUserList = superUserList;\n this.preferPermissionPolicy = preferPermissionPolicy;\n }\n\n async handle(\n request: PolicyQuery,\n user?: PolicyQueryUser,\n ): Promise<PolicyDecision> {\n const userEntityRef = user?.info.userEntityRef ?? `user without entity`;\n\n const auditorEvent = await createPermissionEvaluationAuditorEvent(\n this.auditor,\n userEntityRef,\n request,\n );\n\n try {\n let status = false;\n const action = toPermissionAction(request.permission.attributes);\n\n if (!user) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n\n if (this.superUserList!.includes(userEntityRef)) {\n await auditorEvent.success({\n meta: { result: AuthorizeResult.ALLOW },\n });\n return { result: AuthorizeResult.ALLOW };\n }\n\n const permissionName = request.permission.name;\n const roles = await this.enforcer.getRolesForUser(userEntityRef);\n // handle permission with 'resource' type\n const hasNamedPermission = await this.hasImplicitPermission(\n permissionName,\n action,\n roles,\n );\n\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n if (\n request.permission.name === 'policy.entity.create' &&\n !hasNamedPermission\n ) {\n request.permission = {\n attributes: { action: 'create' },\n type: 'resource',\n resourceType: 'policy-entity',\n name: 'policy.entity.create',\n };\n }\n\n if (isResourcePermission(request.permission)) {\n const resourceType = request.permission.resourceType;\n // Let's set up higher priority for permission specified by name, than by resource type\n const obj = hasNamedPermission ? permissionName : resourceType;\n // handle conditions if they are present\n const conditionResult = await this.handleConditions(\n auditorEvent,\n userEntityRef,\n request,\n roles,\n user.info,\n );\n\n if (this.preferPermissionPolicy) {\n const hasResourcedPermission = await this.hasImplicitPermission(\n resourceType,\n action,\n roles,\n );\n // Permission policy first\n if (hasNamedPermission || hasResourcedPermission) {\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n } else if (conditionResult) {\n return conditionResult;\n }\n } else {\n if (conditionResult) return conditionResult;\n status = await this.isAuthorized(userEntityRef, obj, action, roles);\n }\n } else {\n // handle permission with 'basic' type\n status = await this.isAuthorized(\n userEntityRef,\n permissionName,\n action,\n roles,\n );\n }\n\n const result = status ? AuthorizeResult.ALLOW : AuthorizeResult.DENY;\n\n await auditorEvent.success({ meta: { result } });\n return { result };\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { result: AuthorizeResult.DENY },\n });\n return { result: AuthorizeResult.DENY };\n }\n }\n\n private async hasImplicitPermission(\n permissionName: string,\n action: string,\n roles: string[],\n ): Promise<boolean> {\n for (const role of roles) {\n const perms = await this.enforcer.getFilteredPolicy(\n 0,\n role,\n permissionName,\n action,\n );\n if (perms.length > 0) {\n return true;\n }\n }\n\n return false;\n }\n\n private isAuthorized = async (\n userIdentity: string,\n permission: string,\n action: string,\n roles: string[],\n ): Promise<boolean> => {\n return await this.enforcer.enforce(userIdentity, permission, action, roles);\n };\n\n private async handleConditions(\n auditorEvent: AuditorServiceEvent,\n userEntityRef: string,\n request: PolicyQuery,\n roles: string[],\n userInfo: BackstageUserInfo,\n ): Promise<PolicyDecision | undefined> {\n const permissionName = request.permission.name;\n const resourceType = (request.permission as ResourcePermission)\n .resourceType;\n const action = toPermissionAction(request.permission.attributes);\n\n const conditions: PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >[] = [];\n let pluginId = '';\n for (const role of roles) {\n const conditionalDecisions = await this.conditionStorage.filterConditions(\n role,\n undefined,\n resourceType,\n [action],\n [permissionName],\n );\n\n if (conditionalDecisions.length === 1) {\n pluginId = conditionalDecisions[0].pluginId;\n conditions.push(conditionalDecisions[0].conditions);\n }\n\n // this error is unexpected and should not happen, but just in case handle it.\n if (conditionalDecisions.length > 1) {\n await auditorEvent.fail({\n error: new Error(\n `Detected ${JSON.stringify(\n conditionalDecisions,\n )} collisions for conditional policies. Expected to find a stored single condition for permission with name ${permissionName}, resource type ${resourceType}, action ${action} for user ${userEntityRef}`,\n ),\n meta: { result: AuthorizeResult.DENY },\n });\n return {\n result: AuthorizeResult.DENY,\n };\n }\n }\n\n if (conditions.length > 0) {\n const result: ConditionalPolicyDecision = {\n pluginId,\n result: AuthorizeResult.CONDITIONAL,\n resourceType,\n conditions: {\n anyOf: conditions as NonEmptyArray<\n PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >\n >,\n },\n };\n\n replaceAliases(result.conditions, userInfo);\n\n await auditorEvent.success({ meta: { ...result } });\n return result;\n }\n return undefined;\n }\n}\n"],"names":["useAdminsFromConfig","setAdminPermissions","CSVFileWatcher","YamlConditinalPoliciesFileWatcher","createPermissionEvaluationAuditorEvent","toPermissionAction","AuthorizeResult","isResourcePermission","replaceAliases"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-rbac-backend",
3
- "version": "7.2.0",
3
+ "version": "7.4.0",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -36,17 +36,17 @@
36
36
  "postpack": "backstage-cli package postpack"
37
37
  },
38
38
  "dependencies": {
39
- "@backstage-community/plugin-rbac-common": "^1.19.0",
40
- "@backstage-community/plugin-rbac-node": "^1.13.0",
41
- "@backstage/backend-defaults": "^0.11.1",
42
- "@backstage/backend-plugin-api": "^1.4.1",
43
- "@backstage/catalog-client": "^1.10.2",
39
+ "@backstage-community/plugin-rbac-common": "^1.20.0",
40
+ "@backstage-community/plugin-rbac-node": "^1.14.0",
41
+ "@backstage/backend-defaults": "^0.12.0",
42
+ "@backstage/backend-plugin-api": "^1.4.2",
43
+ "@backstage/catalog-client": "^1.11.0",
44
44
  "@backstage/catalog-model": "^1.7.5",
45
45
  "@backstage/errors": "^1.2.7",
46
- "@backstage/plugin-auth-node": "^0.6.5",
47
- "@backstage/plugin-permission-backend": "^0.7.2",
46
+ "@backstage/plugin-auth-node": "^0.6.6",
47
+ "@backstage/plugin-permission-backend": "^0.7.3",
48
48
  "@backstage/plugin-permission-common": "^0.9.1",
49
- "@backstage/plugin-permission-node": "^0.10.2",
49
+ "@backstage/plugin-permission-node": "^0.10.3",
50
50
  "@dagrejs/graphlib": "^2.1.13",
51
51
  "casbin": "^5.27.1",
52
52
  "chokidar": "^3.6.0",
@@ -61,11 +61,11 @@
61
61
  "zod-to-json-schema": "^3.24.5"
62
62
  },
63
63
  "devDependencies": {
64
- "@backstage/backend-test-utils": "^1.7.0",
65
- "@backstage/cli": "^0.33.1",
64
+ "@backstage/backend-test-utils": "^1.8.0",
65
+ "@backstage/cli": "^0.34.1",
66
66
  "@backstage/config": "^1.3.3",
67
67
  "@backstage/core-plugin-api": "^1.10.9",
68
- "@backstage/plugin-catalog-node": "^1.17.2",
68
+ "@backstage/plugin-catalog-node": "^1.18.0",
69
69
  "@backstage/types": "^1.2.1",
70
70
  "@types/express": "4.17.23",
71
71
  "@types/js-yaml": "^4.0.9",