@backstage-community/plugin-rbac-backend 5.2.4 → 5.2.5
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 +6 -0
- package/dist/admin-permissions/admin-creation.cjs.js.map +1 -1
- package/dist/audit-log/audit-logger.cjs.js.map +1 -1
- package/dist/audit-log/rest-errors-interceptor.cjs.js.map +1 -1
- package/dist/conditional-aliases/alias-resolver.cjs.js.map +1 -1
- package/dist/database/casbin-adapter-factory.cjs.js.map +1 -1
- package/dist/database/conditional-storage.cjs.js.map +1 -1
- package/dist/database/migration.cjs.js.map +1 -1
- package/dist/database/role-metadata.cjs.js.map +1 -1
- package/dist/file-permissions/csv-file-watcher.cjs.js.map +1 -1
- package/dist/file-permissions/file-watcher.cjs.js.map +1 -1
- package/dist/file-permissions/yaml-conditional-file-watcher.cjs.js.map +1 -1
- package/dist/helper.cjs.js.map +1 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/policies/allow-all-policy.cjs.js.map +1 -1
- package/dist/policies/permission-policy.cjs.js.map +1 -1
- package/dist/providers/connect-providers.cjs.js.map +1 -1
- package/dist/role-manager/ancestor-search-memo.cjs.js.map +1 -1
- package/dist/role-manager/member-list.cjs.js.map +1 -1
- package/dist/role-manager/role-manager.cjs.js.map +1 -1
- package/dist/service/enforcer-delegate.cjs.js.map +1 -1
- package/dist/service/permission-model.cjs.js.map +1 -1
- package/dist/service/plugin-endpoints.cjs.js.map +1 -1
- package/dist/service/policies-rest-api.cjs.js.map +1 -1
- package/dist/service/policy-builder.cjs.js.map +1 -1
- package/dist/service/router.cjs.js.map +1 -1
- package/dist/validation/condition-validation.cjs.js.map +1 -1
- package/dist/validation/policies-validation.cjs.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-creation.cjs.js","sources":["../../src/admin-permissions/admin-creation.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';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport { Knex } from 'knex';\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 {\n RoleMetadataDao,\n RoleMetadataStorage,\n} from '../database/role-metadata';\nimport { removeTheDifference } from '../helper';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { validateEntityReference } from '../validation/policies-validation';\n\nexport const ADMIN_ROLE_NAME = 'role:default/rbac_admin';\nexport const ADMIN_ROLE_AUTHOR = 'application configuration';\nconst DEF_ADMIN_ROLE_DESCRIPTION =\n 'The default permission policy for the admin role allows for the creation, deletion, updating, and reading of roles and permission policies.';\n\nconst getAdminRoleMetadata = (): RoleMetadataDao => {\n const currentDate: Date = new Date();\n return {\n source: 'configuration',\n roleEntityRef: ADMIN_ROLE_NAME,\n description: DEF_ADMIN_ROLE_DESCRIPTION,\n author: ADMIN_ROLE_AUTHOR,\n modifiedBy: ADMIN_ROLE_AUTHOR,\n lastModified: currentDate.toUTCString(),\n createdAt: currentDate.toUTCString(),\n };\n};\n\nexport const useAdminsFromConfig = async (\n admins: Config[],\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n roleMetadataStorage: RoleMetadataStorage,\n knex: Knex,\n) => {\n const addedGroupPolicies = new Map<string, string>();\n const newGroupPolicies = new Map<string, string>();\n\n for (const admin of admins) {\n const entityRef = admin.getString('name');\n validateEntityReference(entityRef);\n\n addedGroupPolicies.set(entityRef, ADMIN_ROLE_NAME);\n\n if (!(await enf.hasGroupingPolicy(...[entityRef, ADMIN_ROLE_NAME]))) {\n newGroupPolicies.set(entityRef, ADMIN_ROLE_NAME);\n }\n }\n\n const adminRoleMeta = await roleMetadataStorage.findRoleMetadata(\n ADMIN_ROLE_NAME,\n );\n\n const trx = await knex.transaction();\n let addedRoleMembers;\n try {\n if (!adminRoleMeta) {\n // even if there are no user, we still create default role metadata for admins\n await roleMetadataStorage.createRoleMetadata(getAdminRoleMetadata(), trx);\n } else if (adminRoleMeta.source === 'legacy') {\n await roleMetadataStorage.updateRoleMetadata(\n getAdminRoleMetadata(),\n ADMIN_ROLE_NAME,\n trx,\n );\n }\n\n addedRoleMembers = Array.from<string[]>(newGroupPolicies.entries());\n await enf.addGroupingPolicies(\n addedRoleMembers,\n getAdminRoleMetadata(),\n trx,\n );\n\n await trx.commit();\n } catch (error) {\n await trx.rollback(error);\n throw error;\n }\n\n await auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created or updated role`,\n eventName: RoleEvents.CREATE_OR_UPDATE_ROLE,\n metadata: {\n ...getAdminRoleMetadata(),\n members: addedRoleMembers.map(gp => gp[0]),\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n\n const configGroupPolicies = await enf.getFilteredGroupingPolicy(\n 1,\n ADMIN_ROLE_NAME,\n );\n\n await removeTheDifference(\n configGroupPolicies.map(gp => gp[0]),\n Array.from<string>(addedGroupPolicies.keys()),\n 'configuration',\n ADMIN_ROLE_NAME,\n enf,\n auditLogger,\n ADMIN_ROLE_AUTHOR,\n );\n};\n\nconst addAdminPermissions = async (\n policies: string[][],\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n) => {\n const policiesToAdd: string[][] = [];\n for (const policy of policies) {\n if (!(await enf.hasPolicy(...policy))) {\n policiesToAdd.push(policy);\n }\n }\n await enf.addPolicies(policiesToAdd);\n\n await auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created RBAC admin permissions`,\n eventName: PermissionEvents.CREATE_POLICY,\n metadata: { policies: policies, source: 'configuration' },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n};\n\nexport const setAdminPermissions = async (\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n) => {\n const adminPermissions = [\n [ADMIN_ROLE_NAME, 'policy-entity', 'read', 'allow'],\n [ADMIN_ROLE_NAME, 'policy-entity', 'create', 'allow'],\n [ADMIN_ROLE_NAME, 'policy-entity', 'delete', 'allow'],\n [ADMIN_ROLE_NAME, 'policy-entity', 'update', 'allow'],\n // Needed for the RBAC frontend plugin.\n [ADMIN_ROLE_NAME, 'catalog-entity', 'read', 'allow'],\n ];\n await addAdminPermissions(adminPermissions, enf, auditLogger);\n};\n"],"names":["auditLogger","validateEntityReference","RBAC_BACKEND","RoleEvents","HANDLE_RBAC_DATA_STAGE","removeTheDifference","PermissionEvents"],"mappings":";;;;;;AAoCO,MAAM,eAAkB,GAAA
|
|
1
|
+
{"version":3,"file":"admin-creation.cjs.js","sources":["../../src/admin-permissions/admin-creation.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';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport { Knex } from 'knex';\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 {\n RoleMetadataDao,\n RoleMetadataStorage,\n} from '../database/role-metadata';\nimport { removeTheDifference } from '../helper';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { validateEntityReference } from '../validation/policies-validation';\n\nexport const ADMIN_ROLE_NAME = 'role:default/rbac_admin';\nexport const ADMIN_ROLE_AUTHOR = 'application configuration';\nconst DEF_ADMIN_ROLE_DESCRIPTION =\n 'The default permission policy for the admin role allows for the creation, deletion, updating, and reading of roles and permission policies.';\n\nconst getAdminRoleMetadata = (): RoleMetadataDao => {\n const currentDate: Date = new Date();\n return {\n source: 'configuration',\n roleEntityRef: ADMIN_ROLE_NAME,\n description: DEF_ADMIN_ROLE_DESCRIPTION,\n author: ADMIN_ROLE_AUTHOR,\n modifiedBy: ADMIN_ROLE_AUTHOR,\n lastModified: currentDate.toUTCString(),\n createdAt: currentDate.toUTCString(),\n };\n};\n\nexport const useAdminsFromConfig = async (\n admins: Config[],\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n roleMetadataStorage: RoleMetadataStorage,\n knex: Knex,\n) => {\n const addedGroupPolicies = new Map<string, string>();\n const newGroupPolicies = new Map<string, string>();\n\n for (const admin of admins) {\n const entityRef = admin.getString('name');\n validateEntityReference(entityRef);\n\n addedGroupPolicies.set(entityRef, ADMIN_ROLE_NAME);\n\n if (!(await enf.hasGroupingPolicy(...[entityRef, ADMIN_ROLE_NAME]))) {\n newGroupPolicies.set(entityRef, ADMIN_ROLE_NAME);\n }\n }\n\n const adminRoleMeta = await roleMetadataStorage.findRoleMetadata(\n ADMIN_ROLE_NAME,\n );\n\n const trx = await knex.transaction();\n let addedRoleMembers;\n try {\n if (!adminRoleMeta) {\n // even if there are no user, we still create default role metadata for admins\n await roleMetadataStorage.createRoleMetadata(getAdminRoleMetadata(), trx);\n } else if (adminRoleMeta.source === 'legacy') {\n await roleMetadataStorage.updateRoleMetadata(\n getAdminRoleMetadata(),\n ADMIN_ROLE_NAME,\n trx,\n );\n }\n\n addedRoleMembers = Array.from<string[]>(newGroupPolicies.entries());\n await enf.addGroupingPolicies(\n addedRoleMembers,\n getAdminRoleMetadata(),\n trx,\n );\n\n await trx.commit();\n } catch (error) {\n await trx.rollback(error);\n throw error;\n }\n\n await auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created or updated role`,\n eventName: RoleEvents.CREATE_OR_UPDATE_ROLE,\n metadata: {\n ...getAdminRoleMetadata(),\n members: addedRoleMembers.map(gp => gp[0]),\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n\n const configGroupPolicies = await enf.getFilteredGroupingPolicy(\n 1,\n ADMIN_ROLE_NAME,\n );\n\n await removeTheDifference(\n configGroupPolicies.map(gp => gp[0]),\n Array.from<string>(addedGroupPolicies.keys()),\n 'configuration',\n ADMIN_ROLE_NAME,\n enf,\n auditLogger,\n ADMIN_ROLE_AUTHOR,\n );\n};\n\nconst addAdminPermissions = async (\n policies: string[][],\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n) => {\n const policiesToAdd: string[][] = [];\n for (const policy of policies) {\n if (!(await enf.hasPolicy(...policy))) {\n policiesToAdd.push(policy);\n }\n }\n await enf.addPolicies(policiesToAdd);\n\n await auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created RBAC admin permissions`,\n eventName: PermissionEvents.CREATE_POLICY,\n metadata: { policies: policies, source: 'configuration' },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n};\n\nexport const setAdminPermissions = async (\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n) => {\n const adminPermissions = [\n [ADMIN_ROLE_NAME, 'policy-entity', 'read', 'allow'],\n [ADMIN_ROLE_NAME, 'policy-entity', 'create', 'allow'],\n [ADMIN_ROLE_NAME, 'policy-entity', 'delete', 'allow'],\n [ADMIN_ROLE_NAME, 'policy-entity', 'update', 'allow'],\n // Needed for the RBAC frontend plugin.\n [ADMIN_ROLE_NAME, 'catalog-entity', 'read', 'allow'],\n ];\n await addAdminPermissions(adminPermissions, enf, auditLogger);\n};\n"],"names":["auditLogger","validateEntityReference","RBAC_BACKEND","RoleEvents","HANDLE_RBAC_DATA_STAGE","removeTheDifference","PermissionEvents"],"mappings":"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"}
|
|
@@ -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":";;;;;AA+BO,MAAM,UAAa,GAAA;AAAA,EACxB,WAAa,EAAA,YAAA;AAAA,EACb,WAAa,EAAA,YAAA;AAAA,EACb,WAAa,EAAA,YAAA;AAAA,EACb,qBAAuB,EAAA,oBAAA;AAAA,EACvB,QAAU,EAAA,SAAA;AAAA,EAEV,iBAAmB,EAAA,iBAAA;AAAA,EACnB,iBAAmB,EAAA,iBAAA;AAAA,EACnB,iBAAmB,EAAA,iBAAA;AAAA,EACnB,cAAgB,EAAA
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest-errors-interceptor.cjs.js","sources":["../../src/audit-log/rest-errors-interceptor.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 { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport type {\n ErrorRequestHandler,\n NextFunction,\n Request,\n Response,\n} from 'express';\n\nimport {\n ConditionEvents,\n ListConditionEvents,\n ListPluginPoliciesEvents,\n PermissionEvents,\n RESPONSE_ERROR,\n RoleEvents,\n} from './audit-logger';\n\n// Mapping paths and methods to corresponding events and messages\nconst eventMap: {\n [key: string]: { [key: string]: { event: string; message: string } };\n} = {\n '/policies': {\n POST: {\n event: PermissionEvents.CREATE_POLICY_ERROR,\n message: 'Failed to create permission policies',\n },\n PUT: {\n event: PermissionEvents.UPDATE_POLICY_ERROR,\n message: 'Failed to update permission policies',\n },\n DELETE: {\n event: PermissionEvents.DELETE_POLICY_ERROR,\n message: 'Failed to delete permission policies',\n },\n GET: {\n event: PermissionEvents.GET_POLICY_ERROR,\n message: 'Failed to get permission policies',\n },\n },\n '/roles': {\n POST: {\n event: RoleEvents.CREATE_ROLE_ERROR,\n message: 'Failed to create role',\n },\n PUT: {\n event: RoleEvents.UPDATE_ROLE_ERROR,\n message: 'Failed to update role',\n },\n DELETE: {\n event: RoleEvents.DELETE_ROLE_ERROR,\n message: 'Failed to delete role',\n },\n GET: { event: RoleEvents.GET_ROLE_ERROR, message: 'Failed to get role' },\n },\n '/roles/conditions': {\n POST: {\n event: ConditionEvents.CREATE_CONDITION_ERROR,\n message: 'Failed to create condition',\n },\n PUT: {\n event: ConditionEvents.UPDATE_CONDITION_ERROR,\n message: 'Failed to update condition',\n },\n DELETE: {\n event: ConditionEvents.DELETE_CONDITION_ERROR,\n message: 'Failed to delete condition',\n },\n GET: {\n event: ConditionEvents.GET_CONDITION_ERROR,\n message: 'Failed to get condition',\n },\n },\n '/plugins/policies': {\n GET: {\n event: ListPluginPoliciesEvents.GET_PLUGINS_POLICIES_ERROR,\n message: 'Failed to get list permission policies',\n },\n },\n '/plugins/condition-rules': {\n GET: {\n event: ListConditionEvents.GET_CONDITION_RULES_ERROR,\n message: 'Failed to get list condition rules and schemas',\n },\n },\n};\n\n// Audit log REST api errors interceptor.\nexport function auditError(auditLogger: AuditLogger): ErrorRequestHandler {\n return async (\n err: Error,\n req: Request,\n _resp: Response,\n next: NextFunction,\n ) => {\n const matchedPath = Object.keys(eventMap).find(path =>\n req.path.startsWith(path),\n );\n if (matchedPath) {\n const methodEvents = eventMap[matchedPath][req.method];\n if (methodEvents) {\n const { event, message } = methodEvents;\n try {\n await auditLogger.auditLog({\n message,\n eventName: event,\n stage: RESPONSE_ERROR,\n status: 'failed',\n request: req,\n errors: [err],\n });\n next(err);\n } catch (auditLogError) {\n next(auditLogError);\n }\n return;\n }\n }\n next(err);\n };\n}\n"],"names":["PermissionEvents","RoleEvents","ConditionEvents","ListPluginPoliciesEvents","ListConditionEvents","auditLogger","RESPONSE_ERROR"],"mappings":";;;;AAiCA,MAAM,QAEF,GAAA;AAAA,EACF,WAAa,EAAA;AAAA,IACX,IAAM,EAAA;AAAA,MACJ,OAAOA,4BAAiB,CAAA,mBAAA;AAAA,MACxB,OAAS,EAAA
|
|
1
|
+
{"version":3,"file":"rest-errors-interceptor.cjs.js","sources":["../../src/audit-log/rest-errors-interceptor.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 { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport type {\n ErrorRequestHandler,\n NextFunction,\n Request,\n Response,\n} from 'express';\n\nimport {\n ConditionEvents,\n ListConditionEvents,\n ListPluginPoliciesEvents,\n PermissionEvents,\n RESPONSE_ERROR,\n RoleEvents,\n} from './audit-logger';\n\n// Mapping paths and methods to corresponding events and messages\nconst eventMap: {\n [key: string]: { [key: string]: { event: string; message: string } };\n} = {\n '/policies': {\n POST: {\n event: PermissionEvents.CREATE_POLICY_ERROR,\n message: 'Failed to create permission policies',\n },\n PUT: {\n event: PermissionEvents.UPDATE_POLICY_ERROR,\n message: 'Failed to update permission policies',\n },\n DELETE: {\n event: PermissionEvents.DELETE_POLICY_ERROR,\n message: 'Failed to delete permission policies',\n },\n GET: {\n event: PermissionEvents.GET_POLICY_ERROR,\n message: 'Failed to get permission policies',\n },\n },\n '/roles': {\n POST: {\n event: RoleEvents.CREATE_ROLE_ERROR,\n message: 'Failed to create role',\n },\n PUT: {\n event: RoleEvents.UPDATE_ROLE_ERROR,\n message: 'Failed to update role',\n },\n DELETE: {\n event: RoleEvents.DELETE_ROLE_ERROR,\n message: 'Failed to delete role',\n },\n GET: { event: RoleEvents.GET_ROLE_ERROR, message: 'Failed to get role' },\n },\n '/roles/conditions': {\n POST: {\n event: ConditionEvents.CREATE_CONDITION_ERROR,\n message: 'Failed to create condition',\n },\n PUT: {\n event: ConditionEvents.UPDATE_CONDITION_ERROR,\n message: 'Failed to update condition',\n },\n DELETE: {\n event: ConditionEvents.DELETE_CONDITION_ERROR,\n message: 'Failed to delete condition',\n },\n GET: {\n event: ConditionEvents.GET_CONDITION_ERROR,\n message: 'Failed to get condition',\n },\n },\n '/plugins/policies': {\n GET: {\n event: ListPluginPoliciesEvents.GET_PLUGINS_POLICIES_ERROR,\n message: 'Failed to get list permission policies',\n },\n },\n '/plugins/condition-rules': {\n GET: {\n event: ListConditionEvents.GET_CONDITION_RULES_ERROR,\n message: 'Failed to get list condition rules and schemas',\n },\n },\n};\n\n// Audit log REST api errors interceptor.\nexport function auditError(auditLogger: AuditLogger): ErrorRequestHandler {\n return async (\n err: Error,\n req: Request,\n _resp: Response,\n next: NextFunction,\n ) => {\n const matchedPath = Object.keys(eventMap).find(path =>\n req.path.startsWith(path),\n );\n if (matchedPath) {\n const methodEvents = eventMap[matchedPath][req.method];\n if (methodEvents) {\n const { event, message } = methodEvents;\n try {\n await auditLogger.auditLog({\n message,\n eventName: event,\n stage: RESPONSE_ERROR,\n status: 'failed',\n request: req,\n errors: [err],\n });\n next(err);\n } catch (auditLogError) {\n next(auditLogError);\n }\n return;\n }\n }\n next(err);\n };\n}\n"],"names":["PermissionEvents","RoleEvents","ConditionEvents","ListPluginPoliciesEvents","ListConditionEvents","auditLogger","RESPONSE_ERROR"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alias-resolver.cjs.js","sources":["../../src/conditional-aliases/alias-resolver.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 { BackstageUserInfo } from '@backstage/backend-plugin-api';\nimport type {\n PermissionCondition,\n PermissionCriteria,\n PermissionRuleParam,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport type { JsonPrimitive } from '@backstage/types';\n\nimport {\n CONDITION_ALIAS_SIGN,\n ConditionalAliases,\n} from '@backstage-community/plugin-rbac-common';\n\ninterface Predicate<T> {\n (item: T): boolean;\n}\n\nfunction isOwnerRefsAlias(value: PermissionRuleParam): boolean {\n const alias = `${CONDITION_ALIAS_SIGN}${ConditionalAliases.OWNER_REFS}`;\n return value === alias;\n}\n\nfunction isCurrentUserAlias(value: PermissionRuleParam): boolean {\n const alias = `${CONDITION_ALIAS_SIGN}${ConditionalAliases.CURRENT_USER}`;\n return value === alias;\n}\n\nfunction replaceAliasWithValue<\n K extends string,\n V extends JsonPrimitive | JsonPrimitive[],\n>(\n params: Record<K, PermissionRuleParam> | undefined,\n key: K,\n predicate: Predicate<PermissionRuleParam>,\n newValue: V,\n): Record<K, PermissionRuleParam> | undefined {\n if (!params) {\n return params;\n }\n\n if (Array.isArray(params[key])) {\n const oldValues = params[key] as JsonPrimitive[];\n const nonAliasValues: JsonPrimitive[] = [];\n for (const oldValue of oldValues) {\n const isAliasMatched = predicate(oldValue);\n if (isAliasMatched) {\n const newValues = Array.isArray(newValue) ? newValue : [newValue];\n nonAliasValues.push(...newValues);\n } else {\n nonAliasValues.push(oldValue);\n }\n }\n return { ...params, [key]: nonAliasValues };\n }\n\n const oldValue = params[key] as JsonPrimitive;\n const isAliasMatched = predicate(oldValue);\n if (isAliasMatched && !Array.isArray(newValue)) {\n return { ...params, [key]: newValue };\n }\n\n return params;\n}\n\nexport function replaceAliases(\n conditions: PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >,\n userInfo: BackstageUserInfo,\n) {\n if ('not' in conditions) {\n replaceAliases(conditions.not, userInfo);\n return;\n }\n if ('allOf' in conditions) {\n for (const condition of conditions.allOf) {\n replaceAliases(condition, userInfo);\n }\n return;\n }\n if ('anyOf' in conditions) {\n for (const condition of conditions.anyOf) {\n replaceAliases(condition, userInfo);\n return;\n }\n }\n\n const params = (\n conditions as PermissionCondition<string, PermissionRuleParams>\n ).params;\n if (params) {\n for (const key of Object.keys(params)) {\n let modifiedParams = replaceAliasWithValue(\n params,\n key,\n isCurrentUserAlias,\n userInfo.userEntityRef,\n );\n\n modifiedParams = replaceAliasWithValue(\n modifiedParams,\n key,\n isOwnerRefsAlias,\n userInfo.ownershipEntityRefs,\n );\n\n (conditions as PermissionCondition<string, PermissionRuleParams>).params =\n modifiedParams;\n }\n }\n}\n"],"names":["CONDITION_ALIAS_SIGN","ConditionalAliases","oldValue","isAliasMatched"],"mappings":";;;;AAiCA,SAAS,iBAAiB,KAAqC,EAAA;AAC7D,EAAA,MAAM,KAAQ,GAAA,CAAA,EAAGA,qCAAoB,CAAA,EAAGC,oCAAmB,UAAU,CAAA,CAAA
|
|
1
|
+
{"version":3,"file":"alias-resolver.cjs.js","sources":["../../src/conditional-aliases/alias-resolver.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 { BackstageUserInfo } from '@backstage/backend-plugin-api';\nimport type {\n PermissionCondition,\n PermissionCriteria,\n PermissionRuleParam,\n PermissionRuleParams,\n} from '@backstage/plugin-permission-common';\nimport type { JsonPrimitive } from '@backstage/types';\n\nimport {\n CONDITION_ALIAS_SIGN,\n ConditionalAliases,\n} from '@backstage-community/plugin-rbac-common';\n\ninterface Predicate<T> {\n (item: T): boolean;\n}\n\nfunction isOwnerRefsAlias(value: PermissionRuleParam): boolean {\n const alias = `${CONDITION_ALIAS_SIGN}${ConditionalAliases.OWNER_REFS}`;\n return value === alias;\n}\n\nfunction isCurrentUserAlias(value: PermissionRuleParam): boolean {\n const alias = `${CONDITION_ALIAS_SIGN}${ConditionalAliases.CURRENT_USER}`;\n return value === alias;\n}\n\nfunction replaceAliasWithValue<\n K extends string,\n V extends JsonPrimitive | JsonPrimitive[],\n>(\n params: Record<K, PermissionRuleParam> | undefined,\n key: K,\n predicate: Predicate<PermissionRuleParam>,\n newValue: V,\n): Record<K, PermissionRuleParam> | undefined {\n if (!params) {\n return params;\n }\n\n if (Array.isArray(params[key])) {\n const oldValues = params[key] as JsonPrimitive[];\n const nonAliasValues: JsonPrimitive[] = [];\n for (const oldValue of oldValues) {\n const isAliasMatched = predicate(oldValue);\n if (isAliasMatched) {\n const newValues = Array.isArray(newValue) ? newValue : [newValue];\n nonAliasValues.push(...newValues);\n } else {\n nonAliasValues.push(oldValue);\n }\n }\n return { ...params, [key]: nonAliasValues };\n }\n\n const oldValue = params[key] as JsonPrimitive;\n const isAliasMatched = predicate(oldValue);\n if (isAliasMatched && !Array.isArray(newValue)) {\n return { ...params, [key]: newValue };\n }\n\n return params;\n}\n\nexport function replaceAliases(\n conditions: PermissionCriteria<\n PermissionCondition<string, PermissionRuleParams>\n >,\n userInfo: BackstageUserInfo,\n) {\n if ('not' in conditions) {\n replaceAliases(conditions.not, userInfo);\n return;\n }\n if ('allOf' in conditions) {\n for (const condition of conditions.allOf) {\n replaceAliases(condition, userInfo);\n }\n return;\n }\n if ('anyOf' in conditions) {\n for (const condition of conditions.anyOf) {\n replaceAliases(condition, userInfo);\n return;\n }\n }\n\n const params = (\n conditions as PermissionCondition<string, PermissionRuleParams>\n ).params;\n if (params) {\n for (const key of Object.keys(params)) {\n let modifiedParams = replaceAliasWithValue(\n params,\n key,\n isCurrentUserAlias,\n userInfo.userEntityRef,\n );\n\n modifiedParams = replaceAliasWithValue(\n modifiedParams,\n key,\n isOwnerRefsAlias,\n userInfo.ownershipEntityRefs,\n );\n\n (conditions as PermissionCondition<string, PermissionRuleParams>).params =\n modifiedParams;\n }\n }\n}\n"],"names":["CONDITION_ALIAS_SIGN","ConditionalAliases","oldValue","isAliasMatched"],"mappings":";;;;AAiCA,SAAS,iBAAiB,KAAqC,EAAA;AAC7D,EAAA,MAAM,KAAQ,GAAA,CAAA,EAAGA,qCAAoB,CAAA,EAAGC,oCAAmB,UAAU,CAAA,CAAA;AACrE,EAAA,OAAO,KAAU,KAAA,KAAA;AACnB;AAEA,SAAS,mBAAmB,KAAqC,EAAA;AAC/D,EAAA,MAAM,KAAQ,GAAA,CAAA,EAAGD,qCAAoB,CAAA,EAAGC,oCAAmB,YAAY,CAAA,CAAA;AACvE,EAAA,OAAO,KAAU,KAAA,KAAA;AACnB;AAEA,SAAS,qBAIP,CAAA,MAAA,EACA,GACA,EAAA,SAAA,EACA,QAC4C,EAAA;AAC5C,EAAA,IAAI,CAAC,MAAQ,EAAA;AACX,IAAO,OAAA,MAAA;AAAA;AAGT,EAAA,IAAI,KAAM,CAAA,OAAA,CAAQ,MAAO,CAAA,GAAG,CAAC,CAAG,EAAA;AAC9B,IAAM,MAAA,SAAA,GAAY,OAAO,GAAG,CAAA;AAC5B,IAAA,MAAM,iBAAkC,EAAC;AACzC,IAAA,KAAA,MAAWC,aAAY,SAAW,EAAA;AAChC,MAAMC,MAAAA,eAAAA,GAAiB,UAAUD,SAAQ,CAAA;AACzC,MAAA,IAAIC,eAAgB,EAAA;AAClB,QAAA,MAAM,YAAY,KAAM,CAAA,OAAA,CAAQ,QAAQ,CAAI,GAAA,QAAA,GAAW,CAAC,QAAQ,CAAA;AAChE,QAAe,cAAA,CAAA,IAAA,CAAK,GAAG,SAAS,CAAA;AAAA,OAC3B,MAAA;AACL,QAAA,cAAA,CAAe,KAAKD,SAAQ,CAAA;AAAA;AAC9B;AAEF,IAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,CAAC,GAAG,GAAG,cAAe,EAAA;AAAA;AAG5C,EAAM,MAAA,QAAA,GAAW,OAAO,GAAG,CAAA;AAC3B,EAAM,MAAA,cAAA,GAAiB,UAAU,QAAQ,CAAA;AACzC,EAAA,IAAI,cAAkB,IAAA,CAAC,KAAM,CAAA,OAAA,CAAQ,QAAQ,CAAG,EAAA;AAC9C,IAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,CAAC,GAAG,GAAG,QAAS,EAAA;AAAA;AAGtC,EAAO,OAAA,MAAA;AACT;AAEgB,SAAA,cAAA,CACd,YAGA,QACA,EAAA;AACA,EAAA,IAAI,SAAS,UAAY,EAAA;AACvB,IAAe,cAAA,CAAA,UAAA,CAAW,KAAK,QAAQ,CAAA;AACvC,IAAA;AAAA;AAEF,EAAA,IAAI,WAAW,UAAY,EAAA;AACzB,IAAW,KAAA,MAAA,SAAA,IAAa,WAAW,KAAO,EAAA;AACxC,MAAA,cAAA,CAAe,WAAW,QAAQ,CAAA;AAAA;AAEpC,IAAA;AAAA;AAEF,EAAA,IAAI,WAAW,UAAY,EAAA;AACzB,IAAW,KAAA,MAAA,SAAA,IAAa,WAAW,KAAO,EAAA;AACxC,MAAA,cAAA,CAAe,WAAW,QAAQ,CAAA;AAClC,MAAA;AAAA;AACF;AAGF,EAAA,MAAM,SACJ,UACA,CAAA,MAAA;AACF,EAAA,IAAI,MAAQ,EAAA;AACV,IAAA,KAAA,MAAW,GAAO,IAAA,MAAA,CAAO,IAAK,CAAA,MAAM,CAAG,EAAA;AACrC,MAAA,IAAI,cAAiB,GAAA,qBAAA;AAAA,QACnB,MAAA;AAAA,QACA,GAAA;AAAA,QACA,kBAAA;AAAA,QACA,QAAS,CAAA;AAAA,OACX;AAEA,MAAiB,cAAA,GAAA,qBAAA;AAAA,QACf,cAAA;AAAA,QACA,GAAA;AAAA,QACA,gBAAA;AAAA,QACA,QAAS,CAAA;AAAA,OACX;AAEA,MAAC,WAAiE,MAChE,GAAA,cAAA;AAAA;AACJ;AAEJ;;;;"}
|
|
@@ -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 = await this.databaseClient.client.config.connection\n .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":";;;;;;;;;;AA0BA,MAAM,iCAAoC,GAAA,aAAA
|
|
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 = await this.databaseClient.client.config.connection\n .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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditional-storage.cjs.js","sources":["../../src/database/conditional-storage.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 { ConflictError, InputError, NotFoundError } from '@backstage/errors';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\n\nimport { Knex } from 'knex';\n\nimport type {\n PermissionAction,\n PermissionInfo,\n RoleConditionalPolicyDecision,\n} from '@backstage-community/plugin-rbac-common';\n\nexport const CONDITIONAL_TABLE = 'role-condition-policies';\n\nexport interface ConditionalPolicyDecisionDAO {\n result: AuthorizeResult.CONDITIONAL;\n id?: number;\n roleEntityRef: string;\n permissions: string;\n pluginId: string;\n resourceType: string;\n conditionsJson: string;\n}\n\nexport interface ConditionalStorage {\n filterConditions(\n roleEntityRef?: string | string[],\n pluginId?: string,\n resourceType?: string,\n actions?: PermissionAction[],\n permissionNames?: string[],\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo>[]>;\n createCondition(\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<number>;\n checkConflictedConditions(\n roleEntityRef: string,\n resourceType: string,\n pluginId: string,\n queryPermissionNames: string[],\n idToExclude?: number,\n ): Promise<void>;\n getCondition(\n id: number,\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo> | undefined>;\n deleteCondition(id: number): Promise<void>;\n updateCondition(\n id: number,\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<void>;\n}\n\nexport class DataBaseConditionalStorage implements ConditionalStorage {\n public constructor(private readonly knex: Knex<any, any[]>) {}\n\n async filterConditions(\n roleEntityRef?: string | string[],\n pluginId?: string,\n resourceType?: string,\n actions?: PermissionAction[],\n permissionNames?: string[],\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo>[]> {\n const daoRaws = await this.knex.table(CONDITIONAL_TABLE).where(builder => {\n if (pluginId) {\n builder.where('pluginId', pluginId);\n }\n if (resourceType) {\n builder.where('resourceType', resourceType);\n }\n if (roleEntityRef) {\n if (Array.isArray(roleEntityRef)) {\n builder.whereIn('roleEntityRef', roleEntityRef);\n } else {\n builder.where('roleEntityRef', roleEntityRef);\n }\n }\n });\n\n let conditions: RoleConditionalPolicyDecision<PermissionInfo>[] = [];\n if (daoRaws) {\n conditions = daoRaws.map(dao => this.daoToConditionalDecision(dao));\n }\n\n if (permissionNames && permissionNames.length > 0) {\n conditions = conditions.filter(condition => {\n return permissionNames.every(permissionName =>\n condition.permissionMapping\n .map(permInfo => permInfo.name)\n .includes(permissionName),\n );\n });\n }\n\n if (actions && actions.length > 0) {\n conditions = conditions.filter(condition => {\n return actions.every(action =>\n condition.permissionMapping\n .map(permInfo => permInfo.action)\n .includes(action),\n );\n });\n }\n\n return conditions;\n }\n\n async createCondition(\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<number> {\n await this.checkConflictedConditions(\n conditionalDecision.roleEntityRef,\n conditionalDecision.resourceType,\n conditionalDecision.pluginId,\n conditionalDecision.permissionMapping.map(permInfo => permInfo.action),\n );\n\n const conditionRaw = this.toDAO(conditionalDecision);\n const result = await this.knex\n .table(CONDITIONAL_TABLE)\n .insert<ConditionalPolicyDecisionDAO>(conditionRaw)\n .returning('id');\n if (result && result?.length > 0) {\n return result[0].id;\n }\n\n throw new Error(`Failed to create the condition.`);\n }\n\n async checkConflictedConditions(\n roleEntityRef: string,\n resourceType: string,\n pluginId: string,\n queryConditionActions: PermissionAction[],\n idToExclude?: number,\n ): Promise<void> {\n let conditionsForTheSameResource = await this.filterConditions(\n roleEntityRef,\n pluginId,\n resourceType,\n );\n conditionsForTheSameResource = conditionsForTheSameResource.filter(\n c => c.id !== idToExclude,\n );\n\n if (conditionsForTheSameResource) {\n const conflictedCondition = conditionsForTheSameResource.find(\n condition => {\n const conditionActions = condition.permissionMapping.map(\n permInfo => permInfo.action,\n );\n return queryConditionActions.some(action =>\n conditionActions.includes(action),\n );\n },\n );\n\n if (conflictedCondition) {\n const conflictedActions = queryConditionActions.filter(action =>\n conflictedCondition.permissionMapping.some(p => p.action === action),\n );\n throw new ConflictError(\n `Found condition with conflicted permission action '${JSON.stringify(\n conflictedActions,\n )}'. Role could have multiple ` +\n `conditions for the same resource type '${conflictedCondition.resourceType}', but with different permission action sets.`,\n );\n }\n }\n }\n\n async getCondition(\n id: number,\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo> | undefined> {\n const daoRaw = await this.knex\n .table(CONDITIONAL_TABLE)\n .where('id', id)\n .first();\n\n if (daoRaw) {\n return this.daoToConditionalDecision(daoRaw);\n }\n return undefined;\n }\n\n async deleteCondition(id: number): Promise<void> {\n const condition = await this.getCondition(id);\n if (!condition) {\n throw new NotFoundError(`Condition with id ${id} was not found`);\n }\n await this.knex?.table(CONDITIONAL_TABLE).delete().whereIn('id', [id]);\n }\n\n async updateCondition(\n id: number,\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<void> {\n const condition = await this.getCondition(id);\n if (!condition) {\n throw new NotFoundError(`Condition with id ${id} was not found`);\n }\n\n await this.checkConflictedConditions(\n conditionalDecision.roleEntityRef,\n conditionalDecision.resourceType,\n conditionalDecision.pluginId,\n conditionalDecision.permissionMapping.map(perm => perm.action),\n id,\n );\n\n const conditionRaw = this.toDAO(conditionalDecision);\n conditionRaw.id = id;\n const result = await this.knex\n .table(CONDITIONAL_TABLE)\n .where('id', conditionRaw.id)\n .update<ConditionalPolicyDecisionDAO>(conditionRaw)\n .returning('id');\n\n if (!result || result.length === 0) {\n throw new Error(`Failed to update the condition with id: ${id}.`);\n }\n }\n\n private toDAO(\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): ConditionalPolicyDecisionDAO {\n const {\n result,\n pluginId,\n resourceType,\n conditions,\n roleEntityRef,\n permissionMapping,\n } = conditionalDecision;\n const conditionsJson = JSON.stringify(conditions);\n return {\n result,\n pluginId,\n resourceType,\n conditionsJson,\n roleEntityRef,\n permissions: JSON.stringify(permissionMapping),\n };\n }\n\n private daoToConditionalDecision(\n dao: ConditionalPolicyDecisionDAO,\n ): RoleConditionalPolicyDecision<PermissionInfo> {\n if (!dao.id) {\n throw new InputError(`Missed id in the dao object: ${dao}`);\n }\n const {\n id,\n result,\n pluginId,\n resourceType,\n conditionsJson,\n roleEntityRef,\n permissions,\n } = dao;\n\n const conditions = JSON.parse(conditionsJson);\n return {\n id,\n result,\n pluginId,\n resourceType,\n conditions,\n roleEntityRef,\n permissionMapping: JSON.parse(permissions),\n };\n }\n}\n"],"names":["ConflictError","NotFoundError","InputError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"conditional-storage.cjs.js","sources":["../../src/database/conditional-storage.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 { ConflictError, InputError, NotFoundError } from '@backstage/errors';\nimport { AuthorizeResult } from '@backstage/plugin-permission-common';\n\nimport { Knex } from 'knex';\n\nimport type {\n PermissionAction,\n PermissionInfo,\n RoleConditionalPolicyDecision,\n} from '@backstage-community/plugin-rbac-common';\n\nexport const CONDITIONAL_TABLE = 'role-condition-policies';\n\nexport interface ConditionalPolicyDecisionDAO {\n result: AuthorizeResult.CONDITIONAL;\n id?: number;\n roleEntityRef: string;\n permissions: string;\n pluginId: string;\n resourceType: string;\n conditionsJson: string;\n}\n\nexport interface ConditionalStorage {\n filterConditions(\n roleEntityRef?: string | string[],\n pluginId?: string,\n resourceType?: string,\n actions?: PermissionAction[],\n permissionNames?: string[],\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo>[]>;\n createCondition(\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<number>;\n checkConflictedConditions(\n roleEntityRef: string,\n resourceType: string,\n pluginId: string,\n queryPermissionNames: string[],\n idToExclude?: number,\n ): Promise<void>;\n getCondition(\n id: number,\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo> | undefined>;\n deleteCondition(id: number): Promise<void>;\n updateCondition(\n id: number,\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<void>;\n}\n\nexport class DataBaseConditionalStorage implements ConditionalStorage {\n public constructor(private readonly knex: Knex<any, any[]>) {}\n\n async filterConditions(\n roleEntityRef?: string | string[],\n pluginId?: string,\n resourceType?: string,\n actions?: PermissionAction[],\n permissionNames?: string[],\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo>[]> {\n const daoRaws = await this.knex.table(CONDITIONAL_TABLE).where(builder => {\n if (pluginId) {\n builder.where('pluginId', pluginId);\n }\n if (resourceType) {\n builder.where('resourceType', resourceType);\n }\n if (roleEntityRef) {\n if (Array.isArray(roleEntityRef)) {\n builder.whereIn('roleEntityRef', roleEntityRef);\n } else {\n builder.where('roleEntityRef', roleEntityRef);\n }\n }\n });\n\n let conditions: RoleConditionalPolicyDecision<PermissionInfo>[] = [];\n if (daoRaws) {\n conditions = daoRaws.map(dao => this.daoToConditionalDecision(dao));\n }\n\n if (permissionNames && permissionNames.length > 0) {\n conditions = conditions.filter(condition => {\n return permissionNames.every(permissionName =>\n condition.permissionMapping\n .map(permInfo => permInfo.name)\n .includes(permissionName),\n );\n });\n }\n\n if (actions && actions.length > 0) {\n conditions = conditions.filter(condition => {\n return actions.every(action =>\n condition.permissionMapping\n .map(permInfo => permInfo.action)\n .includes(action),\n );\n });\n }\n\n return conditions;\n }\n\n async createCondition(\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<number> {\n await this.checkConflictedConditions(\n conditionalDecision.roleEntityRef,\n conditionalDecision.resourceType,\n conditionalDecision.pluginId,\n conditionalDecision.permissionMapping.map(permInfo => permInfo.action),\n );\n\n const conditionRaw = this.toDAO(conditionalDecision);\n const result = await this.knex\n .table(CONDITIONAL_TABLE)\n .insert<ConditionalPolicyDecisionDAO>(conditionRaw)\n .returning('id');\n if (result && result?.length > 0) {\n return result[0].id;\n }\n\n throw new Error(`Failed to create the condition.`);\n }\n\n async checkConflictedConditions(\n roleEntityRef: string,\n resourceType: string,\n pluginId: string,\n queryConditionActions: PermissionAction[],\n idToExclude?: number,\n ): Promise<void> {\n let conditionsForTheSameResource = await this.filterConditions(\n roleEntityRef,\n pluginId,\n resourceType,\n );\n conditionsForTheSameResource = conditionsForTheSameResource.filter(\n c => c.id !== idToExclude,\n );\n\n if (conditionsForTheSameResource) {\n const conflictedCondition = conditionsForTheSameResource.find(\n condition => {\n const conditionActions = condition.permissionMapping.map(\n permInfo => permInfo.action,\n );\n return queryConditionActions.some(action =>\n conditionActions.includes(action),\n );\n },\n );\n\n if (conflictedCondition) {\n const conflictedActions = queryConditionActions.filter(action =>\n conflictedCondition.permissionMapping.some(p => p.action === action),\n );\n throw new ConflictError(\n `Found condition with conflicted permission action '${JSON.stringify(\n conflictedActions,\n )}'. Role could have multiple ` +\n `conditions for the same resource type '${conflictedCondition.resourceType}', but with different permission action sets.`,\n );\n }\n }\n }\n\n async getCondition(\n id: number,\n ): Promise<RoleConditionalPolicyDecision<PermissionInfo> | undefined> {\n const daoRaw = await this.knex\n .table(CONDITIONAL_TABLE)\n .where('id', id)\n .first();\n\n if (daoRaw) {\n return this.daoToConditionalDecision(daoRaw);\n }\n return undefined;\n }\n\n async deleteCondition(id: number): Promise<void> {\n const condition = await this.getCondition(id);\n if (!condition) {\n throw new NotFoundError(`Condition with id ${id} was not found`);\n }\n await this.knex?.table(CONDITIONAL_TABLE).delete().whereIn('id', [id]);\n }\n\n async updateCondition(\n id: number,\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): Promise<void> {\n const condition = await this.getCondition(id);\n if (!condition) {\n throw new NotFoundError(`Condition with id ${id} was not found`);\n }\n\n await this.checkConflictedConditions(\n conditionalDecision.roleEntityRef,\n conditionalDecision.resourceType,\n conditionalDecision.pluginId,\n conditionalDecision.permissionMapping.map(perm => perm.action),\n id,\n );\n\n const conditionRaw = this.toDAO(conditionalDecision);\n conditionRaw.id = id;\n const result = await this.knex\n .table(CONDITIONAL_TABLE)\n .where('id', conditionRaw.id)\n .update<ConditionalPolicyDecisionDAO>(conditionRaw)\n .returning('id');\n\n if (!result || result.length === 0) {\n throw new Error(`Failed to update the condition with id: ${id}.`);\n }\n }\n\n private toDAO(\n conditionalDecision: RoleConditionalPolicyDecision<PermissionInfo>,\n ): ConditionalPolicyDecisionDAO {\n const {\n result,\n pluginId,\n resourceType,\n conditions,\n roleEntityRef,\n permissionMapping,\n } = conditionalDecision;\n const conditionsJson = JSON.stringify(conditions);\n return {\n result,\n pluginId,\n resourceType,\n conditionsJson,\n roleEntityRef,\n permissions: JSON.stringify(permissionMapping),\n };\n }\n\n private daoToConditionalDecision(\n dao: ConditionalPolicyDecisionDAO,\n ): RoleConditionalPolicyDecision<PermissionInfo> {\n if (!dao.id) {\n throw new InputError(`Missed id in the dao object: ${dao}`);\n }\n const {\n id,\n result,\n pluginId,\n resourceType,\n conditionsJson,\n roleEntityRef,\n permissions,\n } = dao;\n\n const conditions = JSON.parse(conditionsJson);\n return {\n id,\n result,\n pluginId,\n resourceType,\n conditions,\n roleEntityRef,\n permissionMapping: JSON.parse(permissions),\n };\n }\n}\n"],"names":["ConflictError","NotFoundError","InputError"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.cjs.js","sources":["../../src/database/migration.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 DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-rbac-backend', // Package name\n 'migrations', // Migrations directory\n);\n\nexport async function migrate(databaseManager: DatabaseService) {\n const knex = await databaseManager.getClient();\n\n if (!databaseManager.migrations?.skip) {\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n }\n}\n"],"names":["resolvePackagePath"],"mappings":";;;;AAoBA,MAAM,aAAgB,GAAAA,mCAAA;AAAA,EACpB,0CAAA;AAAA;AAAA,EACA
|
|
1
|
+
{"version":3,"file":"migration.cjs.js","sources":["../../src/database/migration.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 DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-rbac-backend', // Package name\n 'migrations', // Migrations directory\n);\n\nexport async function migrate(databaseManager: DatabaseService) {\n const knex = await databaseManager.getClient();\n\n if (!databaseManager.migrations?.skip) {\n await knex.migrate.latest({\n directory: migrationsDir,\n });\n }\n}\n"],"names":["resolvePackagePath"],"mappings":";;;;AAoBA,MAAM,aAAgB,GAAAA,mCAAA;AAAA,EACpB,0CAAA;AAAA;AAAA,EACA;AAAA;AACF,CAAA;AAEA,eAAsB,QAAQ,eAAkC,EAAA;AAC9D,EAAM,MAAA,IAAA,GAAO,MAAM,eAAA,CAAgB,SAAU,EAAA;AAE7C,EAAI,IAAA,CAAC,eAAgB,CAAA,UAAA,EAAY,IAAM,EAAA;AACrC,IAAM,MAAA,IAAA,CAAK,QAAQ,MAAO,CAAA;AAAA,MACxB,SAAW,EAAA;AAAA,KACZ,CAAA;AAAA;AAEL;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-metadata.cjs.js","sources":["../../src/database/role-metadata.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 { ConflictError, InputError, NotFoundError } from '@backstage/errors';\n\nimport { Knex } from 'knex';\n\nimport type {\n RoleMetadata,\n Source,\n} from '@backstage-community/plugin-rbac-common';\n\nimport { deepSortedEqual } from '../helper';\n\nexport const ROLE_METADATA_TABLE = 'role-metadata';\n\nexport interface RoleMetadataDao extends RoleMetadata {\n id?: number;\n roleEntityRef: string;\n source: Source;\n modifiedBy: string;\n}\n\nexport interface RoleMetadataStorage {\n filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]>;\n findRoleMetadata(\n roleEntityRef: string,\n trx?: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined>;\n createRoleMetadata(\n roleMetadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number>;\n updateRoleMetadata(\n roleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void>;\n removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void>;\n}\n\nexport class DataBaseRoleMetadataStorage implements RoleMetadataStorage {\n constructor(private readonly knex: Knex<any, any[]>) {}\n\n async filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]> {\n return await this.knex.table(ROLE_METADATA_TABLE).where(builder => {\n if (source) {\n builder.where('source', source);\n }\n });\n }\n\n async findRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined> {\n const db = trx || this.knex;\n return await db\n .table(ROLE_METADATA_TABLE)\n .where('roleEntityRef', roleEntityRef)\n // roleEntityRef should be unique.\n .first();\n }\n\n async createRoleMetadata(\n metadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number> {\n if (await this.findRoleMetadata(metadata.roleEntityRef, trx)) {\n throw new ConflictError(\n `A metadata for role ${metadata.roleEntityRef} has already been stored`,\n );\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .insert(metadata)\n .returning<[{ id: number }]>('id');\n if (result && result?.length > 0) {\n return result[0].id;\n }\n\n throw new Error(\n `Failed to create the role metadata: '${JSON.stringify(metadata)}'.`,\n );\n }\n\n async updateRoleMetadata(\n newRoleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n const currentMetadataDao = await this.findRoleMetadata(\n oldRoleEntityRef,\n trx,\n );\n\n if (!currentMetadataDao) {\n throw new NotFoundError(\n `A metadata for role '${oldRoleEntityRef}' was not found`,\n );\n }\n\n if (\n currentMetadataDao.source !== 'legacy' &&\n currentMetadataDao.source !== newRoleMetadata.source\n ) {\n throw new InputError(`The RoleMetadata.source field is 'read-only'.`);\n }\n\n if (deepSortedEqual(currentMetadataDao, newRoleMetadata)) {\n return;\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .where('id', currentMetadataDao.id)\n .update(newRoleMetadata)\n .returning('id');\n\n if (!externalTrx) {\n await trx.commit();\n }\n\n if (!result || result.length === 0) {\n throw new Error(\n `Failed to update the role metadata '${JSON.stringify(\n currentMetadataDao,\n )}' with new value: '${JSON.stringify(newRoleMetadata)}'.`,\n );\n }\n }\n\n async removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void> {\n const metadataDao = await this.findRoleMetadata(roleEntityRef, trx);\n if (!metadataDao) {\n throw new NotFoundError(\n `A metadata for role '${roleEntityRef}' was not found`,\n );\n }\n\n await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .delete()\n .whereIn('id', [metadataDao.id!]);\n }\n}\n\nexport function daoToMetadata(dao: RoleMetadataDao): RoleMetadata {\n return {\n source: dao.source,\n description: dao.description,\n author: dao.author,\n modifiedBy: dao.modifiedBy,\n createdAt: dao.createdAt,\n lastModified: dao.lastModified,\n };\n}\n"],"names":["ConflictError","NotFoundError","InputError","deepSortedEqual"],"mappings":";;;;;AA0BO,MAAM,mBAAsB,GAAA
|
|
1
|
+
{"version":3,"file":"role-metadata.cjs.js","sources":["../../src/database/role-metadata.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 { ConflictError, InputError, NotFoundError } from '@backstage/errors';\n\nimport { Knex } from 'knex';\n\nimport type {\n RoleMetadata,\n Source,\n} from '@backstage-community/plugin-rbac-common';\n\nimport { deepSortedEqual } from '../helper';\n\nexport const ROLE_METADATA_TABLE = 'role-metadata';\n\nexport interface RoleMetadataDao extends RoleMetadata {\n id?: number;\n roleEntityRef: string;\n source: Source;\n modifiedBy: string;\n}\n\nexport interface RoleMetadataStorage {\n filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]>;\n findRoleMetadata(\n roleEntityRef: string,\n trx?: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined>;\n createRoleMetadata(\n roleMetadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number>;\n updateRoleMetadata(\n roleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void>;\n removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void>;\n}\n\nexport class DataBaseRoleMetadataStorage implements RoleMetadataStorage {\n constructor(private readonly knex: Knex<any, any[]>) {}\n\n async filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]> {\n return await this.knex.table(ROLE_METADATA_TABLE).where(builder => {\n if (source) {\n builder.where('source', source);\n }\n });\n }\n\n async findRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined> {\n const db = trx || this.knex;\n return await db\n .table(ROLE_METADATA_TABLE)\n .where('roleEntityRef', roleEntityRef)\n // roleEntityRef should be unique.\n .first();\n }\n\n async createRoleMetadata(\n metadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number> {\n if (await this.findRoleMetadata(metadata.roleEntityRef, trx)) {\n throw new ConflictError(\n `A metadata for role ${metadata.roleEntityRef} has already been stored`,\n );\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .insert(metadata)\n .returning<[{ id: number }]>('id');\n if (result && result?.length > 0) {\n return result[0].id;\n }\n\n throw new Error(\n `Failed to create the role metadata: '${JSON.stringify(metadata)}'.`,\n );\n }\n\n async updateRoleMetadata(\n newRoleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n const currentMetadataDao = await this.findRoleMetadata(\n oldRoleEntityRef,\n trx,\n );\n\n if (!currentMetadataDao) {\n throw new NotFoundError(\n `A metadata for role '${oldRoleEntityRef}' was not found`,\n );\n }\n\n if (\n currentMetadataDao.source !== 'legacy' &&\n currentMetadataDao.source !== newRoleMetadata.source\n ) {\n throw new InputError(`The RoleMetadata.source field is 'read-only'.`);\n }\n\n if (deepSortedEqual(currentMetadataDao, newRoleMetadata)) {\n return;\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .where('id', currentMetadataDao.id)\n .update(newRoleMetadata)\n .returning('id');\n\n if (!externalTrx) {\n await trx.commit();\n }\n\n if (!result || result.length === 0) {\n throw new Error(\n `Failed to update the role metadata '${JSON.stringify(\n currentMetadataDao,\n )}' with new value: '${JSON.stringify(newRoleMetadata)}'.`,\n );\n }\n }\n\n async removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void> {\n const metadataDao = await this.findRoleMetadata(roleEntityRef, trx);\n if (!metadataDao) {\n throw new NotFoundError(\n `A metadata for role '${roleEntityRef}' was not found`,\n );\n }\n\n await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .delete()\n .whereIn('id', [metadataDao.id!]);\n }\n}\n\nexport function daoToMetadata(dao: RoleMetadataDao): RoleMetadata {\n return {\n source: dao.source,\n description: dao.description,\n author: dao.author,\n modifiedBy: dao.modifiedBy,\n createdAt: dao.createdAt,\n lastModified: dao.lastModified,\n };\n}\n"],"names":["ConflictError","NotFoundError","InputError","deepSortedEqual"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csv-file-watcher.cjs.js","sources":["../../src/file-permissions/csv-file-watcher.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 { Enforcer, FileAdapter, newEnforcer, newModelFromString } from 'casbin';\nimport { parse } from 'csv-parse/sync';\nimport { difference } from 'lodash';\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 {\n RoleMetadataDao,\n RoleMetadataStorage,\n} from '../database/role-metadata';\nimport {\n mergeRoleMetadata,\n metadataStringToPolicy,\n policyToString,\n transformArrayToPolicy,\n} from '../helper';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { MODEL } from '../service/permission-model';\nimport {\n checkForDuplicateGroupPolicies,\n checkForDuplicatePolicies,\n validateGroupingPolicy,\n validatePolicy,\n validateSource,\n} from '../validation/policies-validation';\nimport { AbstractFileWatcher } from './file-watcher';\n\nexport const CSV_PERMISSION_POLICY_FILE_AUTHOR = 'csv permission policy file';\n\ntype CSVFilePolicies = {\n addedPolicies: string[][];\n addedGroupPolicies: string[][];\n removedPolicies: string[][];\n removedGroupPolicies: string[][];\n};\n\nexport class CSVFileWatcher extends AbstractFileWatcher<string[][]> {\n private currentContent: string[][];\n private csvFilePolicies: CSVFilePolicies;\n\n constructor(\n filePath: string | undefined,\n allowReload: boolean,\n logger: LoggerService,\n private readonly enforcer: EnforcerDelegate,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly auditLogger: AuditLogger,\n ) {\n super(filePath, allowReload, logger);\n this.currentContent = [];\n this.csvFilePolicies = {\n addedPolicies: [],\n addedGroupPolicies: [],\n removedPolicies: [],\n removedGroupPolicies: [],\n };\n }\n\n /**\n * parse is used to parse the current contents of the CSV file.\n * @returns The CSV file parsed into a string[][].\n */\n parse(): string[][] {\n const content = this.getCurrentContents();\n const parser = parse(content, {\n skip_empty_lines: true,\n relax_column_count: true,\n trim: true,\n });\n\n return parser;\n }\n\n /**\n * initialize will initialize the CSV file by loading all of the permission policies and roles into\n * the enforcer.\n * First, we will remove all roles and permission policies if they do not exist in the temporary file enforcer.\n * Next, we will add all roles and permission polices if they are new to the CSV file\n * Finally, we will set the file to be watched if allow reload is set\n * @param csvFileName The name of the csvFile\n * @param allowReload Whether or not we will allow reloads of the CSV file\n */\n async initialize(): Promise<void> {\n if (!this.filePath) {\n return;\n }\n let content: string[][] = [];\n // If the file is set load the file contents\n content = this.parse();\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new FileAdapter(this.filePath),\n );\n\n // Check for any old policies that will need to be removed by checking if\n // the policy no longer exists in the temp enforcer (csv file)\n const roleMetadatas = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const fileRoles = roleMetadatas.map(meta => meta.roleEntityRef);\n\n if (fileRoles.length > 0) {\n const groupingPoliciesToRemove =\n await this.enforcer.getFilteredGroupingPolicy(1, ...fileRoles);\n for (const gPolicy of groupingPoliciesToRemove) {\n if (!(await tempEnforcer.hasGroupingPolicy(...gPolicy))) {\n this.csvFilePolicies.removedGroupPolicies.push(gPolicy);\n }\n }\n const policiesToRemove = await this.enforcer.getFilteredPolicy(\n 0,\n ...fileRoles,\n );\n for (const policy of policiesToRemove) {\n if (!(await tempEnforcer.hasPolicy(...policy))) {\n this.csvFilePolicies.removedPolicies.push(policy);\n }\n }\n }\n\n // Check for any new policies that need to be added by checking if\n // the policy does not currently exist in the enforcer\n const policiesToAdd = await tempEnforcer.getPolicy();\n const groupPoliciesToAdd = await tempEnforcer.getGroupingPolicy();\n\n for (const policy of policiesToAdd) {\n if (!(await this.enforcer.hasPolicy(...policy))) {\n this.csvFilePolicies.addedPolicies.push(policy);\n }\n }\n\n for (const groupPolicy of groupPoliciesToAdd) {\n if (!(await this.enforcer.hasGroupingPolicy(...groupPolicy))) {\n this.csvFilePolicies.addedGroupPolicies.push(groupPolicy);\n }\n }\n\n await this.migrateLegacyMetadata(tempEnforcer);\n\n // We pass current here because this is during initialization and it has not changed yet\n await this.updatePolicies(content, tempEnforcer);\n\n if (this.allowReload) {\n this.watchFile();\n }\n }\n\n // Check for policies that might need to be updated\n // This will involve update \"legacy\" source in the role metadata if it exist in both the\n // temp enforcer (csv file) and a role metadata storage.\n // We will update role metadata with the new source \"csv-file\"\n private async migrateLegacyMetadata(tempEnforcer: Enforcer) {\n let legacyRolesMetadata = await this.roleMetadataStorage.filterRoleMetadata(\n 'legacy',\n );\n const legacyRoles = legacyRolesMetadata.map(meta => meta.roleEntityRef);\n if (legacyRoles.length > 0) {\n const legacyGroupPolicies = await tempEnforcer.getFilteredGroupingPolicy(\n 1,\n ...legacyRoles,\n );\n const legacyPolicies = await tempEnforcer.getFilteredPolicy(\n 0,\n ...legacyRoles,\n );\n const legacyRolesFromFile = new Set([\n ...legacyGroupPolicies.map(gp => gp[1]),\n ...legacyPolicies.map(p => p[0]),\n ]);\n legacyRolesMetadata = legacyRolesMetadata.filter(meta =>\n legacyRolesFromFile.has(meta.roleEntityRef),\n );\n for (const legacyRoleMeta of legacyRolesMetadata) {\n const nonLegacyRole = mergeRoleMetadata(legacyRoleMeta, {\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n source: 'csv-file',\n roleEntityRef: legacyRoleMeta.roleEntityRef,\n });\n await this.roleMetadataStorage.updateRoleMetadata(\n nonLegacyRole,\n legacyRoleMeta.roleEntityRef,\n );\n }\n }\n }\n\n /**\n * onChange is called whenever there is a change to the CSV file.\n * It will parse the current and new contents of the CSV file and process the roles and permission policies present.\n * Afterwards, it will find the difference between the current and new contents of the CSV file\n * and sort them into added / removed, permission policies / roles.\n * It will finally call updatePolicies with the new content.\n */\n async onChange(): Promise<void> {\n const newContent = this.parse();\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new FileAdapter(this.filePath!),\n );\n\n const currentFlatContent = this.currentContent.flatMap(data => {\n return policyToString(data);\n });\n const newFlatContent = newContent.flatMap(data => {\n return policyToString(data);\n });\n\n const diffRemoved = difference(currentFlatContent, newFlatContent); // policy was removed\n const diffAdded = difference(newFlatContent, currentFlatContent); // policy was added\n\n await this.migrateLegacyMetadata(tempEnforcer);\n\n if (diffRemoved.length === 0 && diffAdded.length === 0) {\n return;\n }\n\n diffRemoved.forEach(policy => {\n const convertedPolicy = metadataStringToPolicy(policy);\n if (convertedPolicy[0] === 'p') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.removedPolicies.push(convertedPolicy);\n } else if (convertedPolicy[0] === 'g') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.removedGroupPolicies.push(convertedPolicy);\n }\n });\n\n diffAdded.forEach(policy => {\n const convertedPolicy = metadataStringToPolicy(policy);\n if (convertedPolicy[0] === 'p') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.addedPolicies.push(convertedPolicy);\n } else if (convertedPolicy[0] === 'g') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.addedGroupPolicies.push(convertedPolicy);\n }\n });\n\n await this.updatePolicies(newContent, tempEnforcer);\n }\n\n /**\n * updatePolicies is used to update all of the permission policies and roles within a CSV file.\n * It will check the number of added and removed permissions policies and roles and call the appropriate\n * methods for these.\n * It will also update the current contents of the CSV file to the most recent\n * @param newContent The new content present in the CSV file\n * @param tempEnforcer Temporary enforcer for checking for duplicates when adding policies\n */\n private async updatePolicies(\n newContent: string[][],\n tempEnforcer: Enforcer,\n ): Promise<void> {\n this.currentContent = newContent;\n\n if (this.csvFilePolicies.addedPolicies.length > 0)\n await this.addPermissionPolicies(tempEnforcer);\n if (this.csvFilePolicies.removedPolicies.length > 0)\n await this.removePermissionPolicies();\n if (this.csvFilePolicies.addedGroupPolicies.length > 0)\n await this.addRoles(tempEnforcer);\n if (this.csvFilePolicies.removedGroupPolicies.length > 0)\n await this.removeRoles();\n }\n\n /**\n * addPermissionPolicies will add the new permission policies that are present in the CSV file.\n * We will attempt to validate the permission policy and log any warnings that are encountered.\n * If a warning is encountered, we will skip adding the permission policy to the enforcer.\n * @param tempEnforcer Temporary enforcer for checking for duplicates when adding policies\n */\n private async addPermissionPolicies(tempEnforcer: Enforcer): Promise<void> {\n for (const policy of this.csvFilePolicies.addedPolicies) {\n const transformedPolicy = transformArrayToPolicy(policy);\n const metadata = await this.roleMetadataStorage.findRoleMetadata(\n policy[0],\n );\n\n let err = validatePolicy(transformedPolicy);\n if (err) {\n this.logger.warn(\n `Failed to validate policy from file ${this.filePath}. Cause: ${err.message}`,\n );\n continue;\n }\n\n err = await validateSource('csv-file', metadata);\n if (err) {\n this.logger.warn(\n `Unable to add policy ${policy} from file ${this.filePath}. Cause: ${err.message}`,\n );\n continue;\n }\n\n err = await checkForDuplicatePolicies(\n tempEnforcer,\n policy,\n this.filePath!,\n );\n if (err) {\n this.logger.warn(err.message);\n continue;\n }\n try {\n await this.enforcer.addPolicy(policy);\n\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created policy`,\n eventName: PermissionEvents.CREATE_POLICY,\n metadata: { policies: [policy], source: 'csv-file' },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to add or update policy ${policy} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n }\n\n this.csvFilePolicies.addedPolicies = [];\n }\n\n /**\n * removePermissionPolicies will remove the permission policies that are no longer present in the CSV file.\n */\n private async removePermissionPolicies(): Promise<void> {\n try {\n await this.enforcer.removePolicies(this.csvFilePolicies.removedPolicies);\n\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Deleted policies`,\n eventName: PermissionEvents.DELETE_POLICY,\n metadata: {\n policies: this.csvFilePolicies.removedPolicies,\n source: 'csv-file',\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to remove policies ${JSON.stringify(\n this.csvFilePolicies.removedPolicies,\n )} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n this.csvFilePolicies.removedPolicies = [];\n }\n\n /**\n * addRoles will add the new roles that are present in the CSV file.\n * We will attempt to validate the role and log any warnings that are encountered.\n * If a warning is encountered, we will skip adding the role to the enforcer.\n * @param tempEnforcer Temporary enforcer for checking for duplicates when adding policies\n */\n private async addRoles(tempEnforcer: Enforcer): Promise<void> {\n for (const groupPolicy of this.csvFilePolicies.addedGroupPolicies) {\n let err = await validateGroupingPolicy(\n groupPolicy,\n this.roleMetadataStorage,\n 'csv-file',\n );\n if (err) {\n this.logger.warn(\n `${err.message}, error originates from file ${this.filePath}`,\n );\n continue;\n }\n\n err = await checkForDuplicateGroupPolicies(\n tempEnforcer,\n groupPolicy,\n this.filePath!,\n );\n if (err) {\n this.logger.warn(err.message);\n continue;\n }\n\n try {\n const roleMetadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef: groupPolicy[1],\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n\n const currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n roleMetadata.roleEntityRef,\n );\n\n await this.enforcer.addGroupingPolicy(groupPolicy, roleMetadata);\n\n const eventName = currentMetadata\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.CREATE_ROLE;\n const message = currentMetadata ? 'Updated role' : 'Created role';\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMetadata, members: [groupPolicy[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to add or update group policy ${groupPolicy} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n }\n this.csvFilePolicies.addedGroupPolicies = [];\n }\n\n /**\n * removeRoles will remove the roles that are no longer present in the CSV file.\n * If the role exists with multiple groups and or users, we will update it role information.\n * Otherwise, we will remove the role completely.\n */\n private async removeRoles(): Promise<void> {\n for (const groupPolicy of this.csvFilePolicies.removedGroupPolicies) {\n const roleEntityRef = groupPolicy[1];\n // this requires knowledge of whether or not it is an update\n const isUpdate = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n roleEntityRef,\n );\n\n // Need to update the time\n try {\n const metadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef,\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n\n await this.enforcer.removeGroupingPolicy(\n groupPolicy,\n metadata,\n isUpdate.length > 1,\n );\n\n const isRolePresent = await this.roleMetadataStorage.findRoleMetadata(\n roleEntityRef,\n );\n const eventName = isRolePresent\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.DELETE_ROLE;\n const message = isRolePresent\n ? 'Updated role: deleted members'\n : 'Deleted role';\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...metadata, members: [groupPolicy[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to remove group policy ${groupPolicy} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n }\n this.csvFilePolicies.removedGroupPolicies = [];\n }\n\n async cleanUpRolesAndPolicies(): Promise<void> {\n const roleMetadatas = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const fileRoles = roleMetadatas.map(meta => meta.roleEntityRef);\n\n if (fileRoles.length > 0) {\n for (const fileRole of fileRoles) {\n this.csvFilePolicies.removedGroupPolicies.push(\n ...(await this.enforcer.getFilteredGroupingPolicy(1, fileRole)),\n );\n this.csvFilePolicies.removedPolicies.push(\n ...(await this.enforcer.getFilteredPolicy(0, fileRole)),\n );\n }\n }\n await this.removePermissionPolicies();\n await this.removeRoles();\n }\n}\n"],"names":["AbstractFileWatcher","parse","newEnforcer","newModelFromString","MODEL","FileAdapter","mergeRoleMetadata","policyToString","difference","metadataStringToPolicy","transformArrayToPolicy","validatePolicy","validateSource","checkForDuplicatePolicies","RBAC_BACKEND","PermissionEvents","HANDLE_RBAC_DATA_STAGE","validateGroupingPolicy","checkForDuplicateGroupPolicies","RoleEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"csv-file-watcher.cjs.js","sources":["../../src/file-permissions/csv-file-watcher.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 { Enforcer, FileAdapter, newEnforcer, newModelFromString } from 'casbin';\nimport { parse } from 'csv-parse/sync';\nimport { difference } from 'lodash';\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 {\n RoleMetadataDao,\n RoleMetadataStorage,\n} from '../database/role-metadata';\nimport {\n mergeRoleMetadata,\n metadataStringToPolicy,\n policyToString,\n transformArrayToPolicy,\n} from '../helper';\nimport { EnforcerDelegate } from '../service/enforcer-delegate';\nimport { MODEL } from '../service/permission-model';\nimport {\n checkForDuplicateGroupPolicies,\n checkForDuplicatePolicies,\n validateGroupingPolicy,\n validatePolicy,\n validateSource,\n} from '../validation/policies-validation';\nimport { AbstractFileWatcher } from './file-watcher';\n\nexport const CSV_PERMISSION_POLICY_FILE_AUTHOR = 'csv permission policy file';\n\ntype CSVFilePolicies = {\n addedPolicies: string[][];\n addedGroupPolicies: string[][];\n removedPolicies: string[][];\n removedGroupPolicies: string[][];\n};\n\nexport class CSVFileWatcher extends AbstractFileWatcher<string[][]> {\n private currentContent: string[][];\n private csvFilePolicies: CSVFilePolicies;\n\n constructor(\n filePath: string | undefined,\n allowReload: boolean,\n logger: LoggerService,\n private readonly enforcer: EnforcerDelegate,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly auditLogger: AuditLogger,\n ) {\n super(filePath, allowReload, logger);\n this.currentContent = [];\n this.csvFilePolicies = {\n addedPolicies: [],\n addedGroupPolicies: [],\n removedPolicies: [],\n removedGroupPolicies: [],\n };\n }\n\n /**\n * parse is used to parse the current contents of the CSV file.\n * @returns The CSV file parsed into a string[][].\n */\n parse(): string[][] {\n const content = this.getCurrentContents();\n const parser = parse(content, {\n skip_empty_lines: true,\n relax_column_count: true,\n trim: true,\n });\n\n return parser;\n }\n\n /**\n * initialize will initialize the CSV file by loading all of the permission policies and roles into\n * the enforcer.\n * First, we will remove all roles and permission policies if they do not exist in the temporary file enforcer.\n * Next, we will add all roles and permission polices if they are new to the CSV file\n * Finally, we will set the file to be watched if allow reload is set\n * @param csvFileName The name of the csvFile\n * @param allowReload Whether or not we will allow reloads of the CSV file\n */\n async initialize(): Promise<void> {\n if (!this.filePath) {\n return;\n }\n let content: string[][] = [];\n // If the file is set load the file contents\n content = this.parse();\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new FileAdapter(this.filePath),\n );\n\n // Check for any old policies that will need to be removed by checking if\n // the policy no longer exists in the temp enforcer (csv file)\n const roleMetadatas = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const fileRoles = roleMetadatas.map(meta => meta.roleEntityRef);\n\n if (fileRoles.length > 0) {\n const groupingPoliciesToRemove =\n await this.enforcer.getFilteredGroupingPolicy(1, ...fileRoles);\n for (const gPolicy of groupingPoliciesToRemove) {\n if (!(await tempEnforcer.hasGroupingPolicy(...gPolicy))) {\n this.csvFilePolicies.removedGroupPolicies.push(gPolicy);\n }\n }\n const policiesToRemove = await this.enforcer.getFilteredPolicy(\n 0,\n ...fileRoles,\n );\n for (const policy of policiesToRemove) {\n if (!(await tempEnforcer.hasPolicy(...policy))) {\n this.csvFilePolicies.removedPolicies.push(policy);\n }\n }\n }\n\n // Check for any new policies that need to be added by checking if\n // the policy does not currently exist in the enforcer\n const policiesToAdd = await tempEnforcer.getPolicy();\n const groupPoliciesToAdd = await tempEnforcer.getGroupingPolicy();\n\n for (const policy of policiesToAdd) {\n if (!(await this.enforcer.hasPolicy(...policy))) {\n this.csvFilePolicies.addedPolicies.push(policy);\n }\n }\n\n for (const groupPolicy of groupPoliciesToAdd) {\n if (!(await this.enforcer.hasGroupingPolicy(...groupPolicy))) {\n this.csvFilePolicies.addedGroupPolicies.push(groupPolicy);\n }\n }\n\n await this.migrateLegacyMetadata(tempEnforcer);\n\n // We pass current here because this is during initialization and it has not changed yet\n await this.updatePolicies(content, tempEnforcer);\n\n if (this.allowReload) {\n this.watchFile();\n }\n }\n\n // Check for policies that might need to be updated\n // This will involve update \"legacy\" source in the role metadata if it exist in both the\n // temp enforcer (csv file) and a role metadata storage.\n // We will update role metadata with the new source \"csv-file\"\n private async migrateLegacyMetadata(tempEnforcer: Enforcer) {\n let legacyRolesMetadata = await this.roleMetadataStorage.filterRoleMetadata(\n 'legacy',\n );\n const legacyRoles = legacyRolesMetadata.map(meta => meta.roleEntityRef);\n if (legacyRoles.length > 0) {\n const legacyGroupPolicies = await tempEnforcer.getFilteredGroupingPolicy(\n 1,\n ...legacyRoles,\n );\n const legacyPolicies = await tempEnforcer.getFilteredPolicy(\n 0,\n ...legacyRoles,\n );\n const legacyRolesFromFile = new Set([\n ...legacyGroupPolicies.map(gp => gp[1]),\n ...legacyPolicies.map(p => p[0]),\n ]);\n legacyRolesMetadata = legacyRolesMetadata.filter(meta =>\n legacyRolesFromFile.has(meta.roleEntityRef),\n );\n for (const legacyRoleMeta of legacyRolesMetadata) {\n const nonLegacyRole = mergeRoleMetadata(legacyRoleMeta, {\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n source: 'csv-file',\n roleEntityRef: legacyRoleMeta.roleEntityRef,\n });\n await this.roleMetadataStorage.updateRoleMetadata(\n nonLegacyRole,\n legacyRoleMeta.roleEntityRef,\n );\n }\n }\n }\n\n /**\n * onChange is called whenever there is a change to the CSV file.\n * It will parse the current and new contents of the CSV file and process the roles and permission policies present.\n * Afterwards, it will find the difference between the current and new contents of the CSV file\n * and sort them into added / removed, permission policies / roles.\n * It will finally call updatePolicies with the new content.\n */\n async onChange(): Promise<void> {\n const newContent = this.parse();\n\n const tempEnforcer = await newEnforcer(\n newModelFromString(MODEL),\n new FileAdapter(this.filePath!),\n );\n\n const currentFlatContent = this.currentContent.flatMap(data => {\n return policyToString(data);\n });\n const newFlatContent = newContent.flatMap(data => {\n return policyToString(data);\n });\n\n const diffRemoved = difference(currentFlatContent, newFlatContent); // policy was removed\n const diffAdded = difference(newFlatContent, currentFlatContent); // policy was added\n\n await this.migrateLegacyMetadata(tempEnforcer);\n\n if (diffRemoved.length === 0 && diffAdded.length === 0) {\n return;\n }\n\n diffRemoved.forEach(policy => {\n const convertedPolicy = metadataStringToPolicy(policy);\n if (convertedPolicy[0] === 'p') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.removedPolicies.push(convertedPolicy);\n } else if (convertedPolicy[0] === 'g') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.removedGroupPolicies.push(convertedPolicy);\n }\n });\n\n diffAdded.forEach(policy => {\n const convertedPolicy = metadataStringToPolicy(policy);\n if (convertedPolicy[0] === 'p') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.addedPolicies.push(convertedPolicy);\n } else if (convertedPolicy[0] === 'g') {\n convertedPolicy.splice(0, 1);\n this.csvFilePolicies.addedGroupPolicies.push(convertedPolicy);\n }\n });\n\n await this.updatePolicies(newContent, tempEnforcer);\n }\n\n /**\n * updatePolicies is used to update all of the permission policies and roles within a CSV file.\n * It will check the number of added and removed permissions policies and roles and call the appropriate\n * methods for these.\n * It will also update the current contents of the CSV file to the most recent\n * @param newContent The new content present in the CSV file\n * @param tempEnforcer Temporary enforcer for checking for duplicates when adding policies\n */\n private async updatePolicies(\n newContent: string[][],\n tempEnforcer: Enforcer,\n ): Promise<void> {\n this.currentContent = newContent;\n\n if (this.csvFilePolicies.addedPolicies.length > 0)\n await this.addPermissionPolicies(tempEnforcer);\n if (this.csvFilePolicies.removedPolicies.length > 0)\n await this.removePermissionPolicies();\n if (this.csvFilePolicies.addedGroupPolicies.length > 0)\n await this.addRoles(tempEnforcer);\n if (this.csvFilePolicies.removedGroupPolicies.length > 0)\n await this.removeRoles();\n }\n\n /**\n * addPermissionPolicies will add the new permission policies that are present in the CSV file.\n * We will attempt to validate the permission policy and log any warnings that are encountered.\n * If a warning is encountered, we will skip adding the permission policy to the enforcer.\n * @param tempEnforcer Temporary enforcer for checking for duplicates when adding policies\n */\n private async addPermissionPolicies(tempEnforcer: Enforcer): Promise<void> {\n for (const policy of this.csvFilePolicies.addedPolicies) {\n const transformedPolicy = transformArrayToPolicy(policy);\n const metadata = await this.roleMetadataStorage.findRoleMetadata(\n policy[0],\n );\n\n let err = validatePolicy(transformedPolicy);\n if (err) {\n this.logger.warn(\n `Failed to validate policy from file ${this.filePath}. Cause: ${err.message}`,\n );\n continue;\n }\n\n err = await validateSource('csv-file', metadata);\n if (err) {\n this.logger.warn(\n `Unable to add policy ${policy} from file ${this.filePath}. Cause: ${err.message}`,\n );\n continue;\n }\n\n err = await checkForDuplicatePolicies(\n tempEnforcer,\n policy,\n this.filePath!,\n );\n if (err) {\n this.logger.warn(err.message);\n continue;\n }\n try {\n await this.enforcer.addPolicy(policy);\n\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Created policy`,\n eventName: PermissionEvents.CREATE_POLICY,\n metadata: { policies: [policy], source: 'csv-file' },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to add or update policy ${policy} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n }\n\n this.csvFilePolicies.addedPolicies = [];\n }\n\n /**\n * removePermissionPolicies will remove the permission policies that are no longer present in the CSV file.\n */\n private async removePermissionPolicies(): Promise<void> {\n try {\n await this.enforcer.removePolicies(this.csvFilePolicies.removedPolicies);\n\n await this.auditLogger.auditLog<PermissionAuditInfo>({\n actorId: RBAC_BACKEND,\n message: `Deleted policies`,\n eventName: PermissionEvents.DELETE_POLICY,\n metadata: {\n policies: this.csvFilePolicies.removedPolicies,\n source: 'csv-file',\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to remove policies ${JSON.stringify(\n this.csvFilePolicies.removedPolicies,\n )} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n this.csvFilePolicies.removedPolicies = [];\n }\n\n /**\n * addRoles will add the new roles that are present in the CSV file.\n * We will attempt to validate the role and log any warnings that are encountered.\n * If a warning is encountered, we will skip adding the role to the enforcer.\n * @param tempEnforcer Temporary enforcer for checking for duplicates when adding policies\n */\n private async addRoles(tempEnforcer: Enforcer): Promise<void> {\n for (const groupPolicy of this.csvFilePolicies.addedGroupPolicies) {\n let err = await validateGroupingPolicy(\n groupPolicy,\n this.roleMetadataStorage,\n 'csv-file',\n );\n if (err) {\n this.logger.warn(\n `${err.message}, error originates from file ${this.filePath}`,\n );\n continue;\n }\n\n err = await checkForDuplicateGroupPolicies(\n tempEnforcer,\n groupPolicy,\n this.filePath!,\n );\n if (err) {\n this.logger.warn(err.message);\n continue;\n }\n\n try {\n const roleMetadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef: groupPolicy[1],\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n\n const currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n roleMetadata.roleEntityRef,\n );\n\n await this.enforcer.addGroupingPolicy(groupPolicy, roleMetadata);\n\n const eventName = currentMetadata\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.CREATE_ROLE;\n const message = currentMetadata ? 'Updated role' : 'Created role';\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...roleMetadata, members: [groupPolicy[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to add or update group policy ${groupPolicy} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n }\n this.csvFilePolicies.addedGroupPolicies = [];\n }\n\n /**\n * removeRoles will remove the roles that are no longer present in the CSV file.\n * If the role exists with multiple groups and or users, we will update it role information.\n * Otherwise, we will remove the role completely.\n */\n private async removeRoles(): Promise<void> {\n for (const groupPolicy of this.csvFilePolicies.removedGroupPolicies) {\n const roleEntityRef = groupPolicy[1];\n // this requires knowledge of whether or not it is an update\n const isUpdate = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n roleEntityRef,\n );\n\n // Need to update the time\n try {\n const metadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef,\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n\n await this.enforcer.removeGroupingPolicy(\n groupPolicy,\n metadata,\n isUpdate.length > 1,\n );\n\n const isRolePresent = await this.roleMetadataStorage.findRoleMetadata(\n roleEntityRef,\n );\n const eventName = isRolePresent\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.DELETE_ROLE;\n const message = isRolePresent\n ? 'Updated role: deleted members'\n : 'Deleted role';\n await this.auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: { ...metadata, members: [groupPolicy[0]] },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n } catch (e) {\n this.logger.warn(\n `Failed to remove group policy ${groupPolicy} after modification ${this.filePath}. Cause: ${e}`,\n );\n }\n }\n this.csvFilePolicies.removedGroupPolicies = [];\n }\n\n async cleanUpRolesAndPolicies(): Promise<void> {\n const roleMetadatas = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const fileRoles = roleMetadatas.map(meta => meta.roleEntityRef);\n\n if (fileRoles.length > 0) {\n for (const fileRole of fileRoles) {\n this.csvFilePolicies.removedGroupPolicies.push(\n ...(await this.enforcer.getFilteredGroupingPolicy(1, fileRole)),\n );\n this.csvFilePolicies.removedPolicies.push(\n ...(await this.enforcer.getFilteredPolicy(0, fileRole)),\n );\n }\n }\n await this.removePermissionPolicies();\n await this.removeRoles();\n }\n}\n"],"names":["AbstractFileWatcher","parse","newEnforcer","newModelFromString","MODEL","FileAdapter","mergeRoleMetadata","policyToString","difference","metadataStringToPolicy","transformArrayToPolicy","validatePolicy","validateSource","checkForDuplicatePolicies","RBAC_BACKEND","PermissionEvents","HANDLE_RBAC_DATA_STAGE","validateGroupingPolicy","checkForDuplicateGroupPolicies","RoleEvents"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-watcher.cjs.js","sources":["../../src/file-permissions/file-watcher.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 chokidar from 'chokidar';\n\nimport fs from 'fs';\n\n/**\n * Represents a file watcher that can be used to monitor changes in a file.\n */\nexport abstract class AbstractFileWatcher<T> {\n constructor(\n protected readonly filePath: string | undefined,\n protected readonly allowReload: boolean,\n protected readonly logger: LoggerService,\n ) {}\n\n /**\n * Initializes the file watcher and starts watching the specified file.\n */\n abstract initialize(): Promise<void>;\n\n /**\n * watchFile initializes the file watcher and sets it to begin watching for changes.\n */\n watchFile(): void {\n if (!this.filePath) {\n throw new Error('File path is not specified');\n }\n const watcher = chokidar.watch(this.filePath);\n watcher.on('change', async path => {\n this.logger.info(`file ${path} has changed`);\n await this.onChange();\n });\n watcher.on('error', error => {\n this.logger.error(`error watching file ${this.filePath}: ${error}`);\n });\n }\n\n /**\n * Handles the change event when the watched file is modified.\n * @returns A promise that resolves when the change event is handled.\n */\n abstract onChange(): Promise<void>;\n\n /**\n * getCurrentContents reads the current contents of the CSV file.\n * @returns The current contents of the file.\n */\n getCurrentContents(): string {\n if (!this.filePath) {\n throw new Error('File path is not specified');\n }\n return fs.readFileSync(this.filePath, 'utf-8');\n }\n\n /**\n * parse is used to parse the current contents of the file.\n * @returns The file parsed into a type <T>.\n */\n abstract parse(): T;\n}\n"],"names":["chokidar","fs"],"mappings":";;;;;;;;;;AAwBO,MAAe,mBAAuB,CAAA;AAAA,EAC3C,WAAA,CACqB,QACA,EAAA,WAAA,EACA,MACnB,EAAA;AAHmB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA
|
|
1
|
+
{"version":3,"file":"file-watcher.cjs.js","sources":["../../src/file-permissions/file-watcher.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 chokidar from 'chokidar';\n\nimport fs from 'fs';\n\n/**\n * Represents a file watcher that can be used to monitor changes in a file.\n */\nexport abstract class AbstractFileWatcher<T> {\n constructor(\n protected readonly filePath: string | undefined,\n protected readonly allowReload: boolean,\n protected readonly logger: LoggerService,\n ) {}\n\n /**\n * Initializes the file watcher and starts watching the specified file.\n */\n abstract initialize(): Promise<void>;\n\n /**\n * watchFile initializes the file watcher and sets it to begin watching for changes.\n */\n watchFile(): void {\n if (!this.filePath) {\n throw new Error('File path is not specified');\n }\n const watcher = chokidar.watch(this.filePath);\n watcher.on('change', async path => {\n this.logger.info(`file ${path} has changed`);\n await this.onChange();\n });\n watcher.on('error', error => {\n this.logger.error(`error watching file ${this.filePath}: ${error}`);\n });\n }\n\n /**\n * Handles the change event when the watched file is modified.\n * @returns A promise that resolves when the change event is handled.\n */\n abstract onChange(): Promise<void>;\n\n /**\n * getCurrentContents reads the current contents of the CSV file.\n * @returns The current contents of the file.\n */\n getCurrentContents(): string {\n if (!this.filePath) {\n throw new Error('File path is not specified');\n }\n return fs.readFileSync(this.filePath, 'utf-8');\n }\n\n /**\n * parse is used to parse the current contents of the file.\n * @returns The file parsed into a type <T>.\n */\n abstract parse(): T;\n}\n"],"names":["chokidar","fs"],"mappings":";;;;;;;;;;AAwBO,MAAe,mBAAuB,CAAA;AAAA,EAC3C,WAAA,CACqB,QACA,EAAA,WAAA,EACA,MACnB,EAAA;AAHmB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAClB;AAAA;AAAA;AAAA,EAUH,SAAkB,GAAA;AAChB,IAAI,IAAA,CAAC,KAAK,QAAU,EAAA;AAClB,MAAM,MAAA,IAAI,MAAM,4BAA4B,CAAA;AAAA;AAE9C,IAAA,MAAM,OAAU,GAAAA,yBAAA,CAAS,KAAM,CAAA,IAAA,CAAK,QAAQ,CAAA;AAC5C,IAAQ,OAAA,CAAA,EAAA,CAAG,QAAU,EAAA,OAAM,IAAQ,KAAA;AACjC,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAQ,KAAA,EAAA,IAAI,CAAc,YAAA,CAAA,CAAA;AAC3C,MAAA,MAAM,KAAK,QAAS,EAAA;AAAA,KACrB,CAAA;AACD,IAAQ,OAAA,CAAA,EAAA,CAAG,SAAS,CAAS,KAAA,KAAA;AAC3B,MAAA,IAAA,CAAK,OAAO,KAAM,CAAA,CAAA,oBAAA,EAAuB,KAAK,QAAQ,CAAA,EAAA,EAAK,KAAK,CAAE,CAAA,CAAA;AAAA,KACnE,CAAA;AAAA;AACH;AAAA;AAAA;AAAA;AAAA,EAYA,kBAA6B,GAAA;AAC3B,IAAI,IAAA,CAAC,KAAK,QAAU,EAAA;AAClB,MAAM,MAAA,IAAI,MAAM,4BAA4B,CAAA;AAAA;AAE9C,IAAA,OAAOC,mBAAG,CAAA,YAAA,CAAa,IAAK,CAAA,QAAA,EAAU,OAAO,CAAA;AAAA;AAQjD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-conditional-file-watcher.cjs.js","sources":["../../src/file-permissions/yaml-conditional-file-watcher.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 { AuthService, LoggerService } from '@backstage/backend-plugin-api';\n\nimport type { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport yaml from 'js-yaml';\nimport { omit } from 'lodash';\n\nimport type {\n PermissionAction,\n RoleConditionalPolicyDecision,\n} from '@backstage-community/plugin-rbac-common';\n\nimport fs from 'fs';\n\nimport {\n ConditionAuditInfo,\n ConditionEvents,\n HANDLE_RBAC_DATA_STAGE,\n} from '../audit-log/audit-logger';\nimport { ConditionalStorage } from '../database/conditional-storage';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { deepSortEqual, processConditionMapping } from '../helper';\nimport { RoleEventEmitter, RoleEvents } from '../service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from '../service/plugin-endpoints';\nimport { validateRoleCondition } from '../validation/condition-validation';\nimport { AbstractFileWatcher } from './file-watcher';\n\ntype ConditionalPoliciesDiff = {\n addedConditions: RoleConditionalPolicyDecision<PermissionAction>[];\n removedConditions: RoleConditionalPolicyDecision<PermissionAction>[];\n};\n\nexport class YamlConditinalPoliciesFileWatcher extends AbstractFileWatcher<\n RoleConditionalPolicyDecision<PermissionAction>[]\n> {\n private conditionsDiff: ConditionalPoliciesDiff;\n\n constructor(\n filePath: string | undefined,\n allowReload: boolean,\n logger: LoggerService,\n private readonly conditionalStorage: ConditionalStorage,\n private readonly auditLogger: AuditLogger,\n private readonly auth: AuthService,\n private readonly pluginMetadataCollector: PluginPermissionMetadataCollector,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly roleEventEmitter: RoleEventEmitter<RoleEvents>,\n ) {\n super(filePath, allowReload, logger);\n\n this.conditionsDiff = {\n addedConditions: [],\n removedConditions: [],\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.filePath) {\n return;\n }\n const fileExists = fs.existsSync(this.filePath);\n if (!fileExists) {\n const err = new Error(`File '${this.filePath}' was not found`);\n this.handleError(\n err.message,\n err,\n ConditionEvents.CONDITIONAL_POLICIES_FILE_NOT_FOUND,\n );\n return;\n }\n\n this.roleEventEmitter.on('roleAdded', this.onChange.bind(this));\n await this.onChange();\n\n if (this.allowReload) {\n this.watchFile();\n }\n }\n\n async onChange(): Promise<void> {\n try {\n const newConds = this.parse().filter(c => c);\n\n const addedConds: RoleConditionalPolicyDecision<PermissionAction>[] = [];\n const removedConds: RoleConditionalPolicyDecision<PermissionAction>[] =\n [];\n\n const csvFileRoles = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const existedFileConds = (\n await this.conditionalStorage.filterConditions(\n csvFileRoles.map(role => role.roleEntityRef),\n )\n ).map(condition => {\n return {\n ...condition,\n permissionMapping: condition.permissionMapping.map(pm => pm.action),\n };\n });\n\n // Find added conditions\n for (const condition of newConds) {\n const roleMetadata = csvFileRoles.find(\n role => condition.roleEntityRef === role.roleEntityRef,\n );\n if (!roleMetadata) {\n this.logger.warn(\n `skip to add condition for role '${condition.roleEntityRef}'. The role either does not exist or was not created from a CSV file.`,\n );\n continue;\n }\n if (roleMetadata.source !== 'csv-file') {\n this.logger.warn(\n `skip to add condition for role '${condition.roleEntityRef}'. Role is not from csv-file`,\n );\n continue;\n }\n\n const existingCondition = existedFileConds.find(c =>\n deepSortEqual(omit(c, ['id']), omit(condition, ['id'])),\n );\n\n if (!existingCondition) {\n addedConds.push(condition);\n }\n }\n\n // Find removed conditions\n for (const condition of existedFileConds) {\n if (\n !newConds.find(c =>\n deepSortEqual(omit(c, ['id']), omit(condition, ['id'])),\n )\n ) {\n removedConds.push(condition);\n }\n }\n\n this.conditionsDiff = {\n addedConditions: addedConds,\n removedConditions: removedConds,\n };\n\n await this.handleFileChanges();\n } catch (error) {\n await this.handleError(\n `Error handling changes from conditional policies file ${this.filePath}`,\n error,\n ConditionEvents.CHANGE_CONDITIONAL_POLICIES_FILE_ERROR,\n );\n }\n }\n\n /**\n * Reads the current contents of the file and parses it.\n * @returns parsed data.\n */\n parse(): RoleConditionalPolicyDecision<PermissionAction>[] {\n const fileContents = this.getCurrentContents();\n const data = yaml.loadAll(\n fileContents,\n ) as RoleConditionalPolicyDecision<PermissionAction>[];\n\n for (const condition of data) {\n validateRoleCondition(condition);\n }\n\n return data;\n }\n\n private async handleFileChanges(): Promise<void> {\n await this.removeConditions();\n await this.addConditions();\n }\n\n private async addConditions(): Promise<void> {\n try {\n for (const condition of this.conditionsDiff.addedConditions) {\n const conditionToCreate = await processConditionMapping(\n condition,\n this.pluginMetadataCollector,\n this.auth,\n );\n\n await this.conditionalStorage.createCondition(conditionToCreate);\n\n await this.auditLogger.auditLog<ConditionAuditInfo>({\n message: `Created conditional permission policy`,\n eventName: ConditionEvents.CREATE_CONDITION,\n metadata: { condition },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n } catch (error) {\n await this.handleError(\n 'Failed to create condition',\n error,\n ConditionEvents.CREATE_CONDITION_ERROR,\n );\n }\n this.conditionsDiff.addedConditions = [];\n }\n\n private async removeConditions(): Promise<void> {\n try {\n for (const condition of this.conditionsDiff.removedConditions) {\n const conditionToDelete = (\n await this.conditionalStorage.filterConditions(\n condition.roleEntityRef,\n condition.pluginId,\n condition.resourceType,\n condition.permissionMapping,\n )\n )[0];\n await this.conditionalStorage.deleteCondition(conditionToDelete.id!);\n\n await this.auditLogger.auditLog<ConditionAuditInfo>({\n message: `Deleted conditional permission policy`,\n eventName: ConditionEvents.DELETE_CONDITION,\n metadata: { condition },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n } catch (error) {\n await this.handleError(\n 'Failed to delete condition by id',\n error,\n ConditionEvents.DELETE_CONDITION_ERROR,\n );\n }\n\n this.conditionsDiff.removedConditions = [];\n }\n\n private async handleError(\n message: string,\n error: unknown,\n event: string,\n ): Promise<void> {\n await this.auditLogger.auditLog({\n message,\n eventName: event,\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'failed',\n errors: [error],\n });\n }\n\n async cleanUpConditionalPolicies(): Promise<void> {\n const csvFileRoles = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const existedFileConds = (\n await this.conditionalStorage.filterConditions(\n csvFileRoles.map(role => role.roleEntityRef),\n )\n ).map(condition => {\n return {\n ...condition,\n permissionMapping: condition.permissionMapping.map(pm => pm.action),\n };\n });\n this.conditionsDiff.removedConditions = existedFileConds;\n await this.removeConditions();\n }\n}\n"],"names":["AbstractFileWatcher","fs","ConditionEvents","deepSortEqual","omit","yaml","validateRoleCondition","processConditionMapping","HANDLE_RBAC_DATA_STAGE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yaml-conditional-file-watcher.cjs.js","sources":["../../src/file-permissions/yaml-conditional-file-watcher.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 { AuthService, LoggerService } from '@backstage/backend-plugin-api';\n\nimport type { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport yaml from 'js-yaml';\nimport { omit } from 'lodash';\n\nimport type {\n PermissionAction,\n RoleConditionalPolicyDecision,\n} from '@backstage-community/plugin-rbac-common';\n\nimport fs from 'fs';\n\nimport {\n ConditionAuditInfo,\n ConditionEvents,\n HANDLE_RBAC_DATA_STAGE,\n} from '../audit-log/audit-logger';\nimport { ConditionalStorage } from '../database/conditional-storage';\nimport { RoleMetadataStorage } from '../database/role-metadata';\nimport { deepSortEqual, processConditionMapping } from '../helper';\nimport { RoleEventEmitter, RoleEvents } from '../service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from '../service/plugin-endpoints';\nimport { validateRoleCondition } from '../validation/condition-validation';\nimport { AbstractFileWatcher } from './file-watcher';\n\ntype ConditionalPoliciesDiff = {\n addedConditions: RoleConditionalPolicyDecision<PermissionAction>[];\n removedConditions: RoleConditionalPolicyDecision<PermissionAction>[];\n};\n\nexport class YamlConditinalPoliciesFileWatcher extends AbstractFileWatcher<\n RoleConditionalPolicyDecision<PermissionAction>[]\n> {\n private conditionsDiff: ConditionalPoliciesDiff;\n\n constructor(\n filePath: string | undefined,\n allowReload: boolean,\n logger: LoggerService,\n private readonly conditionalStorage: ConditionalStorage,\n private readonly auditLogger: AuditLogger,\n private readonly auth: AuthService,\n private readonly pluginMetadataCollector: PluginPermissionMetadataCollector,\n private readonly roleMetadataStorage: RoleMetadataStorage,\n private readonly roleEventEmitter: RoleEventEmitter<RoleEvents>,\n ) {\n super(filePath, allowReload, logger);\n\n this.conditionsDiff = {\n addedConditions: [],\n removedConditions: [],\n };\n }\n\n async initialize(): Promise<void> {\n if (!this.filePath) {\n return;\n }\n const fileExists = fs.existsSync(this.filePath);\n if (!fileExists) {\n const err = new Error(`File '${this.filePath}' was not found`);\n this.handleError(\n err.message,\n err,\n ConditionEvents.CONDITIONAL_POLICIES_FILE_NOT_FOUND,\n );\n return;\n }\n\n this.roleEventEmitter.on('roleAdded', this.onChange.bind(this));\n await this.onChange();\n\n if (this.allowReload) {\n this.watchFile();\n }\n }\n\n async onChange(): Promise<void> {\n try {\n const newConds = this.parse().filter(c => c);\n\n const addedConds: RoleConditionalPolicyDecision<PermissionAction>[] = [];\n const removedConds: RoleConditionalPolicyDecision<PermissionAction>[] =\n [];\n\n const csvFileRoles = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const existedFileConds = (\n await this.conditionalStorage.filterConditions(\n csvFileRoles.map(role => role.roleEntityRef),\n )\n ).map(condition => {\n return {\n ...condition,\n permissionMapping: condition.permissionMapping.map(pm => pm.action),\n };\n });\n\n // Find added conditions\n for (const condition of newConds) {\n const roleMetadata = csvFileRoles.find(\n role => condition.roleEntityRef === role.roleEntityRef,\n );\n if (!roleMetadata) {\n this.logger.warn(\n `skip to add condition for role '${condition.roleEntityRef}'. The role either does not exist or was not created from a CSV file.`,\n );\n continue;\n }\n if (roleMetadata.source !== 'csv-file') {\n this.logger.warn(\n `skip to add condition for role '${condition.roleEntityRef}'. Role is not from csv-file`,\n );\n continue;\n }\n\n const existingCondition = existedFileConds.find(c =>\n deepSortEqual(omit(c, ['id']), omit(condition, ['id'])),\n );\n\n if (!existingCondition) {\n addedConds.push(condition);\n }\n }\n\n // Find removed conditions\n for (const condition of existedFileConds) {\n if (\n !newConds.find(c =>\n deepSortEqual(omit(c, ['id']), omit(condition, ['id'])),\n )\n ) {\n removedConds.push(condition);\n }\n }\n\n this.conditionsDiff = {\n addedConditions: addedConds,\n removedConditions: removedConds,\n };\n\n await this.handleFileChanges();\n } catch (error) {\n await this.handleError(\n `Error handling changes from conditional policies file ${this.filePath}`,\n error,\n ConditionEvents.CHANGE_CONDITIONAL_POLICIES_FILE_ERROR,\n );\n }\n }\n\n /**\n * Reads the current contents of the file and parses it.\n * @returns parsed data.\n */\n parse(): RoleConditionalPolicyDecision<PermissionAction>[] {\n const fileContents = this.getCurrentContents();\n const data = yaml.loadAll(\n fileContents,\n ) as RoleConditionalPolicyDecision<PermissionAction>[];\n\n for (const condition of data) {\n validateRoleCondition(condition);\n }\n\n return data;\n }\n\n private async handleFileChanges(): Promise<void> {\n await this.removeConditions();\n await this.addConditions();\n }\n\n private async addConditions(): Promise<void> {\n try {\n for (const condition of this.conditionsDiff.addedConditions) {\n const conditionToCreate = await processConditionMapping(\n condition,\n this.pluginMetadataCollector,\n this.auth,\n );\n\n await this.conditionalStorage.createCondition(conditionToCreate);\n\n await this.auditLogger.auditLog<ConditionAuditInfo>({\n message: `Created conditional permission policy`,\n eventName: ConditionEvents.CREATE_CONDITION,\n metadata: { condition },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n } catch (error) {\n await this.handleError(\n 'Failed to create condition',\n error,\n ConditionEvents.CREATE_CONDITION_ERROR,\n );\n }\n this.conditionsDiff.addedConditions = [];\n }\n\n private async removeConditions(): Promise<void> {\n try {\n for (const condition of this.conditionsDiff.removedConditions) {\n const conditionToDelete = (\n await this.conditionalStorage.filterConditions(\n condition.roleEntityRef,\n condition.pluginId,\n condition.resourceType,\n condition.permissionMapping,\n )\n )[0];\n await this.conditionalStorage.deleteCondition(conditionToDelete.id!);\n\n await this.auditLogger.auditLog<ConditionAuditInfo>({\n message: `Deleted conditional permission policy`,\n eventName: ConditionEvents.DELETE_CONDITION,\n metadata: { condition },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n }\n } catch (error) {\n await this.handleError(\n 'Failed to delete condition by id',\n error,\n ConditionEvents.DELETE_CONDITION_ERROR,\n );\n }\n\n this.conditionsDiff.removedConditions = [];\n }\n\n private async handleError(\n message: string,\n error: unknown,\n event: string,\n ): Promise<void> {\n await this.auditLogger.auditLog({\n message,\n eventName: event,\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'failed',\n errors: [error],\n });\n }\n\n async cleanUpConditionalPolicies(): Promise<void> {\n const csvFileRoles = await this.roleMetadataStorage.filterRoleMetadata(\n 'csv-file',\n );\n const existedFileConds = (\n await this.conditionalStorage.filterConditions(\n csvFileRoles.map(role => role.roleEntityRef),\n )\n ).map(condition => {\n return {\n ...condition,\n permissionMapping: condition.permissionMapping.map(pm => pm.action),\n };\n });\n this.conditionsDiff.removedConditions = existedFileConds;\n await this.removeConditions();\n }\n}\n"],"names":["AbstractFileWatcher","fs","ConditionEvents","deepSortEqual","omit","yaml","validateRoleCondition","processConditionMapping","HANDLE_RBAC_DATA_STAGE"],"mappings":"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"}
|