@backstage-community/plugin-rbac-backend 5.2.9 → 5.2.10

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,11 @@
1
1
  ### Dependencies
2
2
 
3
+ ## 5.2.10
4
+
5
+ ### Patch Changes
6
+
7
+ - ba4b3e9: Use loadPolicy to keep the enforcer in sync for edit operations. It should keep the RBAC plugin in sync when the Backstage instance is scaled to multiple deployment replicas. Reuse the maximum database pool size value from the application configuration in the RBAC Casbin adapter.
8
+
3
9
  ## 5.2.9
4
10
 
5
11
  ### Patch Changes
@@ -38,6 +38,9 @@ const ListConditionEvents = {
38
38
  GET_CONDITION_RULES: "GetConditionRules",
39
39
  GET_CONDITION_RULES_ERROR: "GetConditionRulesError"
40
40
  };
41
+ const PoliciesData = {
42
+ FAILED_TO_FETCH_NEWER_PERMISSIONS: "FailedToFetchNewerPermissions"
43
+ };
41
44
  const ConditionEvents = {
42
45
  CREATE_CONDITION: "CreateCondition",
43
46
  UPDATE_CONDITION: "UpdateCondition",
@@ -53,6 +56,7 @@ const ConditionEvents = {
53
56
  };
54
57
  const RBAC_BACKEND = "rbac-backend";
55
58
  const HANDLE_RBAC_DATA_STAGE = "handleRBACData";
59
+ const FETCH_NEWER_PERMISSIONS_STAGE = "fetchNewerPermissions";
56
60
  const EVALUATE_PERMISSION_ACCESS_STAGE = "evaluatePermissionAccess";
57
61
  const SEND_RESPONSE_STAGE = "sendResponse";
58
62
  const RESPONSE_ERROR = "responseError";
@@ -96,10 +100,12 @@ function createPermissionEvaluationOptions(message, userEntityRef, request, poli
96
100
  exports.ConditionEvents = ConditionEvents;
97
101
  exports.EVALUATE_PERMISSION_ACCESS_STAGE = EVALUATE_PERMISSION_ACCESS_STAGE;
98
102
  exports.EvaluationEvents = EvaluationEvents;
103
+ exports.FETCH_NEWER_PERMISSIONS_STAGE = FETCH_NEWER_PERMISSIONS_STAGE;
99
104
  exports.HANDLE_RBAC_DATA_STAGE = HANDLE_RBAC_DATA_STAGE;
100
105
  exports.ListConditionEvents = ListConditionEvents;
101
106
  exports.ListPluginPoliciesEvents = ListPluginPoliciesEvents;
102
107
  exports.PermissionEvents = PermissionEvents;
108
+ exports.PoliciesData = PoliciesData;
103
109
  exports.RBAC_BACKEND = RBAC_BACKEND;
104
110
  exports.RESPONSE_ERROR = RESPONSE_ERROR;
105
111
  exports.RoleEvents = RoleEvents;
@@ -1 +1 @@
1
- {"version":3,"file":"audit-logger.cjs.js","sources":["../../src/audit-log/audit-logger.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 {\n AuthorizeResult,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type { PolicyQuery } from '@backstage/plugin-permission-node';\n\nimport type { AuditLogOptions } from '@janus-idp/backstage-plugin-audit-log-node';\n\nimport {\n PermissionAction,\n RoleConditionalPolicyDecision,\n Source,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nexport const RoleEvents = {\n CREATE_ROLE: 'CreateRole',\n UPDATE_ROLE: 'UpdateRole',\n DELETE_ROLE: 'DeleteRole',\n CREATE_OR_UPDATE_ROLE: 'CreateOrUpdateRole',\n GET_ROLE: 'GetRole',\n\n CREATE_ROLE_ERROR: 'CreateRoleError',\n UPDATE_ROLE_ERROR: 'UpdateRoleError',\n DELETE_ROLE_ERROR: 'DeleteRoleError',\n GET_ROLE_ERROR: 'GetRoleError',\n} as const;\n\nexport const PermissionEvents = {\n CREATE_POLICY: 'CreatePolicy',\n UPDATE_POLICY: 'UpdatePolicy',\n DELETE_POLICY: 'DeletePolicy',\n GET_POLICY: 'GetPolicy',\n\n CREATE_POLICY_ERROR: 'CreatePolicyError',\n UPDATE_POLICY_ERROR: 'UpdatePolicyError',\n DELETE_POLICY_ERROR: 'DeletePolicyError',\n GET_POLICY_ERROR: 'GetPolicyError',\n} as const;\n\nexport type RoleAuditInfo = {\n roleEntityRef: string;\n description?: string;\n source: Source;\n\n members: string[];\n};\n\nexport type PermissionAuditInfo = {\n policies: string[][];\n source: Source;\n};\n\nexport const EvaluationEvents = {\n PERMISSION_EVALUATION_STARTED: 'PermissionEvaluationStarted',\n PERMISSION_EVALUATION_COMPLETED: 'PermissionEvaluationCompleted',\n CONDITION_EVALUATION_COMPLETED: 'ConditionEvaluationCompleted',\n PERMISSION_EVALUATION_FAILED: 'PermissionEvaluationFailed',\n} as const;\n\nexport const ListPluginPoliciesEvents = {\n GET_PLUGINS_POLICIES: 'GetPluginsPolicies',\n GET_PLUGINS_POLICIES_ERROR: 'GetPluginsPoliciesError',\n};\n\nexport const ListConditionEvents = {\n GET_CONDITION_RULES: 'GetConditionRules',\n GET_CONDITION_RULES_ERROR: 'GetConditionRulesError',\n};\n\nexport type EvaluationAuditInfo = {\n userEntityRef: string;\n permissionName: string;\n action: PermissionAction;\n resourceType?: string;\n decision?: PolicyDecision;\n};\n\nexport const ConditionEvents = {\n CREATE_CONDITION: 'CreateCondition',\n UPDATE_CONDITION: 'UpdateCondition',\n DELETE_CONDITION: 'DeleteCondition',\n GET_CONDITION: 'GetCondition',\n\n CREATE_CONDITION_ERROR: 'CreateConditionError',\n UPDATE_CONDITION_ERROR: 'UpdateConditionError',\n DELETE_CONDITION_ERROR: 'DeleteConditionError',\n GET_CONDITION_ERROR: 'GetConditionError',\n PARSE_CONDITION_ERROR: 'ParseConditionError',\n CHANGE_CONDITIONAL_POLICIES_FILE_ERROR: 'ChangeConditionalPoliciesError',\n CONDITIONAL_POLICIES_FILE_NOT_FOUND: 'ConditionalPoliciesFileNotFound',\n};\n\nexport type ConditionAuditInfo = {\n condition: RoleConditionalPolicyDecision<PermissionAction>;\n};\n\nexport const RBAC_BACKEND = 'rbac-backend';\n\n// Audit log stage for processing Role-Based Access Control (RBAC) data\nexport const HANDLE_RBAC_DATA_STAGE = 'handleRBACData';\n\n// Audit log stage for determining access rights based on user permissions and resource information\nexport const EVALUATE_PERMISSION_ACCESS_STAGE = 'evaluatePermissionAccess';\n\n// Audit log stage for sending the response to the client about handled permission policies, roles, and condition policies\nexport const SEND_RESPONSE_STAGE = 'sendResponse';\nexport const RESPONSE_ERROR = 'responseError';\n\nexport function createPermissionEvaluationOptions(\n message: string,\n userEntityRef: string,\n request: PolicyQuery,\n policyDecision?: PolicyDecision,\n): AuditLogOptions<EvaluationAuditInfo> {\n const auditInfo: EvaluationAuditInfo = {\n userEntityRef,\n permissionName: request.permission.name,\n action: toPermissionAction(request.permission.attributes),\n };\n\n const resourceType = (request.permission as ResourcePermission).resourceType;\n if (resourceType) {\n auditInfo.resourceType = resourceType;\n }\n\n let eventName;\n if (!policyDecision) {\n eventName = EvaluationEvents.PERMISSION_EVALUATION_STARTED;\n } else {\n auditInfo.decision = policyDecision;\n\n switch (policyDecision.result) {\n case AuthorizeResult.DENY:\n case AuthorizeResult.ALLOW:\n eventName = EvaluationEvents.PERMISSION_EVALUATION_COMPLETED;\n break;\n case AuthorizeResult.CONDITIONAL:\n eventName = EvaluationEvents.CONDITION_EVALUATION_COMPLETED;\n break;\n default:\n throw new Error('Unknown policy decision result');\n }\n }\n\n return {\n actorId: userEntityRef,\n message,\n eventName,\n metadata: auditInfo,\n stage: EVALUATE_PERMISSION_ACCESS_STAGE,\n status: 'succeeded',\n };\n}\n"],"names":["toPermissionAction","AuthorizeResult"],"mappings":"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"}
1
+ {"version":3,"file":"audit-logger.cjs.js","sources":["../../src/audit-log/audit-logger.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 {\n AuthorizeResult,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type { PolicyQuery } from '@backstage/plugin-permission-node';\n\nimport type { AuditLogOptions } from '@janus-idp/backstage-plugin-audit-log-node';\n\nimport {\n PermissionAction,\n RoleConditionalPolicyDecision,\n Source,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nexport const RoleEvents = {\n CREATE_ROLE: 'CreateRole',\n UPDATE_ROLE: 'UpdateRole',\n DELETE_ROLE: 'DeleteRole',\n CREATE_OR_UPDATE_ROLE: 'CreateOrUpdateRole',\n GET_ROLE: 'GetRole',\n\n CREATE_ROLE_ERROR: 'CreateRoleError',\n UPDATE_ROLE_ERROR: 'UpdateRoleError',\n DELETE_ROLE_ERROR: 'DeleteRoleError',\n GET_ROLE_ERROR: 'GetRoleError',\n} as const;\n\nexport const PermissionEvents = {\n CREATE_POLICY: 'CreatePolicy',\n UPDATE_POLICY: 'UpdatePolicy',\n DELETE_POLICY: 'DeletePolicy',\n GET_POLICY: 'GetPolicy',\n\n CREATE_POLICY_ERROR: 'CreatePolicyError',\n UPDATE_POLICY_ERROR: 'UpdatePolicyError',\n DELETE_POLICY_ERROR: 'DeletePolicyError',\n GET_POLICY_ERROR: 'GetPolicyError',\n} as const;\n\nexport type RoleAuditInfo = {\n roleEntityRef: string;\n description?: string;\n source: Source;\n\n members: string[];\n};\n\nexport type PermissionAuditInfo = {\n policies: string[][];\n source: Source;\n};\n\nexport const EvaluationEvents = {\n PERMISSION_EVALUATION_STARTED: 'PermissionEvaluationStarted',\n PERMISSION_EVALUATION_COMPLETED: 'PermissionEvaluationCompleted',\n CONDITION_EVALUATION_COMPLETED: 'ConditionEvaluationCompleted',\n PERMISSION_EVALUATION_FAILED: 'PermissionEvaluationFailed',\n} as const;\n\nexport const ListPluginPoliciesEvents = {\n GET_PLUGINS_POLICIES: 'GetPluginsPolicies',\n GET_PLUGINS_POLICIES_ERROR: 'GetPluginsPoliciesError',\n};\n\nexport const ListConditionEvents = {\n GET_CONDITION_RULES: 'GetConditionRules',\n GET_CONDITION_RULES_ERROR: 'GetConditionRulesError',\n};\n\nexport type EvaluationAuditInfo = {\n userEntityRef: string;\n permissionName: string;\n action: PermissionAction;\n resourceType?: string;\n decision?: PolicyDecision;\n};\n\nexport const PoliciesData = {\n FAILED_TO_FETCH_NEWER_PERMISSIONS: 'FailedToFetchNewerPermissions',\n};\n\nexport const ConditionEvents = {\n CREATE_CONDITION: 'CreateCondition',\n UPDATE_CONDITION: 'UpdateCondition',\n DELETE_CONDITION: 'DeleteCondition',\n GET_CONDITION: 'GetCondition',\n\n CREATE_CONDITION_ERROR: 'CreateConditionError',\n UPDATE_CONDITION_ERROR: 'UpdateConditionError',\n DELETE_CONDITION_ERROR: 'DeleteConditionError',\n GET_CONDITION_ERROR: 'GetConditionError',\n PARSE_CONDITION_ERROR: 'ParseConditionError',\n CHANGE_CONDITIONAL_POLICIES_FILE_ERROR: 'ChangeConditionalPoliciesError',\n CONDITIONAL_POLICIES_FILE_NOT_FOUND: 'ConditionalPoliciesFileNotFound',\n};\n\nexport type ConditionAuditInfo = {\n condition: RoleConditionalPolicyDecision<PermissionAction>;\n};\n\nexport const RBAC_BACKEND = 'rbac-backend';\n\n// Audit log stage for processing Role-Based Access Control (RBAC) data\nexport const HANDLE_RBAC_DATA_STAGE = 'handleRBACData';\n\n// Audit log stage to refresh Role-Based Access Control (RBAC) data\nexport const FETCH_NEWER_PERMISSIONS_STAGE = 'fetchNewerPermissions';\n\n// Audit log stage for determining access rights based on user permissions and resource information\nexport const EVALUATE_PERMISSION_ACCESS_STAGE = 'evaluatePermissionAccess';\n\n// Audit log stage for sending the response to the client about handled permission policies, roles, and condition policies\nexport const SEND_RESPONSE_STAGE = 'sendResponse';\nexport const RESPONSE_ERROR = 'responseError';\n\nexport function createPermissionEvaluationOptions(\n message: string,\n userEntityRef: string,\n request: PolicyQuery,\n policyDecision?: PolicyDecision,\n): AuditLogOptions<EvaluationAuditInfo> {\n const auditInfo: EvaluationAuditInfo = {\n userEntityRef,\n permissionName: request.permission.name,\n action: toPermissionAction(request.permission.attributes),\n };\n\n const resourceType = (request.permission as ResourcePermission).resourceType;\n if (resourceType) {\n auditInfo.resourceType = resourceType;\n }\n\n let eventName;\n if (!policyDecision) {\n eventName = EvaluationEvents.PERMISSION_EVALUATION_STARTED;\n } else {\n auditInfo.decision = policyDecision;\n\n switch (policyDecision.result) {\n case AuthorizeResult.DENY:\n case AuthorizeResult.ALLOW:\n eventName = EvaluationEvents.PERMISSION_EVALUATION_COMPLETED;\n break;\n case AuthorizeResult.CONDITIONAL:\n eventName = EvaluationEvents.CONDITION_EVALUATION_COMPLETED;\n break;\n default:\n throw new Error('Unknown policy decision result');\n }\n }\n\n return {\n actorId: userEntityRef,\n message,\n eventName,\n metadata: auditInfo,\n stage: EVALUATE_PERMISSION_ACCESS_STAGE,\n status: 'succeeded',\n };\n}\n"],"names":["toPermissionAction","AuthorizeResult"],"mappings":"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"}
@@ -30,7 +30,8 @@ class CasbinDBAdapterFactory {
30
30
  password: databaseConfig?.getString("connection.password"),
31
31
  ssl,
32
32
  database: dbName,
33
- schema
33
+ schema,
34
+ poolSize: databaseConfig?.getOptionalNumber("knexConfig.pool.max")
34
35
  });
35
36
  }
36
37
  if (client === "better-sqlite3") {
@@ -1 +1 @@
1
- {"version":3,"file":"casbin-adapter-factory.cjs.js","sources":["../../src/database/casbin-adapter-factory.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 { Config } from '@backstage/config';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\n\nimport { Knex } from 'knex';\nimport TypeORMAdapter from 'typeorm-adapter';\n\nimport { resolve } from 'path';\nimport type { ConnectionOptions, TlsOptions } from 'tls';\n\nimport '@backstage/backend-defaults/database';\n\nconst DEFAULT_SQLITE3_STORAGE_FILE_NAME = 'rbac.sqlite';\n\nexport class CasbinDBAdapterFactory {\n public constructor(\n private readonly config: ConfigApi,\n private readonly databaseClient: Knex,\n ) {}\n\n public async createAdapter(): Promise<TypeORMAdapter> {\n const databaseConfig = this.config.getOptionalConfig('backend.database');\n const client = databaseConfig?.getOptionalString('client');\n\n let adapter;\n if (client === 'pg') {\n const dbName =\n await this.databaseClient.client.config.connection.database;\n const schema =\n (await this.databaseClient.client.searchPath?.[0]) ?? 'public';\n\n const ssl = this.handlePostgresSSL(databaseConfig!);\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'postgres',\n host: databaseConfig?.getString('connection.host'),\n port: databaseConfig?.getNumber('connection.port'),\n username: databaseConfig?.getString('connection.user'),\n password: databaseConfig?.getString('connection.password'),\n ssl,\n database: dbName,\n schema: schema,\n });\n }\n\n if (client === 'better-sqlite3') {\n let storage;\n if (typeof databaseConfig?.get('connection')?.valueOf() === 'string') {\n storage = databaseConfig?.getString('connection');\n } else if (databaseConfig?.has('connection.directory')) {\n const storageDir = databaseConfig?.getString('connection.directory');\n storage = resolve(storageDir, DEFAULT_SQLITE3_STORAGE_FILE_NAME);\n }\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'better-sqlite3',\n // Storage type or path to the storage.\n database: storage || ':memory:',\n });\n }\n\n if (!adapter) {\n throw new Error(`Unsupported database client ${client}`);\n }\n\n return adapter;\n }\n\n private handlePostgresSSL(\n dbConfig: Config,\n ): boolean | TlsOptions | undefined {\n const connection = dbConfig.getOptional<Knex.PgConnectionConfig | string>(\n 'connection',\n );\n if (!connection) {\n return undefined;\n }\n\n if (typeof connection === 'string' || connection instanceof String) {\n throw new Error(\n `rbac backend plugin doesn't support postgres connection in a string format yet`,\n );\n }\n\n const ssl: boolean | ConnectionOptions | undefined = connection.ssl;\n\n if (ssl === undefined) {\n return undefined;\n }\n\n if (typeof ssl === 'boolean') {\n return ssl;\n }\n\n if (typeof ssl === 'object') {\n const { ca, rejectUnauthorized } = ssl as ConnectionOptions;\n const tlsOpts = { ca, rejectUnauthorized };\n\n // SSL object was defined with some options that we don't support yet.\n if (Object.values(tlsOpts).every(el => el === undefined)) {\n return true;\n }\n\n return tlsOpts;\n }\n\n return undefined;\n }\n}\n"],"names":["TypeORMAdapter","resolve"],"mappings":"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"}
1
+ {"version":3,"file":"casbin-adapter-factory.cjs.js","sources":["../../src/database/casbin-adapter-factory.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 { Config } from '@backstage/config';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\n\nimport { Knex } from 'knex';\nimport TypeORMAdapter from 'typeorm-adapter';\n\nimport { resolve } from 'path';\nimport type { ConnectionOptions, TlsOptions } from 'tls';\n\nimport '@backstage/backend-defaults/database';\n\nconst DEFAULT_SQLITE3_STORAGE_FILE_NAME = 'rbac.sqlite';\n\nexport class CasbinDBAdapterFactory {\n public constructor(\n private readonly config: ConfigApi,\n private readonly databaseClient: Knex,\n ) {}\n\n public async createAdapter(): Promise<TypeORMAdapter> {\n const databaseConfig = this.config.getOptionalConfig('backend.database');\n const client = databaseConfig?.getOptionalString('client');\n\n let adapter;\n if (client === 'pg') {\n const dbName =\n await this.databaseClient.client.config.connection.database;\n const schema =\n (await this.databaseClient.client.searchPath?.[0]) ?? 'public';\n\n const ssl = this.handlePostgresSSL(databaseConfig!);\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'postgres',\n host: databaseConfig?.getString('connection.host'),\n port: databaseConfig?.getNumber('connection.port'),\n username: databaseConfig?.getString('connection.user'),\n password: databaseConfig?.getString('connection.password'),\n ssl,\n database: dbName,\n schema: schema,\n poolSize: databaseConfig?.getOptionalNumber('knexConfig.pool.max'),\n });\n }\n\n if (client === 'better-sqlite3') {\n let storage;\n if (typeof databaseConfig?.get('connection')?.valueOf() === 'string') {\n storage = databaseConfig?.getString('connection');\n } else if (databaseConfig?.has('connection.directory')) {\n const storageDir = databaseConfig?.getString('connection.directory');\n storage = resolve(storageDir, DEFAULT_SQLITE3_STORAGE_FILE_NAME);\n }\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'better-sqlite3',\n // Storage type or path to the storage.\n database: storage || ':memory:',\n });\n }\n\n if (!adapter) {\n throw new Error(`Unsupported database client ${client}`);\n }\n\n return adapter;\n }\n\n private handlePostgresSSL(\n dbConfig: Config,\n ): boolean | TlsOptions | undefined {\n const connection = dbConfig.getOptional<Knex.PgConnectionConfig | string>(\n 'connection',\n );\n if (!connection) {\n return undefined;\n }\n\n if (typeof connection === 'string' || connection instanceof String) {\n throw new Error(\n `rbac backend plugin doesn't support postgres connection in a string format yet`,\n );\n }\n\n const ssl: boolean | ConnectionOptions | undefined = connection.ssl;\n\n if (ssl === undefined) {\n return undefined;\n }\n\n if (typeof ssl === 'boolean') {\n return ssl;\n }\n\n if (typeof ssl === 'object') {\n const { ca, rejectUnauthorized } = ssl as ConnectionOptions;\n const tlsOpts = { ca, rejectUnauthorized };\n\n // SSL object was defined with some options that we don't support yet.\n if (Object.values(tlsOpts).every(el => el === undefined)) {\n return true;\n }\n\n return tlsOpts;\n }\n\n return undefined;\n }\n}\n"],"names":["TypeORMAdapter","resolve"],"mappings":"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"}
@@ -114,6 +114,7 @@ class RBACPermissionPolicy {
114
114
  return { result: pluginPermissionCommon.AuthorizeResult.DENY };
115
115
  }
116
116
  const permissionName = request.permission.name;
117
+ await this.enforcer.loadPolicy();
117
118
  const roles = await this.enforcer.getRolesForUser(userEntityRef);
118
119
  if (pluginPermissionCommon.isResourcePermission(request.permission)) {
119
120
  const resourceType = request.permission.resourceType;
@@ -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 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 Permission,\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 { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\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 {\n createPermissionEvaluationOptions,\n EVALUATE_PERMISSION_ACCESS_STAGE,\n EvaluationEvents,\n} from '../audit-log/audit-logger';\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\nconst evaluatePermMsg = (\n userEntityRef: string | undefined,\n result: AuthorizeResult,\n permission: Permission,\n) =>\n `${userEntityRef} is ${result} for permission '${permission.name}'${\n isResourcePermission(permission)\n ? `, resource type '${permission.resourceType}'`\n : ''\n } and action '${toPermissionAction(permission.attributes)}'`;\n\nexport class RBACPermissionPolicy implements PermissionPolicy {\n private readonly superUserList?: string[];\n\n public static async build(\n logger: LoggerService,\n auditLogger: AuditLogger,\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 auditLogger,\n roleMetadataStorage,\n knex,\n );\n await setAdminPermissions(enforcerDelegate, auditLogger);\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 auditLogger,\n );\n await csvFile.initialize();\n\n const conditionalFile = new YamlConditinalPoliciesFileWatcher(\n conditionalPoliciesFile,\n allowReload,\n logger,\n conditionalStorage,\n auditLogger,\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 auditLogger,\n conditionalStorage,\n superUserList,\n );\n }\n\n private constructor(\n private readonly enforcer: EnforcerDelegate,\n private readonly auditLogger: AuditLogger,\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 let auditOptions = createPermissionEvaluationOptions(\n `Policy check for ${userEntityRef}`,\n userEntityRef,\n request,\n );\n this.auditLogger.auditLog(auditOptions);\n\n try {\n let status = false;\n\n const action = toPermissionAction(request.permission.attributes);\n if (!user) {\n const msg = evaluatePermMsg(\n userEntityRef,\n AuthorizeResult.DENY,\n request.permission,\n );\n auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n { result: AuthorizeResult.DENY },\n );\n await this.auditLogger.auditLog(auditOptions);\n return { result: AuthorizeResult.DENY };\n }\n\n const permissionName = request.permission.name;\n const roles = await this.enforcer.getRolesForUser(userEntityRef);\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 userEntityRef,\n request,\n roles,\n user.info,\n );\n if (conditionResult) {\n return conditionResult;\n }\n }\n\n // handle permission with 'resource' type\n const hasNamedPermission =\n await this.hasImplicitPermissionSpecifiedByName(\n userEntityRef,\n permissionName,\n action,\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 const msg = evaluatePermMsg(userEntityRef, result, request.permission);\n auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n { result },\n );\n await this.auditLogger.auditLog(auditOptions);\n return { result };\n } catch (error) {\n await this.auditLogger.auditLog({\n message: 'Permission policy check failed',\n eventName: EvaluationEvents.PERMISSION_EVALUATION_FAILED,\n stage: EVALUATE_PERMISSION_ACCESS_STAGE,\n status: 'failed',\n errors: [error],\n });\n return { result: AuthorizeResult.DENY };\n }\n }\n\n private async hasImplicitPermissionSpecifiedByName(\n userEntityRef: string,\n permissionName: string,\n action: string,\n ): Promise<boolean> {\n const userPerms =\n await this.enforcer.getImplicitPermissionsForUser(userEntityRef);\n for (const perm of userPerms) {\n if (permissionName === perm[1] && action === perm[2]) {\n return true;\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 if (this.superUserList!.includes(userIdentity)) {\n return true;\n }\n\n return await this.enforcer.enforce(userIdentity, permission, action, roles);\n };\n\n private async handleConditions(\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 const msg = `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 const auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n { result: AuthorizeResult.DENY },\n );\n await this.auditLogger.auditLog(auditOptions);\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 const msg = `Send condition to plugin with id ${pluginId} to evaluate permission ${permissionName} with resource type ${resourceType} and action ${action} for user ${userEntityRef}`;\n const auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n result,\n );\n await this.auditLogger.auditLog(auditOptions);\n return result;\n }\n return undefined;\n }\n}\n"],"names":["isResourcePermission","toPermissionAction","useAdminsFromConfig","setAdminPermissions","CSVFileWatcher","YamlConditinalPoliciesFileWatcher","createPermissionEvaluationOptions","msg","AuthorizeResult","EvaluationEvents","EVALUATE_PERMISSION_ACCESS_STAGE","replaceAliases"],"mappings":"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"}
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 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 Permission,\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 { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\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 {\n createPermissionEvaluationOptions,\n EVALUATE_PERMISSION_ACCESS_STAGE,\n EvaluationEvents,\n} from '../audit-log/audit-logger';\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\nconst evaluatePermMsg = (\n userEntityRef: string | undefined,\n result: AuthorizeResult,\n permission: Permission,\n) =>\n `${userEntityRef} is ${result} for permission '${permission.name}'${\n isResourcePermission(permission)\n ? `, resource type '${permission.resourceType}'`\n : ''\n } and action '${toPermissionAction(permission.attributes)}'`;\n\nexport class RBACPermissionPolicy implements PermissionPolicy {\n private readonly superUserList?: string[];\n\n public static async build(\n logger: LoggerService,\n auditLogger: AuditLogger,\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 auditLogger,\n roleMetadataStorage,\n knex,\n );\n await setAdminPermissions(enforcerDelegate, auditLogger);\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 auditLogger,\n );\n await csvFile.initialize();\n\n const conditionalFile = new YamlConditinalPoliciesFileWatcher(\n conditionalPoliciesFile,\n allowReload,\n logger,\n conditionalStorage,\n auditLogger,\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 auditLogger,\n conditionalStorage,\n superUserList,\n );\n }\n\n private constructor(\n private readonly enforcer: EnforcerDelegate,\n private readonly auditLogger: AuditLogger,\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 let auditOptions = createPermissionEvaluationOptions(\n `Policy check for ${userEntityRef}`,\n userEntityRef,\n request,\n );\n this.auditLogger.auditLog(auditOptions);\n\n try {\n let status = false;\n\n const action = toPermissionAction(request.permission.attributes);\n if (!user) {\n const msg = evaluatePermMsg(\n userEntityRef,\n AuthorizeResult.DENY,\n request.permission,\n );\n auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n { result: AuthorizeResult.DENY },\n );\n await this.auditLogger.auditLog(auditOptions);\n return { result: AuthorizeResult.DENY };\n }\n\n const permissionName = request.permission.name;\n await this.enforcer.loadPolicy();\n const roles = await this.enforcer.getRolesForUser(userEntityRef);\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 userEntityRef,\n request,\n roles,\n user.info,\n );\n if (conditionResult) {\n return conditionResult;\n }\n }\n\n // handle permission with 'resource' type\n const hasNamedPermission =\n await this.hasImplicitPermissionSpecifiedByName(\n userEntityRef,\n permissionName,\n action,\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 const msg = evaluatePermMsg(userEntityRef, result, request.permission);\n auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n { result },\n );\n await this.auditLogger.auditLog(auditOptions);\n return { result };\n } catch (error) {\n await this.auditLogger.auditLog({\n message: 'Permission policy check failed',\n eventName: EvaluationEvents.PERMISSION_EVALUATION_FAILED,\n stage: EVALUATE_PERMISSION_ACCESS_STAGE,\n status: 'failed',\n errors: [error],\n });\n return { result: AuthorizeResult.DENY };\n }\n }\n\n private async hasImplicitPermissionSpecifiedByName(\n userEntityRef: string,\n permissionName: string,\n action: string,\n ): Promise<boolean> {\n const userPerms =\n await this.enforcer.getImplicitPermissionsForUser(userEntityRef);\n for (const perm of userPerms) {\n if (permissionName === perm[1] && action === perm[2]) {\n return true;\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 if (this.superUserList!.includes(userIdentity)) {\n return true;\n }\n\n return await this.enforcer.enforce(userIdentity, permission, action, roles);\n };\n\n private async handleConditions(\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 const msg = `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 const auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n { result: AuthorizeResult.DENY },\n );\n await this.auditLogger.auditLog(auditOptions);\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 const msg = `Send condition to plugin with id ${pluginId} to evaluate permission ${permissionName} with resource type ${resourceType} and action ${action} for user ${userEntityRef}`;\n const auditOptions = createPermissionEvaluationOptions(\n msg,\n userEntityRef,\n request,\n result,\n );\n await this.auditLogger.auditLog(auditOptions);\n return result;\n }\n return undefined;\n }\n}\n"],"names":["isResourcePermission","toPermissionAction","useAdminsFromConfig","setAdminPermissions","CSVFileWatcher","YamlConditinalPoliciesFileWatcher","createPermissionEvaluationOptions","msg","AuthorizeResult","EvaluationEvents","EVALUATE_PERMISSION_ACCESS_STAGE","replaceAliases"],"mappings":"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"}
@@ -22,6 +22,7 @@ class Connection {
22
22
  new casbin.StringAdapter(stringPolicy)
23
23
  );
24
24
  const providerRoles = await this.getProviderRoles();
25
+ await this.enforcer.loadPolicy();
25
26
  for (const providerRole of providerRoles) {
26
27
  providerRolesforRemoval.push(
27
28
  ...await this.enforcer.getFilteredGroupingPolicy(1, providerRole)
@@ -38,6 +39,7 @@ class Connection {
38
39
  new casbin.StringAdapter(stringPolicy)
39
40
  );
40
41
  const providerRoles = await this.getProviderRoles();
42
+ await this.enforcer.loadPolicy();
41
43
  for (const providerRole of providerRoles) {
42
44
  providerPermissions.push(
43
45
  ...await this.enforcer.getFilteredPolicy(0, providerRole)
@@ -1 +1 @@
1
- {"version":3,"file":"connect-providers.cjs.js","sources":["../../src/providers/connect-providers.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 { LoggerService } from '@backstage/backend-plugin-api';\n\nimport type { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport {\n Enforcer,\n newEnforcer,\n newModelFromString,\n StringAdapter,\n} from 'casbin';\n\nimport type {\n RBACProvider,\n RBACProviderConnection,\n} from '@backstage-community/plugin-rbac-node';\n\nimport {\n HANDLE_RBAC_DATA_STAGE,\n PermissionAuditInfo,\n PermissionEvents,\n RBAC_BACKEND,\n RoleAuditInfo,\n RoleEvents,\n} from '../audit-log/audit-logger';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { transformArrayToPolicy, typedPoliciesToString } from '../helper';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { MODEL } from '../service/permission-model';\nimport {\n validateGroupingPolicy,\n validatePolicy,\n validateSource,\n} from '../validation/policies-validation';\n\nexport class Connection implements RBACProviderConnection {\n constructor(\n private readonly id: string,\n private readonly enforcer: EnforcerDelegate,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly logger: LoggerService,\n private readonly auditLogger: AuditLogger,\n ) {}\n\n async applyRoles(roles: string[][]): Promise<void> {\n const stringPolicy = typedPoliciesToString(roles, 'g');\n\n const providerRolesforRemoval: string[][] = [];\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new StringAdapter(stringPolicy),\n );\n\n const providerRoles = await this.getProviderRoles();\n\n // Get the roles for this provider coming from rbac plugin\n for (const providerRole of providerRoles) {\n providerRolesforRemoval.push(\n ...(await this.enforcer.getFilteredGroupingPolicy(1, providerRole)),\n );\n }\n\n // Remove role\n // role exists in rbac but does not exist in provider\n await this.removeRoles(providerRolesforRemoval, tempEnforcer);\n\n // Add the role\n // role exists in provider but does not exist in rbac\n await this.addRoles(roles);\n }\n\n async applyPermissions(permissions: string[][]): Promise<void> {\n const stringPolicy = typedPoliciesToString(permissions, 'p');\n\n const providerPermissions: string[][] = [];\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new StringAdapter(stringPolicy),\n );\n\n const providerRoles = await this.getProviderRoles();\n\n // Get the roles for this provider coming from rbac plugin\n for (const providerRole of providerRoles) {\n providerPermissions.push(\n ...(await this.enforcer.getFilteredPolicy(0, providerRole)),\n );\n }\n\n await this.removePermissions(providerPermissions, tempEnforcer);\n\n await this.addPermissions(permissions);\n }\n\n private async addRoles(roles: string[][]): Promise<void> {\n for (const role of roles) {\n if (!(await this.enforcer.hasGroupingPolicy(...role))) {\n const err = await validateGroupingPolicy(\n role,\n this.roleMetadataStorage,\n this.id,\n );\n\n if (err) {\n this.logger.warn(err.message);\n continue; // Skip adding this role as there was an error\n }\n\n let roleMeta = await this.roleMetadataStorage.findRoleMetadata(role[1]);\n\n const eventName = roleMeta\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.CREATE_ROLE;\n const message = roleMeta ? 'Updated role' : 'Created role';\n\n // role does not exist in rbac, create the metadata for it\n if (!roleMeta) {\n roleMeta = {\n modifiedBy: this.id,\n source: this.id,\n roleEntityRef: role[1],\n };\n }\n\n await this.enforcer.addGroupingPolicy(role, roleMeta);\n\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMeta, members: [role[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async removeRoles(\n providerRoles: string[][],\n tempEnforcer: Enforcer,\n ): Promise<void> {\n // Remove role\n // role exists in rbac but does not exist in provider\n for (const role of providerRoles) {\n if (!(await tempEnforcer.hasGroupingPolicy(...role))) {\n const roleMeta = await this.roleMetadataStorage.findRoleMetadata(\n role[1],\n );\n\n const currentRole = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n role[1],\n );\n\n if (!roleMeta) {\n this.logger.warn('role does not exist');\n continue;\n }\n\n const singleRole = roleMeta && currentRole.length === 1;\n\n let eventName: string;\n let message: string;\n\n // Only one role exists in rbac remove role metadata as well\n if (singleRole) {\n eventName = RoleEvents.DELETE_ROLE;\n message = 'Deleted role';\n await this.enforcer.removeGroupingPolicy(role, roleMeta);\n\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMeta, members: [role[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n continue; // Move on to the next role\n }\n\n eventName = RoleEvents.UPDATE_ROLE;\n message = 'Updated role: deleted members';\n await this.enforcer.removeGroupingPolicy(role, roleMeta, true);\n\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMeta, members: [role[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async addPermissions(permissions: string[][]): Promise<void> {\n for (const permission of permissions) {\n if (!(await this.enforcer.hasPolicy(...permission))) {\n const transformedPolicy = transformArrayToPolicy(permission);\n const metadata = await this.roleMetadataStorage.findRoleMetadata(\n permission[0],\n );\n\n let err = validatePolicy(transformedPolicy);\n if (err) {\n this.logger.warn(`Invalid permission policy, ${err}`);\n continue; // Skip this invalid permission policy\n }\n\n err = await validateSource(this.id, metadata);\n if (err) {\n this.logger.warn(\n `Unable to add policy ${permission}. Cause: ${err.message}`,\n );\n continue;\n }\n\n await this.enforcer.addPolicy(permission);\n\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created policy`,\n eventName: PermissionEvents.CREATE_POLICY,\n metadata: { policies: [permission], source: this.id },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async removePermissions(\n providerPermissions: string[][],\n tempEnforcer: Enforcer,\n ): Promise<void> {\n const removedPermissions: string[][] = [];\n for (const permission of providerPermissions) {\n if (!(await tempEnforcer.hasPolicy(...permission))) {\n await this.enforcer.removePolicy(permission);\n removedPermissions.push(permission);\n }\n\n if (removedPermissions.length > 0) {\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Deleted policies`,\n eventName: PermissionEvents.DELETE_POLICY,\n metadata: {\n policies: removedPermissions,\n source: this.id,\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async getProviderRoles(): Promise<string[]> {\n const currentRoles = await this.roleMetadataStorage.filterRoleMetadata(\n this.id,\n );\n return currentRoles.map(meta => meta.roleEntityRef);\n }\n}\n\nexport async function connectRBACProviders(\n providers: RBACProvider[],\n enforcer: EnforcerDelegate,\n roleMetadataStorage: RoleMetadataStorage,\n logger: LoggerService,\n auditLogger: AuditLogger,\n) {\n await Promise.all(\n providers.map(async provider => {\n try {\n const connection = new Connection(\n provider.getProviderName(),\n enforcer,\n roleMetadataStorage,\n logger,\n auditLogger,\n );\n return provider.connect(connection);\n } catch (error) {\n throw new Error(\n `Unable to connect provider ${provider.getProviderName()}, ${error}`,\n );\n }\n }),\n );\n}\n"],"names":["typedPoliciesToString","newEnforcer","newModelFromString","MODEL","StringAdapter","validateGroupingPolicy","RoleEvents","RBAC_BACKEND","HANDLE_RBAC_DATA_STAGE","transformArrayToPolicy","validatePolicy","validateSource","PermissionEvents"],"mappings":"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"}
1
+ {"version":3,"file":"connect-providers.cjs.js","sources":["../../src/providers/connect-providers.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 { LoggerService } from '@backstage/backend-plugin-api';\n\nimport type { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport {\n Enforcer,\n newEnforcer,\n newModelFromString,\n StringAdapter,\n} from 'casbin';\n\nimport type {\n RBACProvider,\n RBACProviderConnection,\n} from '@backstage-community/plugin-rbac-node';\n\nimport {\n HANDLE_RBAC_DATA_STAGE,\n PermissionAuditInfo,\n PermissionEvents,\n RBAC_BACKEND,\n RoleAuditInfo,\n RoleEvents,\n} from '../audit-log/audit-logger';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { transformArrayToPolicy, typedPoliciesToString } from '../helper';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { MODEL } from '../service/permission-model';\nimport {\n validateGroupingPolicy,\n validatePolicy,\n validateSource,\n} from '../validation/policies-validation';\n\nexport class Connection implements RBACProviderConnection {\n constructor(\n private readonly id: string,\n private readonly enforcer: EnforcerDelegate,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly logger: LoggerService,\n private readonly auditLogger: AuditLogger,\n ) {}\n\n async applyRoles(roles: string[][]): Promise<void> {\n const stringPolicy = typedPoliciesToString(roles, 'g');\n\n const providerRolesforRemoval: string[][] = [];\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new StringAdapter(stringPolicy),\n );\n\n const providerRoles = await this.getProviderRoles();\n\n await this.enforcer.loadPolicy();\n // Get the roles for this provider coming from rbac plugin\n for (const providerRole of providerRoles) {\n providerRolesforRemoval.push(\n ...(await this.enforcer.getFilteredGroupingPolicy(1, providerRole)),\n );\n }\n\n // Remove role\n // role exists in rbac but does not exist in provider\n await this.removeRoles(providerRolesforRemoval, tempEnforcer);\n\n // Add the role\n // role exists in provider but does not exist in rbac\n await this.addRoles(roles);\n }\n\n async applyPermissions(permissions: string[][]): Promise<void> {\n const stringPolicy = typedPoliciesToString(permissions, 'p');\n\n const providerPermissions: string[][] = [];\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new StringAdapter(stringPolicy),\n );\n\n const providerRoles = await this.getProviderRoles();\n\n await this.enforcer.loadPolicy();\n // Get the roles for this provider coming from rbac plugin\n for (const providerRole of providerRoles) {\n providerPermissions.push(\n ...(await this.enforcer.getFilteredPolicy(0, providerRole)),\n );\n }\n\n await this.removePermissions(providerPermissions, tempEnforcer);\n\n await this.addPermissions(permissions);\n }\n\n private async addRoles(roles: string[][]): Promise<void> {\n for (const role of roles) {\n if (!(await this.enforcer.hasGroupingPolicy(...role))) {\n const err = await validateGroupingPolicy(\n role,\n this.roleMetadataStorage,\n this.id,\n );\n\n if (err) {\n this.logger.warn(err.message);\n continue; // Skip adding this role as there was an error\n }\n\n let roleMeta = await this.roleMetadataStorage.findRoleMetadata(role[1]);\n\n const eventName = roleMeta\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.CREATE_ROLE;\n const message = roleMeta ? 'Updated role' : 'Created role';\n\n // role does not exist in rbac, create the metadata for it\n if (!roleMeta) {\n roleMeta = {\n modifiedBy: this.id,\n source: this.id,\n roleEntityRef: role[1],\n };\n }\n\n await this.enforcer.addGroupingPolicy(role, roleMeta);\n\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMeta, members: [role[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async removeRoles(\n providerRoles: string[][],\n tempEnforcer: Enforcer,\n ): Promise<void> {\n // Remove role\n // role exists in rbac but does not exist in provider\n for (const role of providerRoles) {\n if (!(await tempEnforcer.hasGroupingPolicy(...role))) {\n const roleMeta = await this.roleMetadataStorage.findRoleMetadata(\n role[1],\n );\n\n const currentRole = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n role[1],\n );\n\n if (!roleMeta) {\n this.logger.warn('role does not exist');\n continue;\n }\n\n const singleRole = roleMeta && currentRole.length === 1;\n\n let eventName: string;\n let message: string;\n\n // Only one role exists in rbac remove role metadata as well\n if (singleRole) {\n eventName = RoleEvents.DELETE_ROLE;\n message = 'Deleted role';\n await this.enforcer.removeGroupingPolicy(role, roleMeta);\n\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMeta, members: [role[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n continue; // Move on to the next role\n }\n\n eventName = RoleEvents.UPDATE_ROLE;\n message = 'Updated role: deleted members';\n await this.enforcer.removeGroupingPolicy(role, roleMeta, true);\n\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMeta, members: [role[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async addPermissions(permissions: string[][]): Promise<void> {\n for (const permission of permissions) {\n if (!(await this.enforcer.hasPolicy(...permission))) {\n const transformedPolicy = transformArrayToPolicy(permission);\n const metadata = await this.roleMetadataStorage.findRoleMetadata(\n permission[0],\n );\n\n let err = validatePolicy(transformedPolicy);\n if (err) {\n this.logger.warn(`Invalid permission policy, ${err}`);\n continue; // Skip this invalid permission policy\n }\n\n err = await validateSource(this.id, metadata);\n if (err) {\n this.logger.warn(\n `Unable to add policy ${permission}. Cause: ${err.message}`,\n );\n continue;\n }\n\n await this.enforcer.addPolicy(permission);\n\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created policy`,\n eventName: PermissionEvents.CREATE_POLICY,\n metadata: { policies: [permission], source: this.id },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async removePermissions(\n providerPermissions: string[][],\n tempEnforcer: Enforcer,\n ): Promise<void> {\n const removedPermissions: string[][] = [];\n for (const permission of providerPermissions) {\n if (!(await tempEnforcer.hasPolicy(...permission))) {\n await this.enforcer.removePolicy(permission);\n removedPermissions.push(permission);\n }\n\n if (removedPermissions.length > 0) {\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Deleted policies`,\n eventName: PermissionEvents.DELETE_POLICY,\n metadata: {\n policies: removedPermissions,\n source: this.id,\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n }\n }\n\n private async getProviderRoles(): Promise<string[]> {\n const currentRoles = await this.roleMetadataStorage.filterRoleMetadata(\n this.id,\n );\n return currentRoles.map(meta => meta.roleEntityRef);\n }\n}\n\nexport async function connectRBACProviders(\n providers: RBACProvider[],\n enforcer: EnforcerDelegate,\n roleMetadataStorage: RoleMetadataStorage,\n logger: LoggerService,\n auditLogger: AuditLogger,\n) {\n await Promise.all(\n providers.map(async provider => {\n try {\n const connection = new Connection(\n provider.getProviderName(),\n enforcer,\n roleMetadataStorage,\n logger,\n auditLogger,\n );\n return provider.connect(connection);\n } catch (error) {\n throw new Error(\n `Unable to connect provider ${provider.getProviderName()}, ${error}`,\n );\n }\n }),\n );\n}\n"],"names":["typedPoliciesToString","newEnforcer","newModelFromString","MODEL","StringAdapter","validateGroupingPolicy","RoleEvents","RBAC_BACKEND","HANDLE_RBAC_DATA_STAGE","transformArrayToPolicy","validatePolicy","validateSource","PermissionEvents"],"mappings":"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"}
@@ -5,18 +5,66 @@ var EventEmitter = require('events');
5
5
  var adminCreation = require('../admin-permissions/admin-creation.cjs.js');
6
6
  var helper = require('../helper.cjs.js');
7
7
  var permissionModel = require('./permission-model.cjs.js');
8
+ var auditLogger = require('../audit-log/audit-logger.cjs.js');
8
9
 
9
10
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
10
11
 
11
12
  var EventEmitter__default = /*#__PURE__*/_interopDefaultCompat(EventEmitter);
12
13
 
13
14
  class EnforcerDelegate {
14
- constructor(enforcer, roleMetadataStorage, knex) {
15
+ // Queue to track edit operations
16
+ constructor(enforcer, auditLogger, roleMetadataStorage, knex) {
15
17
  this.enforcer = enforcer;
18
+ this.auditLogger = auditLogger;
16
19
  this.roleMetadataStorage = roleMetadataStorage;
17
20
  this.knex = knex;
18
21
  }
19
22
  roleEventEmitter = new EventEmitter__default.default();
23
+ loadPolicyPromise = null;
24
+ semaphore = 0;
25
+ editOperationsQueue = [];
26
+ async loadPolicy() {
27
+ if (this.loadPolicyPromise) {
28
+ return this.loadPolicyPromise;
29
+ }
30
+ this.semaphore++;
31
+ this.loadPolicyPromise = (async () => {
32
+ try {
33
+ await this.waitForEditOperationsToFinish();
34
+ await this.enforcer.loadPolicy();
35
+ } catch (err) {
36
+ this.auditLogger.auditLog({
37
+ message: "Failed to load newer policies from database",
38
+ eventName: auditLogger.PoliciesData.FAILED_TO_FETCH_NEWER_PERMISSIONS,
39
+ stage: auditLogger.FETCH_NEWER_PERMISSIONS_STAGE,
40
+ status: "failed",
41
+ errors: [err]
42
+ });
43
+ } finally {
44
+ this.semaphore--;
45
+ this.loadPolicyPromise = null;
46
+ }
47
+ })();
48
+ return this.loadPolicyPromise;
49
+ }
50
+ async waitForEditOperationsToFinish() {
51
+ await Promise.all(this.editOperationsQueue);
52
+ }
53
+ async execOperation(operation) {
54
+ this.editOperationsQueue.push(operation);
55
+ let result;
56
+ try {
57
+ result = await operation;
58
+ } catch (err) {
59
+ throw err;
60
+ } finally {
61
+ const index = this.editOperationsQueue.indexOf(operation);
62
+ if (index !== -1) {
63
+ this.editOperationsQueue.splice(index, 1);
64
+ }
65
+ }
66
+ return result;
67
+ }
20
68
  on(event, listener) {
21
69
  this.roleEventEmitter.on(event, listener);
22
70
  return this;
@@ -119,110 +167,128 @@ class EnforcerDelegate {
119
167
  }
120
168
  }
121
169
  async addPolicies(policies, externalTrx) {
122
- if (policies.length === 0) {
123
- return;
170
+ if (this.loadPolicyPromise) {
171
+ await this.loadPolicyPromise;
124
172
  }
125
- const trx = externalTrx || await this.knex.transaction();
126
- try {
127
- const ok = await this.enforcer.addPolicies(policies);
128
- if (!ok) {
129
- throw new Error(
130
- `Failed to store policies ${helper.policiesToString(policies)}`
131
- );
132
- }
133
- if (!externalTrx) {
134
- await trx.commit();
135
- }
136
- } catch (err) {
137
- if (!externalTrx) {
138
- await trx.rollback(err);
173
+ const addPoliciesOperation = (async () => {
174
+ if (policies.length === 0) {
175
+ return;
176
+ }
177
+ const trx = externalTrx || await this.knex.transaction();
178
+ try {
179
+ const ok = await this.enforcer.addPolicies(policies);
180
+ if (!ok) {
181
+ throw new Error(
182
+ `Failed to store policies ${helper.policiesToString(policies)}`
183
+ );
184
+ }
185
+ if (!externalTrx) {
186
+ await trx.commit();
187
+ }
188
+ } catch (err) {
189
+ if (!externalTrx) {
190
+ await trx.rollback(err);
191
+ }
192
+ throw err;
139
193
  }
140
- throw err;
141
- }
194
+ })();
195
+ await this.execOperation(addPoliciesOperation);
142
196
  }
143
197
  async addGroupingPolicy(policy, roleMetadata, externalTrx) {
144
- const trx = externalTrx ?? await this.knex.transaction();
145
- const entityRef = roleMetadata.roleEntityRef;
146
- if (await this.hasGroupingPolicy(...policy)) {
147
- return;
198
+ if (this.loadPolicyPromise) {
199
+ await this.loadPolicyPromise;
148
200
  }
149
- try {
150
- let currentMetadata;
151
- if (entityRef.startsWith(`role:`)) {
152
- currentMetadata = await this.roleMetadataStorage.findRoleMetadata(
153
- entityRef,
154
- trx
155
- );
156
- }
157
- if (currentMetadata) {
158
- await this.roleMetadataStorage.updateRoleMetadata(
159
- helper.mergeRoleMetadata(currentMetadata, roleMetadata),
160
- entityRef,
161
- trx
162
- );
163
- } else {
164
- const currentDate = /* @__PURE__ */ new Date();
165
- roleMetadata.createdAt = currentDate.toUTCString();
166
- roleMetadata.lastModified = currentDate.toUTCString();
167
- await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);
168
- }
169
- const ok = await this.enforcer.addGroupingPolicy(...policy);
170
- if (!ok) {
171
- throw new Error(`failed to create policy ${helper.policyToString(policy)}`);
172
- }
173
- if (!externalTrx) {
174
- await trx.commit();
175
- }
176
- if (!currentMetadata) {
177
- this.roleEventEmitter.emit("roleAdded", roleMetadata.roleEntityRef);
178
- }
179
- } catch (err) {
180
- if (!externalTrx) {
181
- await trx.rollback(err);
201
+ const addGroupingPolicyOperation = (async () => {
202
+ const trx = externalTrx ?? await this.knex.transaction();
203
+ const entityRef = roleMetadata.roleEntityRef;
204
+ if (await this.hasGroupingPolicy(...policy)) {
205
+ return;
206
+ }
207
+ try {
208
+ let currentMetadata;
209
+ if (entityRef.startsWith(`role:`)) {
210
+ currentMetadata = await this.roleMetadataStorage.findRoleMetadata(
211
+ entityRef,
212
+ trx
213
+ );
214
+ }
215
+ if (currentMetadata) {
216
+ await this.roleMetadataStorage.updateRoleMetadata(
217
+ helper.mergeRoleMetadata(currentMetadata, roleMetadata),
218
+ entityRef,
219
+ trx
220
+ );
221
+ } else {
222
+ const currentDate = /* @__PURE__ */ new Date();
223
+ roleMetadata.createdAt = currentDate.toUTCString();
224
+ roleMetadata.lastModified = currentDate.toUTCString();
225
+ await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);
226
+ }
227
+ const ok = await this.enforcer.addGroupingPolicy(...policy);
228
+ if (!ok) {
229
+ throw new Error(`failed to create policy ${helper.policyToString(policy)}`);
230
+ }
231
+ if (!externalTrx) {
232
+ await trx.commit();
233
+ }
234
+ if (!currentMetadata) {
235
+ this.roleEventEmitter.emit("roleAdded", roleMetadata.roleEntityRef);
236
+ }
237
+ } catch (err) {
238
+ if (!externalTrx) {
239
+ await trx.rollback(err);
240
+ }
241
+ throw err;
182
242
  }
183
- throw err;
184
- }
243
+ })();
244
+ await this.execOperation(addGroupingPolicyOperation);
185
245
  }
186
246
  async addGroupingPolicies(policies, roleMetadata, externalTrx) {
187
- if (policies.length === 0) {
188
- return;
247
+ if (this.loadPolicyPromise) {
248
+ await this.loadPolicyPromise;
189
249
  }
190
- const trx = externalTrx ?? await this.knex.transaction();
191
- try {
192
- const currentRoleMetadata = await this.roleMetadataStorage.findRoleMetadata(
193
- roleMetadata.roleEntityRef,
194
- trx
195
- );
196
- if (currentRoleMetadata) {
197
- await this.roleMetadataStorage.updateRoleMetadata(
198
- helper.mergeRoleMetadata(currentRoleMetadata, roleMetadata),
250
+ const addGroupingPoliciesOperation = (async () => {
251
+ if (policies.length === 0) {
252
+ return;
253
+ }
254
+ const trx = externalTrx ?? await this.knex.transaction();
255
+ try {
256
+ const currentRoleMetadata = await this.roleMetadataStorage.findRoleMetadata(
199
257
  roleMetadata.roleEntityRef,
200
258
  trx
201
259
  );
202
- } else {
203
- const currentDate = /* @__PURE__ */ new Date();
204
- roleMetadata.createdAt = currentDate.toUTCString();
205
- roleMetadata.lastModified = currentDate.toUTCString();
206
- await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);
207
- }
208
- const ok = await this.enforcer.addGroupingPolicies(policies);
209
- if (!ok) {
210
- throw new Error(
211
- `Failed to store policies ${helper.policiesToString(policies)}`
212
- );
213
- }
214
- if (!externalTrx) {
215
- await trx.commit();
216
- }
217
- if (!currentRoleMetadata) {
218
- this.roleEventEmitter.emit("roleAdded", roleMetadata.roleEntityRef);
219
- }
220
- } catch (err) {
221
- if (!externalTrx) {
222
- await trx.rollback(err);
260
+ if (currentRoleMetadata) {
261
+ await this.roleMetadataStorage.updateRoleMetadata(
262
+ helper.mergeRoleMetadata(currentRoleMetadata, roleMetadata),
263
+ roleMetadata.roleEntityRef,
264
+ trx
265
+ );
266
+ } else {
267
+ const currentDate = /* @__PURE__ */ new Date();
268
+ roleMetadata.createdAt = currentDate.toUTCString();
269
+ roleMetadata.lastModified = currentDate.toUTCString();
270
+ await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);
271
+ }
272
+ const ok = await this.enforcer.addGroupingPolicies(policies);
273
+ if (!ok) {
274
+ throw new Error(
275
+ `Failed to store policies ${helper.policiesToString(policies)}`
276
+ );
277
+ }
278
+ if (!externalTrx) {
279
+ await trx.commit();
280
+ }
281
+ if (!currentRoleMetadata) {
282
+ this.roleEventEmitter.emit("roleAdded", roleMetadata.roleEntityRef);
283
+ }
284
+ } catch (err) {
285
+ if (!externalTrx) {
286
+ await trx.rollback(err);
287
+ }
288
+ throw err;
223
289
  }
224
- throw err;
225
- }
290
+ })();
291
+ await this.execOperation(addGroupingPoliciesOperation);
226
292
  }
227
293
  async updateGroupingPolicies(oldRole, newRole, newRoleMetadata) {
228
294
  const oldRoleName = oldRole.at(0)?.at(1);
@@ -255,110 +321,134 @@ class EnforcerDelegate {
255
321
  }
256
322
  }
257
323
  async removePolicy(policy, externalTrx) {
258
- const trx = externalTrx ?? await this.knex.transaction();
259
- try {
260
- const ok = await this.enforcer.removePolicy(...policy);
261
- if (!ok) {
262
- throw new Error(`fail to delete policy ${policy}`);
263
- }
264
- if (!externalTrx) {
265
- await trx.commit();
266
- }
267
- } catch (err) {
268
- if (!externalTrx) {
269
- await trx.rollback(err);
270
- }
271
- throw err;
324
+ if (this.loadPolicyPromise) {
325
+ await this.loadPolicyPromise;
272
326
  }
327
+ const removePolicyOperation = (async () => {
328
+ const trx = externalTrx ?? await this.knex.transaction();
329
+ try {
330
+ const ok = await this.enforcer.removePolicy(...policy);
331
+ if (!ok) {
332
+ throw new Error(`fail to delete policy ${policy}`);
333
+ }
334
+ if (!externalTrx) {
335
+ await trx.commit();
336
+ }
337
+ } catch (err) {
338
+ if (!externalTrx) {
339
+ await trx.rollback(err);
340
+ }
341
+ throw err;
342
+ }
343
+ })();
344
+ await this.execOperation(removePolicyOperation);
273
345
  }
274
346
  async removePolicies(policies, externalTrx) {
275
- const trx = externalTrx ?? await this.knex.transaction();
276
- try {
277
- const ok = await this.enforcer.removePolicies(policies);
278
- if (!ok) {
279
- throw new Error(
280
- `Failed to delete policies ${helper.policiesToString(policies)}`
281
- );
282
- }
283
- if (!externalTrx) {
284
- await trx.commit();
285
- }
286
- } catch (err) {
287
- if (!externalTrx) {
288
- await trx.rollback(err);
289
- }
290
- throw err;
347
+ if (this.loadPolicyPromise) {
348
+ await this.loadPolicyPromise;
291
349
  }
350
+ const removePoliciesOperation = (async () => {
351
+ const trx = externalTrx ?? await this.knex.transaction();
352
+ try {
353
+ const ok = await this.enforcer.removePolicies(policies);
354
+ if (!ok) {
355
+ throw new Error(
356
+ `Failed to delete policies ${helper.policiesToString(policies)}`
357
+ );
358
+ }
359
+ if (!externalTrx) {
360
+ await trx.commit();
361
+ }
362
+ } catch (err) {
363
+ if (!externalTrx) {
364
+ await trx.rollback(err);
365
+ }
366
+ throw err;
367
+ }
368
+ })();
369
+ await this.execOperation(removePoliciesOperation);
292
370
  }
293
371
  async removeGroupingPolicy(policy, roleMetadata, isUpdate, externalTrx) {
294
- const trx = externalTrx ?? await this.knex.transaction();
295
- const roleEntity = policy[1];
296
- try {
297
- const ok = await this.enforcer.removeGroupingPolicy(...policy);
298
- if (!ok) {
299
- throw new Error(`Failed to delete policy ${helper.policyToString(policy)}`);
300
- }
301
- if (!isUpdate) {
302
- const currentRoleMetadata = await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);
303
- const remainingGroupPolicies = await this.getFilteredGroupingPolicy(
304
- 1,
305
- roleEntity
306
- );
307
- if (currentRoleMetadata && remainingGroupPolicies.length === 0 && roleEntity !== adminCreation.ADMIN_ROLE_NAME) {
308
- await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);
309
- } else if (currentRoleMetadata) {
310
- await this.roleMetadataStorage.updateRoleMetadata(
311
- helper.mergeRoleMetadata(currentRoleMetadata, roleMetadata),
312
- roleEntity,
313
- trx
372
+ if (this.loadPolicyPromise) {
373
+ await this.loadPolicyPromise;
374
+ }
375
+ const removeGroupingPolicyOperation = (async () => {
376
+ const trx = externalTrx ?? await this.knex.transaction();
377
+ const roleEntity = policy[1];
378
+ try {
379
+ const ok = await this.enforcer.removeGroupingPolicy(...policy);
380
+ if (!ok) {
381
+ throw new Error(`Failed to delete policy ${helper.policyToString(policy)}`);
382
+ }
383
+ if (!isUpdate) {
384
+ const currentRoleMetadata = await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);
385
+ const remainingGroupPolicies = await this.getFilteredGroupingPolicy(
386
+ 1,
387
+ roleEntity
314
388
  );
389
+ if (currentRoleMetadata && remainingGroupPolicies.length === 0 && roleEntity !== adminCreation.ADMIN_ROLE_NAME) {
390
+ await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);
391
+ } else if (currentRoleMetadata) {
392
+ await this.roleMetadataStorage.updateRoleMetadata(
393
+ helper.mergeRoleMetadata(currentRoleMetadata, roleMetadata),
394
+ roleEntity,
395
+ trx
396
+ );
397
+ }
315
398
  }
399
+ if (!externalTrx) {
400
+ await trx.commit();
401
+ }
402
+ } catch (err) {
403
+ if (!externalTrx) {
404
+ await trx.rollback(err);
405
+ }
406
+ throw err;
316
407
  }
317
- if (!externalTrx) {
318
- await trx.commit();
319
- }
320
- } catch (err) {
321
- if (!externalTrx) {
322
- await trx.rollback(err);
323
- }
324
- throw err;
325
- }
408
+ })();
409
+ await this.execOperation(removeGroupingPolicyOperation);
326
410
  }
327
411
  async removeGroupingPolicies(policies, roleMetadata, isUpdate, externalTrx) {
328
- const trx = externalTrx ?? await this.knex.transaction();
329
- const roleEntity = roleMetadata.roleEntityRef;
330
- try {
331
- const ok = await this.enforcer.removeGroupingPolicies(policies);
332
- if (!ok) {
333
- throw new Error(
334
- `Failed to delete grouping policies: ${helper.policiesToString(policies)}`
335
- );
336
- }
337
- if (!isUpdate) {
338
- const currentRoleMetadata = await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);
339
- const remainingGroupPolicies = await this.getFilteredGroupingPolicy(
340
- 1,
341
- roleEntity
342
- );
343
- if (currentRoleMetadata && remainingGroupPolicies.length === 0 && roleEntity !== adminCreation.ADMIN_ROLE_NAME) {
344
- await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);
345
- } else if (currentRoleMetadata) {
346
- await this.roleMetadataStorage.updateRoleMetadata(
347
- helper.mergeRoleMetadata(currentRoleMetadata, roleMetadata),
348
- roleEntity,
349
- trx
412
+ if (this.loadPolicyPromise) {
413
+ await this.loadPolicyPromise;
414
+ }
415
+ const removeGroupingPolicyOperation = (async () => {
416
+ const trx = externalTrx ?? await this.knex.transaction();
417
+ const roleEntity = roleMetadata.roleEntityRef;
418
+ try {
419
+ const ok = await this.enforcer.removeGroupingPolicies(policies);
420
+ if (!ok) {
421
+ throw new Error(
422
+ `Failed to delete grouping policies: ${helper.policiesToString(policies)}`
350
423
  );
351
424
  }
425
+ if (!isUpdate) {
426
+ const currentRoleMetadata = await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);
427
+ const remainingGroupPolicies = await this.getFilteredGroupingPolicy(
428
+ 1,
429
+ roleEntity
430
+ );
431
+ if (currentRoleMetadata && remainingGroupPolicies.length === 0 && roleEntity !== adminCreation.ADMIN_ROLE_NAME) {
432
+ await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);
433
+ } else if (currentRoleMetadata) {
434
+ await this.roleMetadataStorage.updateRoleMetadata(
435
+ helper.mergeRoleMetadata(currentRoleMetadata, roleMetadata),
436
+ roleEntity,
437
+ trx
438
+ );
439
+ }
440
+ }
441
+ if (!externalTrx) {
442
+ await trx.commit();
443
+ }
444
+ } catch (err) {
445
+ if (!externalTrx) {
446
+ await trx.rollback(err);
447
+ }
448
+ throw err;
352
449
  }
353
- if (!externalTrx) {
354
- await trx.commit();
355
- }
356
- } catch (err) {
357
- if (!externalTrx) {
358
- await trx.rollback(err);
359
- }
360
- throw err;
361
- }
450
+ })();
451
+ await this.execOperation(removeGroupingPolicyOperation);
362
452
  }
363
453
  /**
364
454
  * enforce aims to enforce a particular permission policy based on the user that it receives.
@@ -374,7 +464,8 @@ class EnforcerDelegate {
374
464
  * The temporary enforcer has lazy loading of the permission policies enabled to reduce the amount
375
465
  * of time it takes to initialize the temporary enforcer.
376
466
  * The justification for lazy loading is because permission policies are already present in the
377
- * role manager / database and it will be filtered and loaded whenever `loadFilteredPolicy` is called.
467
+ * role manager / database and it will be filtered and loaded whenever `getFilteredPolicy` is called
468
+ * and permissions / roles are applied to the temp enforcer
378
469
  * @param entityRef The user to enforce
379
470
  * @param resourceType The resource type / name of the permission policy
380
471
  * @param action The action of the permission policy
@@ -383,31 +474,49 @@ class EnforcerDelegate {
383
474
  * @returns True if the user is allowed based on the particular permission
384
475
  */
385
476
  async enforce(entityRef, resourceType, action, roles) {
386
- const filter = [];
387
- if (roles.length > 0) {
388
- roles.forEach((role) => {
389
- filter.push({ ptype: "p", v0: role, v1: resourceType, v2: action });
390
- });
391
- } else {
392
- filter.push({ ptype: "p", v1: resourceType, v2: action });
477
+ if (this.loadPolicyPromise) {
478
+ await this.loadPolicyPromise;
393
479
  }
394
- const adapt = this.enforcer.getAdapter();
395
- const roleManager = this.enforcer.getRoleManager();
396
- const tempEnforcer = new casbin.Enforcer();
397
- await tempEnforcer.initWithModelAndAdapter(
398
- casbin.newModelFromString(permissionModel.MODEL),
399
- adapt,
400
- true
401
- );
402
- tempEnforcer.setRoleManager(roleManager);
403
- await tempEnforcer.loadFilteredPolicy(filter);
404
- return await tempEnforcer.enforce(entityRef, resourceType, action);
480
+ const evaluatePermissionOperation = (async () => {
481
+ const filter = [];
482
+ if (roles.length > 0) {
483
+ roles.forEach((role) => {
484
+ filter.push({ ptype: "p", v0: role, v1: resourceType, v2: action });
485
+ });
486
+ } else {
487
+ filter.push({ ptype: "p", v1: resourceType, v2: action });
488
+ }
489
+ const adapt = this.enforcer.getAdapter();
490
+ const roleManager = this.enforcer.getRoleManager();
491
+ const tempEnforcer = new casbin.Enforcer();
492
+ await tempEnforcer.initWithModelAndAdapter(
493
+ casbin.newModelFromString(permissionModel.MODEL),
494
+ adapt,
495
+ true
496
+ );
497
+ tempEnforcer.setRoleManager(roleManager);
498
+ await tempEnforcer.loadFilteredPolicy(filter);
499
+ return await tempEnforcer.enforce(entityRef, resourceType, action);
500
+ })();
501
+ return await this.execOperation(evaluatePermissionOperation);
405
502
  }
406
503
  async getImplicitPermissionsForUser(user) {
407
- return this.enforcer.getImplicitPermissionsForUser(user);
504
+ if (this.loadPolicyPromise) {
505
+ await this.loadPolicyPromise;
506
+ }
507
+ const getPermissionsForUserOperation = (async () => {
508
+ return this.enforcer.getImplicitPermissionsForUser(user);
509
+ })();
510
+ return await this.execOperation(getPermissionsForUserOperation);
408
511
  }
409
512
  async getAllRoles() {
410
- return this.enforcer.getAllRoles();
513
+ if (this.loadPolicyPromise) {
514
+ await this.loadPolicyPromise;
515
+ }
516
+ const getRolesOperation = (async () => {
517
+ return this.enforcer.getAllRoles();
518
+ })();
519
+ return await this.execOperation(getRolesOperation);
411
520
  }
412
521
  }
413
522
 
@@ -1 +1 @@
1
- {"version":3,"file":"enforcer-delegate.cjs.js","sources":["../../src/service/enforcer-delegate.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 { Enforcer, FilteredAdapter, newModelFromString } from 'casbin';\nimport { Knex } from 'knex';\n\nimport EventEmitter from 'events';\n\nimport { ADMIN_ROLE_NAME } from '../admin-permissions/admin-creation';\nimport {\n RoleMetadataDao,\n RoleMetadataStorage,\n} from '../database/role-metadata';\nimport { mergeRoleMetadata, policiesToString, policyToString } from '../helper';\nimport { MODEL } from './permission-model';\n\nexport type RoleEvents = 'roleAdded';\nexport interface RoleEventEmitter<T extends RoleEvents> {\n on(event: T, listener: (roleEntityRef: string | string[]) => void): this;\n}\n\ntype EventMap = {\n [event in RoleEvents]: any[];\n};\n\nexport class EnforcerDelegate implements RoleEventEmitter<RoleEvents> {\n private readonly roleEventEmitter = new EventEmitter<EventMap>();\n\n constructor(\n private readonly enforcer: Enforcer,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly knex: Knex,\n ) {}\n\n on(event: RoleEvents, listener: (role: string) => void): this {\n this.roleEventEmitter.on(event, listener);\n return this;\n }\n\n async hasPolicy(...policy: string[]): Promise<boolean> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [\n {\n ptype: 'p',\n v0: policy[0],\n v1: policy[1],\n v2: policy[2],\n v3: policy[3],\n },\n ],\n );\n return tempModel.hasPolicy('p', 'p', policy);\n }\n\n async hasGroupingPolicy(...policy: string[]): Promise<boolean> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [\n {\n ptype: 'g',\n v0: policy[0],\n v1: policy[1],\n },\n ],\n );\n return tempModel.hasPolicy('g', 'g', policy);\n }\n\n async getPolicy(): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [{ ptype: 'p' }],\n );\n return await tempModel.getPolicy('p', 'p');\n }\n\n async getGroupingPolicy(): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [{ ptype: 'g' }],\n );\n return await tempModel.getPolicy('g', 'g');\n }\n\n async getRolesForUser(userEntityRef: string): Promise<string[]> {\n return await this.enforcer.getRolesForUser(userEntityRef);\n }\n\n async getFilteredPolicy(\n fieldIndex: number,\n ...filter: string[]\n ): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n\n const filterArgs: Record<string, string>[] = [];\n const filterObj: Record<string, string> = { ptype: 'p' };\n for (let i = 0; i < filter.length; i++) {\n filterObj[`v${i + fieldIndex}`] = filter[i];\n filterArgs.push(filterObj);\n }\n\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n filterArgs,\n );\n\n return await tempModel.getPolicy('p', 'p');\n }\n\n async getFilteredGroupingPolicy(\n fieldIndex: number,\n ...filter: string[]\n ): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n\n const filterArgs: Record<string, string>[] = [];\n const filterObj: Record<string, string> = { ptype: 'g' };\n for (let i = 0; i < filter.length; i++) {\n filterObj[`v${i + fieldIndex}`] = filter[i];\n filterArgs.push(filterObj);\n }\n\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n filterArgs,\n );\n\n return await tempModel.getPolicy('g', 'g');\n }\n\n async addPolicy(\n policy: string[],\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n if (await this.hasPolicy(...policy)) {\n return;\n }\n try {\n const ok = await this.enforcer.addPolicy(...policy);\n if (!ok) {\n throw new Error(`failed to create policy ${policyToString(policy)}`);\n }\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async addPolicies(\n policies: string[][],\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (policies.length === 0) {\n return;\n }\n\n const trx = externalTrx || (await this.knex.transaction());\n\n try {\n const ok = await this.enforcer.addPolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to store policies ${policiesToString(policies)}`,\n );\n }\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async addGroupingPolicy(\n policy: string[],\n roleMetadata: RoleMetadataDao,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n const entityRef = roleMetadata.roleEntityRef;\n\n if (await this.hasGroupingPolicy(...policy)) {\n return;\n }\n try {\n let currentMetadata;\n if (entityRef.startsWith(`role:`)) {\n currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n entityRef,\n trx,\n );\n }\n\n if (currentMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentMetadata, roleMetadata),\n entityRef,\n trx,\n );\n } else {\n const currentDate: Date = new Date();\n roleMetadata.createdAt = currentDate.toUTCString();\n roleMetadata.lastModified = currentDate.toUTCString();\n await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);\n }\n\n const ok = await this.enforcer.addGroupingPolicy(...policy);\n if (!ok) {\n throw new Error(`failed to create policy ${policyToString(policy)}`);\n }\n if (!externalTrx) {\n await trx.commit();\n }\n if (!currentMetadata) {\n this.roleEventEmitter.emit('roleAdded', roleMetadata.roleEntityRef);\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async addGroupingPolicies(\n policies: string[][],\n roleMetadata: RoleMetadataDao,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (policies.length === 0) {\n return;\n }\n\n const trx = externalTrx ?? (await this.knex.transaction());\n\n try {\n const currentRoleMetadata =\n await this.roleMetadataStorage.findRoleMetadata(\n roleMetadata.roleEntityRef,\n trx,\n );\n if (currentRoleMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentRoleMetadata, roleMetadata),\n roleMetadata.roleEntityRef,\n trx,\n );\n } else {\n const currentDate: Date = new Date();\n roleMetadata.createdAt = currentDate.toUTCString();\n roleMetadata.lastModified = currentDate.toUTCString();\n await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);\n }\n\n const ok = await this.enforcer.addGroupingPolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to store policies ${policiesToString(policies)}`,\n );\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n if (!currentRoleMetadata) {\n this.roleEventEmitter.emit('roleAdded', roleMetadata.roleEntityRef);\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async updateGroupingPolicies(\n oldRole: string[][],\n newRole: string[][],\n newRoleMetadata: RoleMetadataDao,\n ): Promise<void> {\n const oldRoleName = oldRole.at(0)?.at(1)!;\n\n const trx = await this.knex.transaction();\n try {\n const currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n oldRoleName,\n trx,\n );\n if (!currentMetadata) {\n throw new Error(`Role metadata ${oldRoleName} was not found`);\n }\n\n await this.removeGroupingPolicies(oldRole, currentMetadata, true, trx);\n await this.addGroupingPolicies(newRole, newRoleMetadata, trx);\n await trx.commit();\n } catch (err) {\n await trx.rollback(err);\n throw err;\n }\n }\n\n async updatePolicies(\n oldPolicies: string[][],\n newPolicies: string[][],\n ): Promise<void> {\n const trx = await this.knex.transaction();\n\n try {\n await this.removePolicies(oldPolicies, trx);\n await this.addPolicies(newPolicies, trx);\n await trx.commit();\n } catch (err) {\n await trx.rollback(err);\n throw err;\n }\n }\n\n async removePolicy(policy: string[], externalTrx?: Knex.Transaction) {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n try {\n const ok = await this.enforcer.removePolicy(...policy);\n if (!ok) {\n throw new Error(`fail to delete policy ${policy}`);\n }\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async removePolicies(\n policies: string[][],\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n try {\n const ok = await this.enforcer.removePolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to delete policies ${policiesToString(policies)}`,\n );\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async removeGroupingPolicy(\n policy: string[],\n roleMetadata: RoleMetadataDao,\n isUpdate?: boolean,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n const roleEntity = policy[1];\n\n try {\n const ok = await this.enforcer.removeGroupingPolicy(...policy);\n if (!ok) {\n throw new Error(`Failed to delete policy ${policyToString(policy)}`);\n }\n\n if (!isUpdate) {\n const currentRoleMetadata =\n await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);\n const remainingGroupPolicies = await this.getFilteredGroupingPolicy(\n 1,\n roleEntity,\n );\n if (\n currentRoleMetadata &&\n remainingGroupPolicies.length === 0 &&\n roleEntity !== ADMIN_ROLE_NAME\n ) {\n await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);\n } else if (currentRoleMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentRoleMetadata, roleMetadata),\n roleEntity,\n trx,\n );\n }\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async removeGroupingPolicies(\n policies: string[][],\n roleMetadata: RoleMetadataDao,\n isUpdate?: boolean,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n const roleEntity = roleMetadata.roleEntityRef;\n try {\n const ok = await this.enforcer.removeGroupingPolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to delete grouping policies: ${policiesToString(policies)}`,\n );\n }\n\n if (!isUpdate) {\n const currentRoleMetadata =\n await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);\n const remainingGroupPolicies = await this.getFilteredGroupingPolicy(\n 1,\n roleEntity,\n );\n if (\n currentRoleMetadata &&\n remainingGroupPolicies.length === 0 &&\n roleEntity !== ADMIN_ROLE_NAME\n ) {\n await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);\n } else if (currentRoleMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentRoleMetadata, roleMetadata),\n roleEntity,\n trx,\n );\n }\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n /**\n * enforce aims to enforce a particular permission policy based on the user that it receives.\n * Under the hood, enforce uses the `enforce` method from the enforcer`.\n *\n * Before enforcement, a filter is set up to reduce the number of permission policies that will\n * be loaded in.\n * This will reduce the amount of checks that need to be made to determine if a user is authorize\n * to perform an action\n *\n * A temporary enforcer will also be used while enforcing.\n * This is to ensure that the filter does not interact with the base enforcer.\n * The temporary enforcer has lazy loading of the permission policies enabled to reduce the amount\n * of time it takes to initialize the temporary enforcer.\n * The justification for lazy loading is because permission policies are already present in the\n * role manager / database and it will be filtered and loaded whenever `loadFilteredPolicy` is called.\n * @param entityRef The user to enforce\n * @param resourceType The resource type / name of the permission policy\n * @param action The action of the permission policy\n * @param roles Any roles that the user is directly or indirectly attached to.\n * Used for filtering permission policies.\n * @returns True if the user is allowed based on the particular permission\n */\n async enforce(\n entityRef: string,\n resourceType: string,\n action: string,\n roles: string[],\n ): Promise<boolean> {\n const filter = [];\n if (roles.length > 0) {\n roles.forEach(role => {\n filter.push({ ptype: 'p', v0: role, v1: resourceType, v2: action });\n });\n } else {\n filter.push({ ptype: 'p', v1: resourceType, v2: action });\n }\n\n const adapt = this.enforcer.getAdapter();\n const roleManager = this.enforcer.getRoleManager();\n const tempEnforcer = new Enforcer();\n await tempEnforcer.initWithModelAndAdapter(\n newModelFromString(MODEL),\n adapt,\n true,\n );\n tempEnforcer.setRoleManager(roleManager);\n\n await tempEnforcer.loadFilteredPolicy(filter);\n\n return await tempEnforcer.enforce(entityRef, resourceType, action);\n }\n\n async getImplicitPermissionsForUser(user: string): Promise<string[][]> {\n return this.enforcer.getImplicitPermissionsForUser(user);\n }\n\n async getAllRoles(): Promise<string[]> {\n return this.enforcer.getAllRoles();\n }\n}\n"],"names":["EventEmitter","newModelFromString","MODEL","policyToString","policiesToString","mergeRoleMetadata","ADMIN_ROLE_NAME","Enforcer"],"mappings":"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"}
1
+ {"version":3,"file":"enforcer-delegate.cjs.js","sources":["../../src/service/enforcer-delegate.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 { Enforcer, FilteredAdapter, newModelFromString } from 'casbin';\nimport { Knex } from 'knex';\n\nimport EventEmitter from 'events';\n\nimport { ADMIN_ROLE_NAME } from '../admin-permissions/admin-creation';\nimport {\n RoleMetadataDao,\n RoleMetadataStorage,\n} from '../database/role-metadata';\nimport { mergeRoleMetadata, policiesToString, policyToString } from '../helper';\nimport { MODEL } from './permission-model';\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport {\n FETCH_NEWER_PERMISSIONS_STAGE,\n PoliciesData,\n} from '../audit-log/audit-logger';\n\nexport type RoleEvents = 'roleAdded';\nexport interface RoleEventEmitter<T extends RoleEvents> {\n on(event: T, listener: (roleEntityRef: string | string[]) => void): this;\n}\n\ntype EventMap = {\n [event in RoleEvents]: any[];\n};\n\nexport class EnforcerDelegate implements RoleEventEmitter<RoleEvents> {\n private readonly roleEventEmitter = new EventEmitter<EventMap>();\n\n private loadPolicyPromise: Promise<void> | null = null;\n private semaphore: number = 0;\n private editOperationsQueue: Promise<any>[] = []; // Queue to track edit operations\n\n constructor(\n private readonly enforcer: Enforcer,\n private readonly auditLogger: AuditLogger,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly knex: Knex,\n ) {}\n\n async loadPolicy(): Promise<void> {\n if (this.loadPolicyPromise) {\n // If a load operation is already in progress, return the cached promise\n return this.loadPolicyPromise;\n }\n\n // Increment semaphore to block edits during load\n this.semaphore++;\n\n this.loadPolicyPromise = (async () => {\n try {\n await this.waitForEditOperationsToFinish();\n\n await this.enforcer.loadPolicy();\n } catch (err) {\n this.auditLogger.auditLog({\n message: 'Failed to load newer policies from database',\n eventName: PoliciesData.FAILED_TO_FETCH_NEWER_PERMISSIONS,\n stage: FETCH_NEWER_PERMISSIONS_STAGE,\n status: 'failed',\n errors: [err],\n });\n } finally {\n this.semaphore--;\n this.loadPolicyPromise = null;\n }\n })();\n\n return this.loadPolicyPromise;\n }\n\n private async waitForEditOperationsToFinish(): Promise<void> {\n await Promise.all(this.editOperationsQueue);\n }\n\n async execOperation<T>(operation: Promise<T>): Promise<T> {\n this.editOperationsQueue.push(operation);\n\n let result;\n try {\n result = await operation;\n } catch (err) {\n throw err;\n } finally {\n const index = this.editOperationsQueue.indexOf(operation);\n if (index !== -1) {\n this.editOperationsQueue.splice(index, 1);\n }\n }\n\n return result;\n }\n\n on(event: RoleEvents, listener: (role: string) => void): this {\n this.roleEventEmitter.on(event, listener);\n return this;\n }\n\n async hasPolicy(...policy: string[]): Promise<boolean> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [\n {\n ptype: 'p',\n v0: policy[0],\n v1: policy[1],\n v2: policy[2],\n v3: policy[3],\n },\n ],\n );\n return tempModel.hasPolicy('p', 'p', policy);\n }\n\n async hasGroupingPolicy(...policy: string[]): Promise<boolean> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [\n {\n ptype: 'g',\n v0: policy[0],\n v1: policy[1],\n },\n ],\n );\n return tempModel.hasPolicy('g', 'g', policy);\n }\n\n async getPolicy(): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [{ ptype: 'p' }],\n );\n return await tempModel.getPolicy('p', 'p');\n }\n\n async getGroupingPolicy(): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n [{ ptype: 'g' }],\n );\n return await tempModel.getPolicy('g', 'g');\n }\n\n async getRolesForUser(userEntityRef: string): Promise<string[]> {\n return await this.enforcer.getRolesForUser(userEntityRef);\n }\n\n async getFilteredPolicy(\n fieldIndex: number,\n ...filter: string[]\n ): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n\n const filterArgs: Record<string, string>[] = [];\n const filterObj: Record<string, string> = { ptype: 'p' };\n for (let i = 0; i < filter.length; i++) {\n filterObj[`v${i + fieldIndex}`] = filter[i];\n filterArgs.push(filterObj);\n }\n\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n filterArgs,\n );\n\n return await tempModel.getPolicy('p', 'p');\n }\n\n async getFilteredGroupingPolicy(\n fieldIndex: number,\n ...filter: string[]\n ): Promise<string[][]> {\n const tempModel = newModelFromString(MODEL);\n\n const filterArgs: Record<string, string>[] = [];\n const filterObj: Record<string, string> = { ptype: 'g' };\n for (let i = 0; i < filter.length; i++) {\n filterObj[`v${i + fieldIndex}`] = filter[i];\n filterArgs.push(filterObj);\n }\n\n await (this.enforcer.getAdapter() as FilteredAdapter).loadFilteredPolicy(\n tempModel,\n filterArgs,\n );\n\n return await tempModel.getPolicy('g', 'g');\n }\n\n async addPolicy(\n policy: string[],\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n if (await this.hasPolicy(...policy)) {\n return;\n }\n try {\n const ok = await this.enforcer.addPolicy(...policy);\n if (!ok) {\n throw new Error(`failed to create policy ${policyToString(policy)}`);\n }\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n }\n\n async addPolicies(\n policies: string[][],\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const addPoliciesOperation = (async () => {\n if (policies.length === 0) {\n return;\n }\n\n const trx = externalTrx || (await this.knex.transaction());\n\n try {\n const ok = await this.enforcer.addPolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to store policies ${policiesToString(policies)}`,\n );\n }\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(addPoliciesOperation);\n }\n\n async addGroupingPolicy(\n policy: string[],\n roleMetadata: RoleMetadataDao,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const addGroupingPolicyOperation = (async () => {\n const trx = externalTrx ?? (await this.knex.transaction());\n const entityRef = roleMetadata.roleEntityRef;\n\n if (await this.hasGroupingPolicy(...policy)) {\n return;\n }\n try {\n let currentMetadata;\n if (entityRef.startsWith(`role:`)) {\n currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n entityRef,\n trx,\n );\n }\n\n if (currentMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentMetadata, roleMetadata),\n entityRef,\n trx,\n );\n } else {\n const currentDate: Date = new Date();\n roleMetadata.createdAt = currentDate.toUTCString();\n roleMetadata.lastModified = currentDate.toUTCString();\n await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);\n }\n\n const ok = await this.enforcer.addGroupingPolicy(...policy);\n if (!ok) {\n throw new Error(`failed to create policy ${policyToString(policy)}`);\n }\n if (!externalTrx) {\n await trx.commit();\n }\n if (!currentMetadata) {\n this.roleEventEmitter.emit('roleAdded', roleMetadata.roleEntityRef);\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(addGroupingPolicyOperation);\n }\n\n async addGroupingPolicies(\n policies: string[][],\n roleMetadata: RoleMetadataDao,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const addGroupingPoliciesOperation = (async () => {\n if (policies.length === 0) {\n return;\n }\n\n const trx = externalTrx ?? (await this.knex.transaction());\n\n try {\n const currentRoleMetadata =\n await this.roleMetadataStorage.findRoleMetadata(\n roleMetadata.roleEntityRef,\n trx,\n );\n if (currentRoleMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentRoleMetadata, roleMetadata),\n roleMetadata.roleEntityRef,\n trx,\n );\n } else {\n const currentDate: Date = new Date();\n roleMetadata.createdAt = currentDate.toUTCString();\n roleMetadata.lastModified = currentDate.toUTCString();\n await this.roleMetadataStorage.createRoleMetadata(roleMetadata, trx);\n }\n\n const ok = await this.enforcer.addGroupingPolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to store policies ${policiesToString(policies)}`,\n );\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n if (!currentRoleMetadata) {\n this.roleEventEmitter.emit('roleAdded', roleMetadata.roleEntityRef);\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(addGroupingPoliciesOperation);\n }\n\n async updateGroupingPolicies(\n oldRole: string[][],\n newRole: string[][],\n newRoleMetadata: RoleMetadataDao,\n ): Promise<void> {\n const oldRoleName = oldRole.at(0)?.at(1)!;\n\n const trx = await this.knex.transaction();\n try {\n const currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n oldRoleName,\n trx,\n );\n if (!currentMetadata) {\n throw new Error(`Role metadata ${oldRoleName} was not found`);\n }\n\n await this.removeGroupingPolicies(oldRole, currentMetadata, true, trx);\n await this.addGroupingPolicies(newRole, newRoleMetadata, trx);\n await trx.commit();\n } catch (err) {\n await trx.rollback(err);\n throw err;\n }\n }\n\n async updatePolicies(\n oldPolicies: string[][],\n newPolicies: string[][],\n ): Promise<void> {\n const trx = await this.knex.transaction();\n\n try {\n await this.removePolicies(oldPolicies, trx);\n await this.addPolicies(newPolicies, trx);\n await trx.commit();\n } catch (err) {\n await trx.rollback(err);\n throw err;\n }\n }\n\n async removePolicy(policy: string[], externalTrx?: Knex.Transaction) {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const removePolicyOperation = (async () => {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n try {\n const ok = await this.enforcer.removePolicy(...policy);\n if (!ok) {\n throw new Error(`fail to delete policy ${policy}`);\n }\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(removePolicyOperation);\n }\n\n async removePolicies(\n policies: string[][],\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const removePoliciesOperation = (async () => {\n const trx = externalTrx ?? (await this.knex.transaction());\n\n try {\n const ok = await this.enforcer.removePolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to delete policies ${policiesToString(policies)}`,\n );\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(removePoliciesOperation);\n }\n\n async removeGroupingPolicy(\n policy: string[],\n roleMetadata: RoleMetadataDao,\n isUpdate?: boolean,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const removeGroupingPolicyOperation = (async () => {\n const trx = externalTrx ?? (await this.knex.transaction());\n const roleEntity = policy[1];\n\n try {\n const ok = await this.enforcer.removeGroupingPolicy(...policy);\n if (!ok) {\n throw new Error(`Failed to delete policy ${policyToString(policy)}`);\n }\n\n if (!isUpdate) {\n const currentRoleMetadata =\n await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);\n const remainingGroupPolicies = await this.getFilteredGroupingPolicy(\n 1,\n roleEntity,\n );\n if (\n currentRoleMetadata &&\n remainingGroupPolicies.length === 0 &&\n roleEntity !== ADMIN_ROLE_NAME\n ) {\n await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);\n } else if (currentRoleMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentRoleMetadata, roleMetadata),\n roleEntity,\n trx,\n );\n }\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(removeGroupingPolicyOperation);\n }\n\n async removeGroupingPolicies(\n policies: string[][],\n roleMetadata: RoleMetadataDao,\n isUpdate?: boolean,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const removeGroupingPolicyOperation = (async () => {\n const trx = externalTrx ?? (await this.knex.transaction());\n const roleEntity = roleMetadata.roleEntityRef;\n\n try {\n const ok = await this.enforcer.removeGroupingPolicies(policies);\n if (!ok) {\n throw new Error(\n `Failed to delete grouping policies: ${policiesToString(policies)}`,\n );\n }\n\n if (!isUpdate) {\n const currentRoleMetadata =\n await this.roleMetadataStorage.findRoleMetadata(roleEntity, trx);\n const remainingGroupPolicies = await this.getFilteredGroupingPolicy(\n 1,\n roleEntity,\n );\n\n if (\n currentRoleMetadata &&\n remainingGroupPolicies.length === 0 &&\n roleEntity !== ADMIN_ROLE_NAME\n ) {\n await this.roleMetadataStorage.removeRoleMetadata(roleEntity, trx);\n } else if (currentRoleMetadata) {\n await this.roleMetadataStorage.updateRoleMetadata(\n mergeRoleMetadata(currentRoleMetadata, roleMetadata),\n roleEntity,\n trx,\n );\n }\n }\n\n if (!externalTrx) {\n await trx.commit();\n }\n } catch (err) {\n if (!externalTrx) {\n await trx.rollback(err);\n }\n throw err;\n }\n })();\n await this.execOperation(removeGroupingPolicyOperation);\n }\n\n /**\n * enforce aims to enforce a particular permission policy based on the user that it receives.\n * Under the hood, enforce uses the `enforce` method from the enforcer`.\n *\n * Before enforcement, a filter is set up to reduce the number of permission policies that will\n * be loaded in.\n * This will reduce the amount of checks that need to be made to determine if a user is authorize\n * to perform an action\n *\n * A temporary enforcer will also be used while enforcing.\n * This is to ensure that the filter does not interact with the base enforcer.\n * The temporary enforcer has lazy loading of the permission policies enabled to reduce the amount\n * of time it takes to initialize the temporary enforcer.\n * The justification for lazy loading is because permission policies are already present in the\n * role manager / database and it will be filtered and loaded whenever `getFilteredPolicy` is called\n * and permissions / roles are applied to the temp enforcer\n * @param entityRef The user to enforce\n * @param resourceType The resource type / name of the permission policy\n * @param action The action of the permission policy\n * @param roles Any roles that the user is directly or indirectly attached to.\n * Used for filtering permission policies.\n * @returns True if the user is allowed based on the particular permission\n */\n async enforce(\n entityRef: string,\n resourceType: string,\n action: string,\n roles: string[],\n ): Promise<boolean> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const evaluatePermissionOperation = (async () => {\n const filter = [];\n if (roles.length > 0) {\n roles.forEach(role => {\n filter.push({ ptype: 'p', v0: role, v1: resourceType, v2: action });\n });\n } else {\n filter.push({ ptype: 'p', v1: resourceType, v2: action });\n }\n\n const adapt = this.enforcer.getAdapter();\n const roleManager = this.enforcer.getRoleManager();\n const tempEnforcer = new Enforcer();\n await tempEnforcer.initWithModelAndAdapter(\n newModelFromString(MODEL),\n adapt,\n true,\n );\n tempEnforcer.setRoleManager(roleManager);\n\n await tempEnforcer.loadFilteredPolicy(filter);\n\n return await tempEnforcer.enforce(entityRef, resourceType, action);\n })();\n\n return await this.execOperation(evaluatePermissionOperation);\n }\n\n async getImplicitPermissionsForUser(user: string): Promise<string[][]> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const getPermissionsForUserOperation = (async () => {\n return this.enforcer.getImplicitPermissionsForUser(user);\n })();\n\n return await this.execOperation(getPermissionsForUserOperation);\n }\n\n async getAllRoles(): Promise<string[]> {\n if (this.loadPolicyPromise) {\n await this.loadPolicyPromise;\n }\n\n const getRolesOperation = (async () => {\n return this.enforcer.getAllRoles();\n })();\n\n return await this.execOperation(getRolesOperation);\n }\n}\n"],"names":["EventEmitter","PoliciesData","FETCH_NEWER_PERMISSIONS_STAGE","newModelFromString","MODEL","policyToString","policiesToString","mergeRoleMetadata","ADMIN_ROLE_NAME","Enforcer"],"mappings":"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"}
@@ -48,16 +48,17 @@ class PolicyBuilder {
48
48
  await migration.migrate(databaseManager);
49
49
  const conditionStorage = new conditionalStorage.DataBaseConditionalStorage(databaseClient);
50
50
  const roleMetadataStorage = new roleMetadata.DataBaseRoleMetadataStorage(databaseClient);
51
- const enforcerDelegate$1 = new enforcerDelegate.EnforcerDelegate(
52
- enf,
53
- roleMetadataStorage,
54
- databaseClient
55
- );
56
51
  const defAuditLog = new backstagePluginAuditLogNode.DefaultAuditLogger({
57
52
  logger: env.logger,
58
53
  authService: env.auth,
59
54
  httpAuthService: env.httpAuth
60
55
  });
56
+ const enforcerDelegate$1 = new enforcerDelegate.EnforcerDelegate(
57
+ enf,
58
+ defAuditLog,
59
+ roleMetadataStorage,
60
+ databaseClient
61
+ );
61
62
  if (rbacProviders) {
62
63
  await connectProviders.connectRBACProviders(
63
64
  rbacProviders,
@@ -1 +1 @@
1
- {"version":3,"file":"policy-builder.cjs.js","sources":["../../src/service/policy-builder.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 { DatabaseManager } from '@backstage/backend-defaults/database';\nimport type {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LifecycleService,\n LoggerService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport type { Config } from '@backstage/config';\nimport type { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport { PermissionPolicy } from '@backstage/plugin-permission-node';\n\nimport { DefaultAuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport { newEnforcer, newModelFromString } from 'casbin';\nimport type { Router } from 'express';\n\nimport type {\n PluginIdProvider,\n RBACProvider,\n} from '@backstage-community/plugin-rbac-node';\n\nimport { CasbinDBAdapterFactory } from '../database/casbin-adapter-factory';\nimport { DataBaseConditionalStorage } from '../database/conditional-storage';\nimport { migrate } from '../database/migration';\nimport { DataBaseRoleMetadataStorage } from '../database/role-metadata';\nimport { AllowAllPolicy } from '../policies/allow-all-policy';\nimport { RBACPermissionPolicy } from '../policies/permission-policy';\nimport { connectRBACProviders } from '../providers/connect-providers';\nimport { BackstageRoleManager } from '../role-manager/role-manager';\nimport { EnforcerDelegate } from './enforcer-delegate';\nimport { MODEL } from './permission-model';\nimport { PluginPermissionMetadataCollector } from './plugin-endpoints';\nimport { PoliciesServer } from './policies-rest-api';\n\n/**\n * @public\n */\nexport type EnvOptions = {\n config: Config;\n logger: LoggerService;\n discovery: DiscoveryService;\n permissions: PermissionEvaluator;\n auth: AuthService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n lifecycle: LifecycleService;\n};\n\n/**\n * @public\n */\nexport type RBACRouterOptions = {\n config: Config;\n logger: LoggerService;\n discovery: DiscoveryService;\n policy: PermissionPolicy;\n auth: AuthService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n};\n\n/**\n * @public\n */\nexport class PolicyBuilder {\n public static async build(\n env: EnvOptions,\n pluginIdProvider: PluginIdProvider = { getPluginIds: () => [] },\n rbacProviders?: Array<RBACProvider>,\n ): Promise<Router> {\n let policy: PermissionPolicy;\n\n const databaseManager = DatabaseManager.fromConfig(env.config).forPlugin(\n 'permission',\n { logger: env.logger, lifecycle: env.lifecycle },\n );\n\n const databaseClient = await databaseManager.getClient();\n\n const adapter = await new CasbinDBAdapterFactory(\n env.config,\n databaseClient,\n ).createAdapter();\n\n const enf = await newEnforcer(newModelFromString(MODEL), adapter);\n await enf.loadPolicy();\n enf.enableAutoSave(true);\n\n const catalogClient = new CatalogClient({ discoveryApi: env.discovery });\n const catalogDBClient = await DatabaseManager.fromConfig(env.config)\n .forPlugin('catalog', { logger: env.logger, lifecycle: env.lifecycle })\n .getClient();\n\n const rm = new BackstageRoleManager(\n catalogClient,\n env.logger,\n catalogDBClient,\n databaseClient,\n env.config,\n env.auth,\n );\n enf.setRoleManager(rm);\n enf.enableAutoBuildRoleLinks(false);\n await enf.buildRoleLinks();\n\n await migrate(databaseManager);\n\n const conditionStorage = new DataBaseConditionalStorage(databaseClient);\n\n const roleMetadataStorage = new DataBaseRoleMetadataStorage(databaseClient);\n const enforcerDelegate = new EnforcerDelegate(\n enf,\n roleMetadataStorage,\n databaseClient,\n );\n\n const defAuditLog = new DefaultAuditLogger({\n logger: env.logger,\n authService: env.auth,\n httpAuthService: env.httpAuth,\n });\n\n if (rbacProviders) {\n await connectRBACProviders(\n rbacProviders,\n enforcerDelegate,\n roleMetadataStorage,\n env.logger,\n defAuditLog,\n );\n }\n\n const pluginIdsConfig = env.config.getOptionalStringArray(\n 'permission.rbac.pluginsWithPermission',\n );\n if (pluginIdsConfig) {\n const pluginIds = new Set([\n ...pluginIdsConfig,\n ...pluginIdProvider.getPluginIds(),\n ]);\n pluginIdProvider.getPluginIds = () => {\n return [...pluginIds];\n };\n }\n\n const pluginPermMetaData = new PluginPermissionMetadataCollector({\n deps: {\n discovery: env.discovery,\n pluginIdProvider: pluginIdProvider,\n logger: env.logger,\n config: env.config,\n },\n });\n\n const isPluginEnabled = env.config.getOptionalBoolean('permission.enabled');\n if (isPluginEnabled) {\n env.logger.info('RBAC backend plugin was enabled');\n\n policy = await RBACPermissionPolicy.build(\n env.logger,\n defAuditLog,\n env.config,\n conditionStorage,\n enforcerDelegate,\n roleMetadataStorage,\n databaseClient,\n pluginPermMetaData,\n env.auth,\n );\n } else {\n env.logger.warn(\n 'RBAC backend plugin was disabled by application config permission.enabled: false',\n );\n\n policy = new AllowAllPolicy();\n }\n\n const options: RBACRouterOptions = {\n config: env.config,\n logger: env.logger,\n discovery: env.discovery,\n policy,\n auth: env.auth,\n httpAuth: env.httpAuth,\n userInfo: env.userInfo,\n };\n\n const server = new PoliciesServer(\n env.permissions,\n options,\n enforcerDelegate,\n conditionStorage,\n pluginPermMetaData,\n roleMetadataStorage,\n defAuditLog,\n rbacProviders,\n );\n return server.serve();\n }\n}\n"],"names":["DatabaseManager","CasbinDBAdapterFactory","newEnforcer","newModelFromString","MODEL","catalogClient","CatalogClient","BackstageRoleManager","migrate","DataBaseConditionalStorage","DataBaseRoleMetadataStorage","enforcerDelegate","EnforcerDelegate","DefaultAuditLogger","connectRBACProviders","PluginPermissionMetadataCollector","RBACPermissionPolicy","AllowAllPolicy","PoliciesServer"],"mappings":"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"}
1
+ {"version":3,"file":"policy-builder.cjs.js","sources":["../../src/service/policy-builder.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 { DatabaseManager } from '@backstage/backend-defaults/database';\nimport type {\n AuthService,\n DiscoveryService,\n HttpAuthService,\n LifecycleService,\n LoggerService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport type { Config } from '@backstage/config';\nimport type { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport { PermissionPolicy } from '@backstage/plugin-permission-node';\n\nimport { DefaultAuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport { newEnforcer, newModelFromString } from 'casbin';\nimport type { Router } from 'express';\n\nimport type {\n PluginIdProvider,\n RBACProvider,\n} from '@backstage-community/plugin-rbac-node';\n\nimport { CasbinDBAdapterFactory } from '../database/casbin-adapter-factory';\nimport { DataBaseConditionalStorage } from '../database/conditional-storage';\nimport { migrate } from '../database/migration';\nimport { DataBaseRoleMetadataStorage } from '../database/role-metadata';\nimport { AllowAllPolicy } from '../policies/allow-all-policy';\nimport { RBACPermissionPolicy } from '../policies/permission-policy';\nimport { connectRBACProviders } from '../providers/connect-providers';\nimport { BackstageRoleManager } from '../role-manager/role-manager';\nimport { EnforcerDelegate } from './enforcer-delegate';\nimport { MODEL } from './permission-model';\nimport { PluginPermissionMetadataCollector } from './plugin-endpoints';\nimport { PoliciesServer } from './policies-rest-api';\n\n/**\n * @public\n */\nexport type EnvOptions = {\n config: Config;\n logger: LoggerService;\n discovery: DiscoveryService;\n permissions: PermissionEvaluator;\n auth: AuthService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n lifecycle: LifecycleService;\n};\n\n/**\n * @public\n */\nexport type RBACRouterOptions = {\n config: Config;\n logger: LoggerService;\n discovery: DiscoveryService;\n policy: PermissionPolicy;\n auth: AuthService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n};\n\n/**\n * @public\n */\nexport class PolicyBuilder {\n public static async build(\n env: EnvOptions,\n pluginIdProvider: PluginIdProvider = { getPluginIds: () => [] },\n rbacProviders?: Array<RBACProvider>,\n ): Promise<Router> {\n let policy: PermissionPolicy;\n\n const databaseManager = DatabaseManager.fromConfig(env.config).forPlugin(\n 'permission',\n { logger: env.logger, lifecycle: env.lifecycle },\n );\n\n const databaseClient = await databaseManager.getClient();\n\n const adapter = await new CasbinDBAdapterFactory(\n env.config,\n databaseClient,\n ).createAdapter();\n\n const enf = await newEnforcer(newModelFromString(MODEL), adapter);\n await enf.loadPolicy();\n enf.enableAutoSave(true);\n\n const catalogClient = new CatalogClient({ discoveryApi: env.discovery });\n const catalogDBClient = await DatabaseManager.fromConfig(env.config)\n .forPlugin('catalog', { logger: env.logger, lifecycle: env.lifecycle })\n .getClient();\n\n const rm = new BackstageRoleManager(\n catalogClient,\n env.logger,\n catalogDBClient,\n databaseClient,\n env.config,\n env.auth,\n );\n enf.setRoleManager(rm);\n enf.enableAutoBuildRoleLinks(false);\n await enf.buildRoleLinks();\n\n await migrate(databaseManager);\n\n const conditionStorage = new DataBaseConditionalStorage(databaseClient);\n\n const roleMetadataStorage = new DataBaseRoleMetadataStorage(databaseClient);\n const defAuditLog = new DefaultAuditLogger({\n logger: env.logger,\n authService: env.auth,\n httpAuthService: env.httpAuth,\n });\n const enforcerDelegate = new EnforcerDelegate(\n enf,\n defAuditLog,\n roleMetadataStorage,\n databaseClient,\n );\n\n if (rbacProviders) {\n await connectRBACProviders(\n rbacProviders,\n enforcerDelegate,\n roleMetadataStorage,\n env.logger,\n defAuditLog,\n );\n }\n\n const pluginIdsConfig = env.config.getOptionalStringArray(\n 'permission.rbac.pluginsWithPermission',\n );\n if (pluginIdsConfig) {\n const pluginIds = new Set([\n ...pluginIdsConfig,\n ...pluginIdProvider.getPluginIds(),\n ]);\n pluginIdProvider.getPluginIds = () => {\n return [...pluginIds];\n };\n }\n\n const pluginPermMetaData = new PluginPermissionMetadataCollector({\n deps: {\n discovery: env.discovery,\n pluginIdProvider: pluginIdProvider,\n logger: env.logger,\n config: env.config,\n },\n });\n\n const isPluginEnabled = env.config.getOptionalBoolean('permission.enabled');\n if (isPluginEnabled) {\n env.logger.info('RBAC backend plugin was enabled');\n\n policy = await RBACPermissionPolicy.build(\n env.logger,\n defAuditLog,\n env.config,\n conditionStorage,\n enforcerDelegate,\n roleMetadataStorage,\n databaseClient,\n pluginPermMetaData,\n env.auth,\n );\n } else {\n env.logger.warn(\n 'RBAC backend plugin was disabled by application config permission.enabled: false',\n );\n\n policy = new AllowAllPolicy();\n }\n\n const options: RBACRouterOptions = {\n config: env.config,\n logger: env.logger,\n discovery: env.discovery,\n policy,\n auth: env.auth,\n httpAuth: env.httpAuth,\n userInfo: env.userInfo,\n };\n\n const server = new PoliciesServer(\n env.permissions,\n options,\n enforcerDelegate,\n conditionStorage,\n pluginPermMetaData,\n roleMetadataStorage,\n defAuditLog,\n rbacProviders,\n );\n return server.serve();\n }\n}\n"],"names":["DatabaseManager","CasbinDBAdapterFactory","newEnforcer","newModelFromString","MODEL","catalogClient","CatalogClient","BackstageRoleManager","migrate","DataBaseConditionalStorage","DataBaseRoleMetadataStorage","DefaultAuditLogger","enforcerDelegate","EnforcerDelegate","connectRBACProviders","PluginPermissionMetadataCollector","RBACPermissionPolicy","AllowAllPolicy","PoliciesServer"],"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": "5.2.9",
3
+ "version": "5.2.10",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -64,6 +64,7 @@
64
64
  "@backstage/types": "1.1.1",
65
65
  "@spotify/prettier-config": "^15.0.0",
66
66
  "@types/express": "4.17.21",
67
+ "@types/knex": "^0.16.1",
67
68
  "@types/lodash": "^4.14.151",
68
69
  "@types/node": "18.19.68",
69
70
  "@types/supertest": "2.0.16",