@backstage-community/plugin-rbac-backend 5.2.9 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/admin-permissions/admin-creation.cjs.js +1 -1
- package/dist/admin-permissions/admin-creation.cjs.js.map +1 -1
- package/dist/audit-log/audit-logger.cjs.js +6 -0
- package/dist/audit-log/audit-logger.cjs.js.map +1 -1
- package/dist/database/casbin-adapter-factory.cjs.js +2 -1
- package/dist/database/casbin-adapter-factory.cjs.js.map +1 -1
- package/dist/file-permissions/csv-file-watcher.cjs.js +8 -4
- package/dist/file-permissions/csv-file-watcher.cjs.js.map +1 -1
- package/dist/file-permissions/lowercase-file-adapter.cjs.js +36 -0
- package/dist/file-permissions/lowercase-file-adapter.cjs.js.map +1 -0
- package/dist/helper.cjs.js +12 -0
- package/dist/helper.cjs.js.map +1 -1
- package/dist/policies/permission-policy.cjs.js +1 -0
- package/dist/policies/permission-policy.cjs.js.map +1 -1
- package/dist/providers/connect-providers.cjs.js +7 -3
- package/dist/providers/connect-providers.cjs.js.map +1 -1
- package/dist/service/enforcer-delegate.cjs.js +312 -203
- package/dist/service/enforcer-delegate.cjs.js.map +1 -1
- package/dist/service/policies-rest-api.cjs.js +9 -1
- package/dist/service/policies-rest-api.cjs.js.map +1 -1
- package/dist/service/policy-builder.cjs.js +6 -5
- package/dist/service/policy-builder.cjs.js.map +1 -1
- package/migrations/20241108093910_migrations.js +35 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
### Dependencies
|
|
2
2
|
|
|
3
|
+
## 5.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 53daff0: Roles and permissions were not correctly applied for users and groups with names containing uppercase letters. To address this issue, we now convert user and group references in all user inputs to lowercase. This change migrates `v0` column in `casbin_rule` table in `backstage_plugin_permission` database. Conditions containing claims with uppercase letters are not resolved yet.
|
|
8
|
+
|
|
9
|
+
## 5.2.10
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- ba4b3e9: Use loadPolicy to keep the enforcer in sync for edit operations. It should keep the RBAC plugin in sync when the Backstage instance is scaled to multiple deployment replicas. Reuse the maximum database pool size value from the application configuration in the RBAC Casbin adapter.
|
|
14
|
+
|
|
3
15
|
## 5.2.9
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -23,7 +23,7 @@ const useAdminsFromConfig = async (admins, enf, auditLogger$1, roleMetadataStora
|
|
|
23
23
|
const addedGroupPolicies = /* @__PURE__ */ new Map();
|
|
24
24
|
const newGroupPolicies = /* @__PURE__ */ new Map();
|
|
25
25
|
for (const admin of admins) {
|
|
26
|
-
const entityRef = admin.getString("name");
|
|
26
|
+
const entityRef = admin.getString("name").toLocaleLowerCase("en-US");
|
|
27
27
|
policiesValidation.validateEntityReference(entityRef);
|
|
28
28
|
addedGroupPolicies.set(entityRef, ADMIN_ROLE_NAME);
|
|
29
29
|
if (!await enf.hasGroupingPolicy(...[entityRef, ADMIN_ROLE_NAME])) {
|
|
@@ -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 =\n await roleMetadataStorage.findRoleMetadata(ADMIN_ROLE_NAME);\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;AACxB,MAAM,iBAAoB,GAAA;AACjC,MAAM,0BACJ,GAAA,6IAAA;AAEF,MAAM,uBAAuB,MAAuB;AAClD,EAAM,MAAA,WAAA,uBAAwB,IAAK,EAAA;AACnC,EAAO,OAAA;AAAA,IACL,MAAQ,EAAA,eAAA;AAAA,IACR,aAAe,EAAA,eAAA;AAAA,IACf,WAAa,EAAA,0BAAA;AAAA,IACb,MAAQ,EAAA,iBAAA;AAAA,IACR,UAAY,EAAA,iBAAA;AAAA,IACZ,YAAA,EAAc,YAAY,WAAY,EAAA;AAAA,IACtC,SAAA,EAAW,YAAY,WAAY;AAAA,GACrC;AACF,CAAA;AAEO,MAAM,sBAAsB,OACjC,MAAA,EACA,GACA,EAAAA,aAAA,EACA,qBACA,IACG,KAAA;AACH,EAAM,MAAA,kBAAA,uBAAyB,GAAoB,EAAA;AACnD,EAAM,MAAA,gBAAA,uBAAuB,GAAoB,EAAA;AAEjD,EAAA,KAAA,MAAW,SAAS,MAAQ,EAAA;AAC1B,
|
|
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').toLocaleLowerCase('en-US');\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 =\n await roleMetadataStorage.findRoleMetadata(ADMIN_ROLE_NAME);\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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"}
|
|
@@ -38,6 +38,9 @@ const ListConditionEvents = {
|
|
|
38
38
|
GET_CONDITION_RULES: "GetConditionRules",
|
|
39
39
|
GET_CONDITION_RULES_ERROR: "GetConditionRulesError"
|
|
40
40
|
};
|
|
41
|
+
const PoliciesData = {
|
|
42
|
+
FAILED_TO_FETCH_NEWER_PERMISSIONS: "FailedToFetchNewerPermissions"
|
|
43
|
+
};
|
|
41
44
|
const ConditionEvents = {
|
|
42
45
|
CREATE_CONDITION: "CreateCondition",
|
|
43
46
|
UPDATE_CONDITION: "UpdateCondition",
|
|
@@ -53,6 +56,7 @@ const ConditionEvents = {
|
|
|
53
56
|
};
|
|
54
57
|
const RBAC_BACKEND = "rbac-backend";
|
|
55
58
|
const HANDLE_RBAC_DATA_STAGE = "handleRBACData";
|
|
59
|
+
const FETCH_NEWER_PERMISSIONS_STAGE = "fetchNewerPermissions";
|
|
56
60
|
const EVALUATE_PERMISSION_ACCESS_STAGE = "evaluatePermissionAccess";
|
|
57
61
|
const SEND_RESPONSE_STAGE = "sendResponse";
|
|
58
62
|
const RESPONSE_ERROR = "responseError";
|
|
@@ -96,10 +100,12 @@ function createPermissionEvaluationOptions(message, userEntityRef, request, poli
|
|
|
96
100
|
exports.ConditionEvents = ConditionEvents;
|
|
97
101
|
exports.EVALUATE_PERMISSION_ACCESS_STAGE = EVALUATE_PERMISSION_ACCESS_STAGE;
|
|
98
102
|
exports.EvaluationEvents = EvaluationEvents;
|
|
103
|
+
exports.FETCH_NEWER_PERMISSIONS_STAGE = FETCH_NEWER_PERMISSIONS_STAGE;
|
|
99
104
|
exports.HANDLE_RBAC_DATA_STAGE = HANDLE_RBAC_DATA_STAGE;
|
|
100
105
|
exports.ListConditionEvents = ListConditionEvents;
|
|
101
106
|
exports.ListPluginPoliciesEvents = ListPluginPoliciesEvents;
|
|
102
107
|
exports.PermissionEvents = PermissionEvents;
|
|
108
|
+
exports.PoliciesData = PoliciesData;
|
|
103
109
|
exports.RBAC_BACKEND = RBAC_BACKEND;
|
|
104
110
|
exports.RESPONSE_ERROR = RESPONSE_ERROR;
|
|
105
111
|
exports.RoleEvents = RoleEvents;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-logger.cjs.js","sources":["../../src/audit-log/audit-logger.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n AuthorizeResult,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type { PolicyQuery } from '@backstage/plugin-permission-node';\n\nimport type { AuditLogOptions } from '@janus-idp/backstage-plugin-audit-log-node';\n\nimport {\n PermissionAction,\n RoleConditionalPolicyDecision,\n Source,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nexport const RoleEvents = {\n CREATE_ROLE: 'CreateRole',\n UPDATE_ROLE: 'UpdateRole',\n DELETE_ROLE: 'DeleteRole',\n CREATE_OR_UPDATE_ROLE: 'CreateOrUpdateRole',\n GET_ROLE: 'GetRole',\n\n CREATE_ROLE_ERROR: 'CreateRoleError',\n UPDATE_ROLE_ERROR: 'UpdateRoleError',\n DELETE_ROLE_ERROR: 'DeleteRoleError',\n GET_ROLE_ERROR: 'GetRoleError',\n} as const;\n\nexport const PermissionEvents = {\n CREATE_POLICY: 'CreatePolicy',\n UPDATE_POLICY: 'UpdatePolicy',\n DELETE_POLICY: 'DeletePolicy',\n GET_POLICY: 'GetPolicy',\n\n CREATE_POLICY_ERROR: 'CreatePolicyError',\n UPDATE_POLICY_ERROR: 'UpdatePolicyError',\n DELETE_POLICY_ERROR: 'DeletePolicyError',\n GET_POLICY_ERROR: 'GetPolicyError',\n} as const;\n\nexport type RoleAuditInfo = {\n roleEntityRef: string;\n description?: string;\n source: Source;\n\n members: string[];\n};\n\nexport type PermissionAuditInfo = {\n policies: string[][];\n source: Source;\n};\n\nexport const EvaluationEvents = {\n PERMISSION_EVALUATION_STARTED: 'PermissionEvaluationStarted',\n PERMISSION_EVALUATION_COMPLETED: 'PermissionEvaluationCompleted',\n CONDITION_EVALUATION_COMPLETED: 'ConditionEvaluationCompleted',\n PERMISSION_EVALUATION_FAILED: 'PermissionEvaluationFailed',\n} as const;\n\nexport const ListPluginPoliciesEvents = {\n GET_PLUGINS_POLICIES: 'GetPluginsPolicies',\n GET_PLUGINS_POLICIES_ERROR: 'GetPluginsPoliciesError',\n};\n\nexport const ListConditionEvents = {\n GET_CONDITION_RULES: 'GetConditionRules',\n GET_CONDITION_RULES_ERROR: 'GetConditionRulesError',\n};\n\nexport type EvaluationAuditInfo = {\n userEntityRef: string;\n permissionName: string;\n action: PermissionAction;\n resourceType?: string;\n decision?: PolicyDecision;\n};\n\nexport const ConditionEvents = {\n CREATE_CONDITION: 'CreateCondition',\n UPDATE_CONDITION: 'UpdateCondition',\n DELETE_CONDITION: 'DeleteCondition',\n GET_CONDITION: 'GetCondition',\n\n CREATE_CONDITION_ERROR: 'CreateConditionError',\n UPDATE_CONDITION_ERROR: 'UpdateConditionError',\n DELETE_CONDITION_ERROR: 'DeleteConditionError',\n GET_CONDITION_ERROR: 'GetConditionError',\n PARSE_CONDITION_ERROR: 'ParseConditionError',\n CHANGE_CONDITIONAL_POLICIES_FILE_ERROR: 'ChangeConditionalPoliciesError',\n CONDITIONAL_POLICIES_FILE_NOT_FOUND: 'ConditionalPoliciesFileNotFound',\n};\n\nexport type ConditionAuditInfo = {\n condition: RoleConditionalPolicyDecision<PermissionAction>;\n};\n\nexport const RBAC_BACKEND = 'rbac-backend';\n\n// Audit log stage for processing Role-Based Access Control (RBAC) data\nexport const HANDLE_RBAC_DATA_STAGE = 'handleRBACData';\n\n// Audit log stage for determining access rights based on user permissions and resource information\nexport const EVALUATE_PERMISSION_ACCESS_STAGE = 'evaluatePermissionAccess';\n\n// Audit log stage for sending the response to the client about handled permission policies, roles, and condition policies\nexport const SEND_RESPONSE_STAGE = 'sendResponse';\nexport const RESPONSE_ERROR = 'responseError';\n\nexport function createPermissionEvaluationOptions(\n message: string,\n userEntityRef: string,\n request: PolicyQuery,\n policyDecision?: PolicyDecision,\n): AuditLogOptions<EvaluationAuditInfo> {\n const auditInfo: EvaluationAuditInfo = {\n userEntityRef,\n permissionName: request.permission.name,\n action: toPermissionAction(request.permission.attributes),\n };\n\n const resourceType = (request.permission as ResourcePermission).resourceType;\n if (resourceType) {\n auditInfo.resourceType = resourceType;\n }\n\n let eventName;\n if (!policyDecision) {\n eventName = EvaluationEvents.PERMISSION_EVALUATION_STARTED;\n } else {\n auditInfo.decision = policyDecision;\n\n switch (policyDecision.result) {\n case AuthorizeResult.DENY:\n case AuthorizeResult.ALLOW:\n eventName = EvaluationEvents.PERMISSION_EVALUATION_COMPLETED;\n break;\n case AuthorizeResult.CONDITIONAL:\n eventName = EvaluationEvents.CONDITION_EVALUATION_COMPLETED;\n break;\n default:\n throw new Error('Unknown policy decision result');\n }\n }\n\n return {\n actorId: userEntityRef,\n message,\n eventName,\n metadata: auditInfo,\n stage: EVALUATE_PERMISSION_ACCESS_STAGE,\n status: 'succeeded',\n };\n}\n"],"names":["toPermissionAction","AuthorizeResult"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"audit-logger.cjs.js","sources":["../../src/audit-log/audit-logger.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n AuthorizeResult,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport type { PolicyQuery } from '@backstage/plugin-permission-node';\n\nimport type { AuditLogOptions } from '@janus-idp/backstage-plugin-audit-log-node';\n\nimport {\n PermissionAction,\n RoleConditionalPolicyDecision,\n Source,\n toPermissionAction,\n} from '@backstage-community/plugin-rbac-common';\n\nexport const RoleEvents = {\n CREATE_ROLE: 'CreateRole',\n UPDATE_ROLE: 'UpdateRole',\n DELETE_ROLE: 'DeleteRole',\n CREATE_OR_UPDATE_ROLE: 'CreateOrUpdateRole',\n GET_ROLE: 'GetRole',\n\n CREATE_ROLE_ERROR: 'CreateRoleError',\n UPDATE_ROLE_ERROR: 'UpdateRoleError',\n DELETE_ROLE_ERROR: 'DeleteRoleError',\n GET_ROLE_ERROR: 'GetRoleError',\n} as const;\n\nexport const PermissionEvents = {\n CREATE_POLICY: 'CreatePolicy',\n UPDATE_POLICY: 'UpdatePolicy',\n DELETE_POLICY: 'DeletePolicy',\n GET_POLICY: 'GetPolicy',\n\n CREATE_POLICY_ERROR: 'CreatePolicyError',\n UPDATE_POLICY_ERROR: 'UpdatePolicyError',\n DELETE_POLICY_ERROR: 'DeletePolicyError',\n GET_POLICY_ERROR: 'GetPolicyError',\n} as const;\n\nexport type RoleAuditInfo = {\n roleEntityRef: string;\n description?: string;\n source: Source;\n\n members: string[];\n};\n\nexport type PermissionAuditInfo = {\n policies: string[][];\n source: Source;\n};\n\nexport const EvaluationEvents = {\n PERMISSION_EVALUATION_STARTED: 'PermissionEvaluationStarted',\n PERMISSION_EVALUATION_COMPLETED: 'PermissionEvaluationCompleted',\n CONDITION_EVALUATION_COMPLETED: 'ConditionEvaluationCompleted',\n PERMISSION_EVALUATION_FAILED: 'PermissionEvaluationFailed',\n} as const;\n\nexport const ListPluginPoliciesEvents = {\n GET_PLUGINS_POLICIES: 'GetPluginsPolicies',\n GET_PLUGINS_POLICIES_ERROR: 'GetPluginsPoliciesError',\n};\n\nexport const ListConditionEvents = {\n GET_CONDITION_RULES: 'GetConditionRules',\n GET_CONDITION_RULES_ERROR: 'GetConditionRulesError',\n};\n\nexport type EvaluationAuditInfo = {\n userEntityRef: string;\n permissionName: string;\n action: PermissionAction;\n resourceType?: string;\n decision?: PolicyDecision;\n};\n\nexport const PoliciesData = {\n FAILED_TO_FETCH_NEWER_PERMISSIONS: 'FailedToFetchNewerPermissions',\n};\n\nexport const ConditionEvents = {\n CREATE_CONDITION: 'CreateCondition',\n UPDATE_CONDITION: 'UpdateCondition',\n DELETE_CONDITION: 'DeleteCondition',\n GET_CONDITION: 'GetCondition',\n\n CREATE_CONDITION_ERROR: 'CreateConditionError',\n UPDATE_CONDITION_ERROR: 'UpdateConditionError',\n DELETE_CONDITION_ERROR: 'DeleteConditionError',\n GET_CONDITION_ERROR: 'GetConditionError',\n PARSE_CONDITION_ERROR: 'ParseConditionError',\n CHANGE_CONDITIONAL_POLICIES_FILE_ERROR: 'ChangeConditionalPoliciesError',\n CONDITIONAL_POLICIES_FILE_NOT_FOUND: 'ConditionalPoliciesFileNotFound',\n};\n\nexport type ConditionAuditInfo = {\n condition: RoleConditionalPolicyDecision<PermissionAction>;\n};\n\nexport const RBAC_BACKEND = 'rbac-backend';\n\n// Audit log stage for processing Role-Based Access Control (RBAC) data\nexport const HANDLE_RBAC_DATA_STAGE = 'handleRBACData';\n\n// Audit log stage to refresh Role-Based Access Control (RBAC) data\nexport const FETCH_NEWER_PERMISSIONS_STAGE = 'fetchNewerPermissions';\n\n// Audit log stage for determining access rights based on user permissions and resource information\nexport const EVALUATE_PERMISSION_ACCESS_STAGE = 'evaluatePermissionAccess';\n\n// Audit log stage for sending the response to the client about handled permission policies, roles, and condition policies\nexport const SEND_RESPONSE_STAGE = 'sendResponse';\nexport const RESPONSE_ERROR = 'responseError';\n\nexport function createPermissionEvaluationOptions(\n message: string,\n userEntityRef: string,\n request: PolicyQuery,\n policyDecision?: PolicyDecision,\n): AuditLogOptions<EvaluationAuditInfo> {\n const auditInfo: EvaluationAuditInfo = {\n userEntityRef,\n permissionName: request.permission.name,\n action: toPermissionAction(request.permission.attributes),\n };\n\n const resourceType = (request.permission as ResourcePermission).resourceType;\n if (resourceType) {\n auditInfo.resourceType = resourceType;\n }\n\n let eventName;\n if (!policyDecision) {\n eventName = EvaluationEvents.PERMISSION_EVALUATION_STARTED;\n } else {\n auditInfo.decision = policyDecision;\n\n switch (policyDecision.result) {\n case AuthorizeResult.DENY:\n case AuthorizeResult.ALLOW:\n eventName = EvaluationEvents.PERMISSION_EVALUATION_COMPLETED;\n break;\n case AuthorizeResult.CONDITIONAL:\n eventName = EvaluationEvents.CONDITION_EVALUATION_COMPLETED;\n break;\n default:\n throw new Error('Unknown policy decision result');\n }\n }\n\n return {\n actorId: userEntityRef,\n message,\n eventName,\n metadata: auditInfo,\n stage: EVALUATE_PERMISSION_ACCESS_STAGE,\n status: 'succeeded',\n };\n}\n"],"names":["toPermissionAction","AuthorizeResult"],"mappings":";;;;;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;AAClB;AAEO,MAAM,gBAAmB,GAAA;AAAA,EAC9B,aAAe,EAAA,cAAA;AAAA,EACf,aAAe,EAAA,cAAA;AAAA,EACf,aAAe,EAAA,cAAA;AAAA,EACf,UAAY,EAAA,WAAA;AAAA,EAEZ,mBAAqB,EAAA,mBAAA;AAAA,EACrB,mBAAqB,EAAA,mBAAA;AAAA,EACrB,mBAAqB,EAAA,mBAAA;AAAA,EACrB,gBAAkB,EAAA;AACpB;AAeO,MAAM,gBAAmB,GAAA;AAAA,EAC9B,6BAA+B,EAAA,6BAAA;AAAA,EAC/B,+BAAiC,EAAA,+BAAA;AAAA,EACjC,8BAAgC,EAAA,8BAAA;AAAA,EAChC,4BAA8B,EAAA;AAChC;AAEO,MAAM,wBAA2B,GAAA;AAAA,EACtC,oBAAsB,EAAA,oBAAA;AAAA,EACtB,0BAA4B,EAAA;AAC9B;AAEO,MAAM,mBAAsB,GAAA;AAAA,EACjC,mBAAqB,EAAA,mBAAA;AAAA,EACrB,yBAA2B,EAAA;AAC7B;AAUO,MAAM,YAAe,GAAA;AAAA,EAC1B,iCAAmC,EAAA;AACrC;AAEO,MAAM,eAAkB,GAAA;AAAA,EAC7B,gBAAkB,EAAA,iBAAA;AAAA,EAClB,gBAAkB,EAAA,iBAAA;AAAA,EAClB,gBAAkB,EAAA,iBAAA;AAAA,EAClB,aAAe,EAAA,cAAA;AAAA,EAEf,sBAAwB,EAAA,sBAAA;AAAA,EACxB,sBAAwB,EAAA,sBAAA;AAAA,EACxB,sBAAwB,EAAA,sBAAA;AAAA,EACxB,mBAAqB,EAAA,mBAAA;AAAA,EACrB,qBAAuB,EAAA,qBAAA;AAAA,EACvB,sCAAwC,EAAA,gCAAA;AAAA,EACxC,mCAAqC,EAAA;AACvC;AAMO,MAAM,YAAe,GAAA;AAGrB,MAAM,sBAAyB,GAAA;AAG/B,MAAM,6BAAgC,GAAA;AAGtC,MAAM,gCAAmC,GAAA;AAGzC,MAAM,mBAAsB,GAAA;AAC5B,MAAM,cAAiB,GAAA;AAEvB,SAAS,iCACd,CAAA,OAAA,EACA,aACA,EAAA,OAAA,EACA,cACsC,EAAA;AACtC,EAAA,MAAM,SAAiC,GAAA;AAAA,IACrC,aAAA;AAAA,IACA,cAAA,EAAgB,QAAQ,UAAW,CAAA,IAAA;AAAA,IACnC,MAAQ,EAAAA,mCAAA,CAAmB,OAAQ,CAAA,UAAA,CAAW,UAAU;AAAA,GAC1D;AAEA,EAAM,MAAA,YAAA,GAAgB,QAAQ,UAAkC,CAAA,YAAA;AAChE,EAAA,IAAI,YAAc,EAAA;AAChB,IAAA,SAAA,CAAU,YAAe,GAAA,YAAA;AAAA;AAG3B,EAAI,IAAA,SAAA;AACJ,EAAA,IAAI,CAAC,cAAgB,EAAA;AACnB,IAAA,SAAA,GAAY,gBAAiB,CAAA,6BAAA;AAAA,GACxB,MAAA;AACL,IAAA,SAAA,CAAU,QAAW,GAAA,cAAA;AAErB,IAAA,QAAQ,eAAe,MAAQ;AAAA,MAC7B,KAAKC,sCAAgB,CAAA,IAAA;AAAA,MACrB,KAAKA,sCAAgB,CAAA,KAAA;AACnB,QAAA,SAAA,GAAY,gBAAiB,CAAA,+BAAA;AAC7B,QAAA;AAAA,MACF,KAAKA,sCAAgB,CAAA,WAAA;AACnB,QAAA,SAAA,GAAY,gBAAiB,CAAA,8BAAA;AAC7B,QAAA;AAAA,MACF;AACE,QAAM,MAAA,IAAI,MAAM,gCAAgC,CAAA;AAAA;AACpD;AAGF,EAAO,OAAA;AAAA,IACL,OAAS,EAAA,aAAA;AAAA,IACT,OAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAU,EAAA,SAAA;AAAA,IACV,KAAO,EAAA,gCAAA;AAAA,IACP,MAAQ,EAAA;AAAA,GACV;AACF;;;;;;;;;;;;;;;;;"}
|
|
@@ -30,7 +30,8 @@ class CasbinDBAdapterFactory {
|
|
|
30
30
|
password: databaseConfig?.getString("connection.password"),
|
|
31
31
|
ssl,
|
|
32
32
|
database: dbName,
|
|
33
|
-
schema
|
|
33
|
+
schema,
|
|
34
|
+
poolSize: databaseConfig?.getOptionalNumber("knexConfig.pool.max")
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
if (client === "better-sqlite3") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"casbin-adapter-factory.cjs.js","sources":["../../src/database/casbin-adapter-factory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { Config } from '@backstage/config';\nimport type { ConfigApi } from '@backstage/core-plugin-api';\n\nimport { Knex } from 'knex';\nimport TypeORMAdapter from 'typeorm-adapter';\n\nimport { resolve } from 'path';\nimport type { ConnectionOptions, TlsOptions } from 'tls';\n\nimport '@backstage/backend-defaults/database';\n\nconst DEFAULT_SQLITE3_STORAGE_FILE_NAME = 'rbac.sqlite';\n\nexport class CasbinDBAdapterFactory {\n public constructor(\n private readonly config: ConfigApi,\n private readonly databaseClient: Knex,\n ) {}\n\n public async createAdapter(): Promise<TypeORMAdapter> {\n const databaseConfig = this.config.getOptionalConfig('backend.database');\n const client = databaseConfig?.getOptionalString('client');\n\n let adapter;\n if (client === 'pg') {\n const dbName =\n await this.databaseClient.client.config.connection.database;\n const schema =\n (await this.databaseClient.client.searchPath?.[0]) ?? 'public';\n\n const ssl = this.handlePostgresSSL(databaseConfig!);\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'postgres',\n host: databaseConfig?.getString('connection.host'),\n port: databaseConfig?.getNumber('connection.port'),\n username: databaseConfig?.getString('connection.user'),\n password: databaseConfig?.getString('connection.password'),\n ssl,\n database: dbName,\n schema: schema,\n });\n }\n\n if (client === 'better-sqlite3') {\n let storage;\n if (typeof databaseConfig?.get('connection')?.valueOf() === 'string') {\n storage = databaseConfig?.getString('connection');\n } else if (databaseConfig?.has('connection.directory')) {\n const storageDir = databaseConfig?.getString('connection.directory');\n storage = resolve(storageDir, DEFAULT_SQLITE3_STORAGE_FILE_NAME);\n }\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'better-sqlite3',\n // Storage type or path to the storage.\n database: storage || ':memory:',\n });\n }\n\n if (!adapter) {\n throw new Error(`Unsupported database client ${client}`);\n }\n\n return adapter;\n }\n\n private handlePostgresSSL(\n dbConfig: Config,\n ): boolean | TlsOptions | undefined {\n const connection = dbConfig.getOptional<Knex.PgConnectionConfig | string>(\n 'connection',\n );\n if (!connection) {\n return undefined;\n }\n\n if (typeof connection === 'string' || connection instanceof String) {\n throw new Error(\n `rbac backend plugin doesn't support postgres connection in a string format yet`,\n );\n }\n\n const ssl: boolean | ConnectionOptions | undefined = connection.ssl;\n\n if (ssl === undefined) {\n return undefined;\n }\n\n if (typeof ssl === 'boolean') {\n return ssl;\n }\n\n if (typeof ssl === 'object') {\n const { ca, rejectUnauthorized } = ssl as ConnectionOptions;\n const tlsOpts = { ca, rejectUnauthorized };\n\n // SSL object was defined with some options that we don't support yet.\n if (Object.values(tlsOpts).every(el => el === undefined)) {\n return true;\n }\n\n return tlsOpts;\n }\n\n return undefined;\n }\n}\n"],"names":["TypeORMAdapter","resolve"],"mappings":";;;;;;;;;;AA0BA,MAAM,iCAAoC,GAAA,aAAA;AAEnC,MAAM,sBAAuB,CAAA;AAAA,EAC3B,WAAA,CACY,QACA,cACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA;AAChB,EAEH,MAAa,aAAyC,GAAA;AACpD,IAAA,MAAM,cAAiB,GAAA,IAAA,CAAK,MAAO,CAAA,iBAAA,CAAkB,kBAAkB,CAAA;AACvE,IAAM,MAAA,MAAA,GAAS,cAAgB,EAAA,iBAAA,CAAkB,QAAQ,CAAA;AAEzD,IAAI,IAAA,OAAA;AACJ,IAAA,IAAI,WAAW,IAAM,EAAA;AACnB,MAAA,MAAM,SACJ,MAAM,IAAA,CAAK,cAAe,CAAA,MAAA,CAAO,OAAO,UAAW,CAAA,QAAA;AACrD,MAAA,MAAM,SACH,MAAM,IAAA,CAAK,eAAe,MAAO,CAAA,UAAA,GAAa,CAAC,CAAM,IAAA,QAAA;AAExD,MAAM,MAAA,GAAA,GAAM,IAAK,CAAA,iBAAA,CAAkB,cAAe,CAAA;AAElD,MAAU,OAAA,GAAA,MAAMA,gCAAe,UAAW,CAAA;AAAA,QACxC,IAAM,EAAA,UAAA;AAAA,QACN,IAAA,EAAM,cAAgB,EAAA,SAAA,CAAU,iBAAiB,CAAA;AAAA,QACjD,IAAA,EAAM,cAAgB,EAAA,SAAA,CAAU,iBAAiB,CAAA;AAAA,QACjD,QAAA,EAAU,cAAgB,EAAA,SAAA,CAAU,iBAAiB,CAAA;AAAA,QACrD,QAAA,EAAU,cAAgB,EAAA,SAAA,CAAU,qBAAqB,CAAA;AAAA,QACzD,GAAA;AAAA,QACA,QAAU,EAAA,MAAA;AAAA,QACV;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 =\n await this.databaseClient.client.config.connection.database;\n const schema =\n (await this.databaseClient.client.searchPath?.[0]) ?? 'public';\n\n const ssl = this.handlePostgresSSL(databaseConfig!);\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'postgres',\n host: databaseConfig?.getString('connection.host'),\n port: databaseConfig?.getNumber('connection.port'),\n username: databaseConfig?.getString('connection.user'),\n password: databaseConfig?.getString('connection.password'),\n ssl,\n database: dbName,\n schema: schema,\n poolSize: databaseConfig?.getOptionalNumber('knexConfig.pool.max'),\n });\n }\n\n if (client === 'better-sqlite3') {\n let storage;\n if (typeof databaseConfig?.get('connection')?.valueOf() === 'string') {\n storage = databaseConfig?.getString('connection');\n } else if (databaseConfig?.has('connection.directory')) {\n const storageDir = databaseConfig?.getString('connection.directory');\n storage = resolve(storageDir, DEFAULT_SQLITE3_STORAGE_FILE_NAME);\n }\n\n adapter = await TypeORMAdapter.newAdapter({\n type: 'better-sqlite3',\n // Storage type or path to the storage.\n database: storage || ':memory:',\n });\n }\n\n if (!adapter) {\n throw new Error(`Unsupported database client ${client}`);\n }\n\n return adapter;\n }\n\n private handlePostgresSSL(\n dbConfig: Config,\n ): boolean | TlsOptions | undefined {\n const connection = dbConfig.getOptional<Knex.PgConnectionConfig | string>(\n 'connection',\n );\n if (!connection) {\n return undefined;\n }\n\n if (typeof connection === 'string' || connection instanceof String) {\n throw new Error(\n `rbac backend plugin doesn't support postgres connection in a string format yet`,\n );\n }\n\n const ssl: boolean | ConnectionOptions | undefined = connection.ssl;\n\n if (ssl === undefined) {\n return undefined;\n }\n\n if (typeof ssl === 'boolean') {\n return ssl;\n }\n\n if (typeof ssl === 'object') {\n const { ca, rejectUnauthorized } = ssl as ConnectionOptions;\n const tlsOpts = { ca, rejectUnauthorized };\n\n // SSL object was defined with some options that we don't support yet.\n if (Object.values(tlsOpts).every(el => el === undefined)) {\n return true;\n }\n\n return tlsOpts;\n }\n\n return undefined;\n }\n}\n"],"names":["TypeORMAdapter","resolve"],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ var helper = require('../helper.cjs.js');
|
|
|
8
8
|
var permissionModel = require('../service/permission-model.cjs.js');
|
|
9
9
|
var policiesValidation = require('../validation/policies-validation.cjs.js');
|
|
10
10
|
var fileWatcher = require('./file-watcher.cjs.js');
|
|
11
|
+
var lowercaseFileAdapter = require('./lowercase-file-adapter.cjs.js');
|
|
11
12
|
|
|
12
13
|
const CSV_PERMISSION_POLICY_FILE_AUTHOR = "csv permission policy file";
|
|
13
14
|
class CSVFileWatcher extends fileWatcher.AbstractFileWatcher {
|
|
@@ -32,12 +33,15 @@ class CSVFileWatcher extends fileWatcher.AbstractFileWatcher {
|
|
|
32
33
|
*/
|
|
33
34
|
parse() {
|
|
34
35
|
const content = this.getCurrentContents();
|
|
35
|
-
const
|
|
36
|
+
const data = sync.parse(content, {
|
|
36
37
|
skip_empty_lines: true,
|
|
37
38
|
relax_column_count: true,
|
|
38
39
|
trim: true
|
|
39
40
|
});
|
|
40
|
-
|
|
41
|
+
for (const policy of data) {
|
|
42
|
+
helper.transformPolicyGroupToLowercase(policy);
|
|
43
|
+
}
|
|
44
|
+
return data;
|
|
41
45
|
}
|
|
42
46
|
/**
|
|
43
47
|
* initialize will initialize the CSV file by loading all of the permission policies and roles into
|
|
@@ -56,7 +60,7 @@ class CSVFileWatcher extends fileWatcher.AbstractFileWatcher {
|
|
|
56
60
|
content = this.parse();
|
|
57
61
|
const tempEnforcer = await casbin.newEnforcer(
|
|
58
62
|
casbin.newModelFromString(permissionModel.MODEL),
|
|
59
|
-
new
|
|
63
|
+
new lowercaseFileAdapter.LowercaseFileAdapter(this.filePath)
|
|
60
64
|
);
|
|
61
65
|
await this.cleanUpRolesAndPolicies();
|
|
62
66
|
const policiesToAdd = await tempEnforcer.getPolicy();
|
|
@@ -124,7 +128,7 @@ class CSVFileWatcher extends fileWatcher.AbstractFileWatcher {
|
|
|
124
128
|
const newContent = this.parse();
|
|
125
129
|
const tempEnforcer = await casbin.newEnforcer(
|
|
126
130
|
casbin.newModelFromString(permissionModel.MODEL),
|
|
127
|
-
new
|
|
131
|
+
new lowercaseFileAdapter.LowercaseFileAdapter(this.filePath)
|
|
128
132
|
);
|
|
129
133
|
const currentFlatContent = this.currentContent.flatMap((data) => {
|
|
130
134
|
return helper.policyToString(data);
|
|
@@ -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\n await this.cleanUpRolesAndPolicies();\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 =\n await this.roleMetadataStorage.filterRoleMetadata('legacy');\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 =\n await this.roleMetadataStorage.findRoleMetadata(roleEntityRef);\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 =\n await this.roleMetadataStorage.filterRoleMetadata('csv-file');\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, 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 transformPolicyGroupToLowercase,\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';\nimport { LowercaseFileAdapter } from './lowercase-file-adapter';\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 data = parse(content, {\n skip_empty_lines: true,\n relax_column_count: true,\n trim: true,\n });\n\n for (const policy of data) {\n transformPolicyGroupToLowercase(policy);\n }\n\n return data;\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 LowercaseFileAdapter(this.filePath),\n );\n\n // Check for any old policies that will need to be removed\n await this.cleanUpRolesAndPolicies();\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 =\n await this.roleMetadataStorage.filterRoleMetadata('legacy');\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 LowercaseFileAdapter(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 =\n await this.roleMetadataStorage.findRoleMetadata(roleEntityRef);\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 =\n await this.roleMetadataStorage.filterRoleMetadata('csv-file');\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","transformPolicyGroupToLowercase","newEnforcer","newModelFromString","MODEL","LowercaseFileAdapter","mergeRoleMetadata","policyToString","difference","metadataStringToPolicy","transformArrayToPolicy","validatePolicy","validateSource","checkForDuplicatePolicies","RBAC_BACKEND","PermissionEvents","HANDLE_RBAC_DATA_STAGE","validateGroupingPolicy","checkForDuplicateGroupPolicies","RoleEvents"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var casbin = require('casbin');
|
|
4
|
+
|
|
5
|
+
class LowercaseFileAdapter extends casbin.FileAdapter {
|
|
6
|
+
async loadPolicy(model) {
|
|
7
|
+
if (!this.filePath) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
await this.loadLowercasePolicyFile(model, casbin.Helper.loadPolicyLine);
|
|
11
|
+
}
|
|
12
|
+
transformLineToLowercaseGroupsUsers(line) {
|
|
13
|
+
if (line.trim().startsWith("g")) {
|
|
14
|
+
const policyArray = line.split(",");
|
|
15
|
+
if (policyArray.length >= 1 && policyArray[0].trim().startsWith("g")) {
|
|
16
|
+
policyArray[1] = policyArray[1].toLocaleLowerCase("en-US");
|
|
17
|
+
}
|
|
18
|
+
return policyArray.join(",");
|
|
19
|
+
}
|
|
20
|
+
return line;
|
|
21
|
+
}
|
|
22
|
+
async loadLowercasePolicyFile(model, handler) {
|
|
23
|
+
const bodyBuf = await (this.fs ? this.fs : casbin.mustGetDefaultFileSystem()).readFileSync(this.filePath);
|
|
24
|
+
const lines = bodyBuf.toString().split("\n");
|
|
25
|
+
lines.forEach((line) => {
|
|
26
|
+
if (!line) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const lowercasedLine = this.transformLineToLowercaseGroupsUsers(line);
|
|
30
|
+
handler(lowercasedLine, model);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.LowercaseFileAdapter = LowercaseFileAdapter;
|
|
36
|
+
//# sourceMappingURL=lowercase-file-adapter.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lowercase-file-adapter.cjs.js","sources":["../../src/file-permissions/lowercase-file-adapter.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 { FileAdapter, Helper, Model, mustGetDefaultFileSystem } from 'casbin';\n\nexport class LowercaseFileAdapter extends FileAdapter {\n public async loadPolicy(model: Model): Promise<void> {\n if (!this.filePath) {\n return;\n }\n await this.loadLowercasePolicyFile(model, Helper.loadPolicyLine);\n }\n\n private transformLineToLowercaseGroupsUsers(line: string): string {\n if (line.trim().startsWith('g')) {\n const policyArray = line.split(',');\n if (policyArray.length >= 1 && policyArray[0].trim().startsWith('g')) {\n policyArray[1] = policyArray[1].toLocaleLowerCase('en-US');\n }\n return policyArray.join(',');\n }\n return line;\n }\n\n private async loadLowercasePolicyFile(\n model: Model,\n handler: (line: string, model: Model) => void,\n ): Promise<void> {\n // Reference: https://github.com/casbin/node-casbin/blob/master/src/persist/fileAdapter.ts#L34-#L43\n const bodyBuf = await (\n this.fs ? this.fs : mustGetDefaultFileSystem()\n ).readFileSync(this.filePath);\n const lines = bodyBuf.toString().split('\\n');\n\n lines.forEach((line: string) => {\n if (!line) {\n return;\n }\n const lowercasedLine = this.transformLineToLowercaseGroupsUsers(line);\n handler(lowercasedLine, model);\n });\n }\n}\n"],"names":["FileAdapter","Helper","mustGetDefaultFileSystem"],"mappings":";;;;AAiBO,MAAM,6BAA6BA,kBAAY,CAAA;AAAA,EACpD,MAAa,WAAW,KAA6B,EAAA;AACnD,IAAI,IAAA,CAAC,KAAK,QAAU,EAAA;AAClB,MAAA;AAAA;AAEF,IAAA,MAAM,IAAK,CAAA,uBAAA,CAAwB,KAAO,EAAAC,aAAA,CAAO,cAAc,CAAA;AAAA;AACjE,EAEQ,oCAAoC,IAAsB,EAAA;AAChE,IAAA,IAAI,IAAK,CAAA,IAAA,EAAO,CAAA,UAAA,CAAW,GAAG,CAAG,EAAA;AAC/B,MAAM,MAAA,WAAA,GAAc,IAAK,CAAA,KAAA,CAAM,GAAG,CAAA;AAClC,MAAI,IAAA,WAAA,CAAY,MAAU,IAAA,CAAA,IAAK,WAAY,CAAA,CAAC,EAAE,IAAK,EAAA,CAAE,UAAW,CAAA,GAAG,CAAG,EAAA;AACpE,QAAA,WAAA,CAAY,CAAC,CAAI,GAAA,WAAA,CAAY,CAAC,CAAA,CAAE,kBAAkB,OAAO,CAAA;AAAA;AAE3D,MAAO,OAAA,WAAA,CAAY,KAAK,GAAG,CAAA;AAAA;AAE7B,IAAO,OAAA,IAAA;AAAA;AACT,EAEA,MAAc,uBACZ,CAAA,KAAA,EACA,OACe,EAAA;AAEf,IAAM,MAAA,OAAA,GAAU,MACd,CAAA,IAAA,CAAK,EAAK,GAAA,IAAA,CAAK,KAAKC,+BAAyB,EAAA,EAC7C,YAAa,CAAA,IAAA,CAAK,QAAQ,CAAA;AAC5B,IAAA,MAAM,KAAQ,GAAA,OAAA,CAAQ,QAAS,EAAA,CAAE,MAAM,IAAI,CAAA;AAE3C,IAAM,KAAA,CAAA,OAAA,CAAQ,CAAC,IAAiB,KAAA;AAC9B,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA;AAAA;AAEF,MAAM,MAAA,cAAA,GAAiB,IAAK,CAAA,mCAAA,CAAoC,IAAI,CAAA;AACpE,MAAA,OAAA,CAAQ,gBAAgB,KAAK,CAAA;AAAA,KAC9B,CAAA;AAAA;AAEL;;;;"}
|
package/dist/helper.cjs.js
CHANGED
|
@@ -59,6 +59,16 @@ function transformArrayToPolicy(policyArray) {
|
|
|
59
59
|
const [entityReference, permission, policy, effect] = policyArray;
|
|
60
60
|
return { entityReference, permission, policy, effect };
|
|
61
61
|
}
|
|
62
|
+
function transformPolicyGroupToLowercase(policyArray) {
|
|
63
|
+
if (policyArray.length > 1 && policyArray[0].startsWith("g") && (policyArray[1].startsWith("user") || policyArray[1].startsWith("group"))) {
|
|
64
|
+
policyArray[1] = policyArray[1].toLocaleLowerCase("en-US");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function transformRolesGroupToLowercase(roles) {
|
|
68
|
+
return roles.map(
|
|
69
|
+
(role) => role.length >= 1 ? [role[0].toLocaleLowerCase("en-US"), ...role.slice(1)] : role
|
|
70
|
+
);
|
|
71
|
+
}
|
|
62
72
|
function deepSortedEqual(obj1, obj2, excludeFields) {
|
|
63
73
|
let copyObj1;
|
|
64
74
|
let copyObj2;
|
|
@@ -166,6 +176,8 @@ exports.policyToString = policyToString;
|
|
|
166
176
|
exports.processConditionMapping = processConditionMapping;
|
|
167
177
|
exports.removeTheDifference = removeTheDifference;
|
|
168
178
|
exports.transformArrayToPolicy = transformArrayToPolicy;
|
|
179
|
+
exports.transformPolicyGroupToLowercase = transformPolicyGroupToLowercase;
|
|
180
|
+
exports.transformRolesGroupToLowercase = transformRolesGroupToLowercase;
|
|
169
181
|
exports.typedPoliciesToString = typedPoliciesToString;
|
|
170
182
|
exports.typedPolicyToString = typedPolicyToString;
|
|
171
183
|
//# sourceMappingURL=helper.cjs.js.map
|
package/dist/helper.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.cjs.js","sources":["../src/helper.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 { AuthService } from '@backstage/backend-plugin-api';\nimport type { MetadataResponse } from '@backstage/plugin-permission-node';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport {\n difference,\n fromPairs,\n isArray,\n isEqual,\n isPlainObject,\n omitBy,\n sortBy,\n toPairs,\n ValueKeyIteratee,\n} from 'lodash';\n\nimport {\n PermissionAction,\n PermissionInfo,\n RoleBasedPolicy,\n RoleConditionalPolicyDecision,\n Source,\n} from '@backstage-community/plugin-rbac-common';\n\nimport {\n HANDLE_RBAC_DATA_STAGE,\n RBAC_BACKEND,\n RoleAuditInfo,\n RoleEvents,\n} from './audit-log/audit-logger';\nimport { RoleMetadataDao, RoleMetadataStorage } from './database/role-metadata';\nimport { EnforcerDelegate } from './service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from './service/plugin-endpoints';\n\nexport function policyToString(policy: string[]): string {\n return `[${policy.join(', ')}]`;\n}\n\nexport function typedPolicyToString(policy: string[], type: string): string {\n return `${type}, ${policy.join(', ')}`;\n}\n\nexport function policiesToString(policies: string[][]): string {\n const policiesString = policies\n .map(policy => policyToString(policy))\n .join(',');\n return `[${policiesString}]`;\n}\n\nexport function typedPoliciesToString(\n policies: string[][],\n type: string,\n): string {\n const policiesString = policies\n .map(policy => {\n return policy.length !== 0 ? typedPolicyToString(policy, type) : '';\n })\n .join('\\n');\n return `\n ${policiesString}\n `;\n}\n\nexport function metadataStringToPolicy(policy: string): string[] {\n return policy.replace('[', '').replace(']', '').split(', ');\n}\n\nexport async function removeTheDifference(\n originalGroup: string[],\n addedGroup: string[],\n source: Source,\n roleEntityRef: string,\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n modifiedBy: string,\n): Promise<void> {\n originalGroup.sort((a, b) => a.localeCompare(b));\n addedGroup.sort((a, b) => a.localeCompare(b));\n const missing = difference(originalGroup, addedGroup);\n\n const groupPolicies: string[][] = [];\n for (const missingRole of missing) {\n groupPolicies.push([missingRole, roleEntityRef]);\n }\n\n if (groupPolicies.length === 0) {\n return;\n }\n\n const roleMetadata = { source, modifiedBy, roleEntityRef };\n await enf.removeGroupingPolicies(groupPolicies, roleMetadata, false);\n\n const remainingMembers = await enf.getFilteredGroupingPolicy(\n 1,\n roleEntityRef,\n );\n const message =\n remainingMembers.length > 0\n ? 'Updated role: deleted members'\n : 'Deleted role';\n const eventName =\n remainingMembers.length > 0\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.DELETE_ROLE;\n await auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: {\n ...roleMetadata,\n members: groupPolicies.map(gp => gp[0]),\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n}\n\nexport function transformArrayToPolicy(policyArray: string[]): RoleBasedPolicy {\n const [entityReference, permission, policy, effect] = policyArray;\n return { entityReference, permission, policy, effect };\n}\n\nexport function deepSortedEqual(\n obj1: Record<string, any>,\n obj2: Record<string, any>,\n excludeFields?: string[],\n): boolean {\n let copyObj1;\n let copyObj2;\n if (excludeFields) {\n const excludeFieldsPredicate: ValueKeyIteratee<any> = (_value, key) => {\n for (const field of excludeFields) {\n if (key === field) {\n return true;\n }\n }\n return false;\n };\n copyObj1 = omitBy(obj1, excludeFieldsPredicate);\n copyObj2 = omitBy(obj2, excludeFieldsPredicate);\n }\n\n const sortedObj1 = sortBy(toPairs(copyObj1 || obj1), ([key]) => key);\n const sortedObj2 = sortBy(toPairs(copyObj2 || obj2), ([key]) => key);\n\n return isEqual(sortedObj1, sortedObj2);\n}\n\nexport function isPermissionAction(action: string): action is PermissionAction {\n return ['create', 'read', 'update', 'delete', 'use'].includes(\n action as PermissionAction,\n );\n}\n\nexport async function buildRoleSourceMap(\n policies: string[][],\n roleMetadata: RoleMetadataStorage,\n): Promise<Map<string, Source | undefined>> {\n return await policies.reduce(\n async (\n acc: Promise<Map<string, Source | undefined>>,\n policy: string[],\n ): Promise<Map<string, Source | undefined>> => {\n const roleEntityRef = policy[0];\n const acummulator = await acc;\n if (!acummulator.has(roleEntityRef)) {\n const metadata = await roleMetadata.findRoleMetadata(roleEntityRef);\n acummulator.set(roleEntityRef, metadata?.source);\n }\n return acummulator;\n },\n Promise.resolve(new Map<string, Source | undefined>()),\n );\n}\n\nexport function mergeRoleMetadata(\n currentMetadata: RoleMetadataDao,\n newMetadata: RoleMetadataDao,\n): RoleMetadataDao {\n const mergedMetaData: RoleMetadataDao = { ...currentMetadata };\n mergedMetaData.lastModified =\n newMetadata.lastModified ?? new Date().toUTCString();\n mergedMetaData.modifiedBy = newMetadata.modifiedBy;\n mergedMetaData.description =\n newMetadata.description ?? currentMetadata.description;\n mergedMetaData.roleEntityRef = newMetadata.roleEntityRef;\n mergedMetaData.source = newMetadata.source;\n return mergedMetaData;\n}\n\nexport async function processConditionMapping(\n roleConditionPolicy: RoleConditionalPolicyDecision<PermissionAction>,\n pluginPermMetaData: PluginPermissionMetadataCollector,\n auth: AuthService,\n): Promise<RoleConditionalPolicyDecision<PermissionInfo>> {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: roleConditionPolicy.pluginId,\n });\n\n const rule: MetadataResponse | undefined =\n await pluginPermMetaData.getMetadataByPluginId(\n roleConditionPolicy.pluginId,\n token,\n );\n if (!rule?.permissions) {\n throw new Error(\n `Unable to get permission list for plugin ${roleConditionPolicy.pluginId}`,\n );\n }\n\n const permInfo: PermissionInfo[] = [];\n for (const action of roleConditionPolicy.permissionMapping) {\n const perm = rule.permissions.find(\n permission =>\n permission.type === 'resource' &&\n (action === permission.attributes.action ||\n (action === 'use' && permission.attributes.action === undefined)),\n );\n if (!perm) {\n throw new Error(\n `Unable to find permission to get permission name for resource type '${\n roleConditionPolicy.resourceType\n }' and action ${JSON.stringify(action)}`,\n );\n }\n permInfo.push({ name: perm.name, action });\n }\n\n return {\n ...roleConditionPolicy,\n permissionMapping: permInfo,\n };\n}\n\nexport function deepSort(value: any): any {\n if (isArray(value)) {\n return sortBy(value.map(deepSort));\n } else if (isPlainObject(value)) {\n return fromPairs(\n sortBy(\n toPairs(value).map(([k, v]: [string, any]) => [k, deepSort(v)]),\n 0,\n ),\n );\n }\n return value;\n}\n\nexport function deepSortEqual(obj1: any, obj2: any): boolean {\n return isEqual(deepSort(obj1), deepSort(obj2));\n}\n"],"names":["auditLogger","difference","RoleEvents","RBAC_BACKEND","HANDLE_RBAC_DATA_STAGE","omitBy","sortBy","toPairs","isEqual","isArray","isPlainObject","fromPairs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"helper.cjs.js","sources":["../src/helper.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 { AuthService } from '@backstage/backend-plugin-api';\nimport type { MetadataResponse } from '@backstage/plugin-permission-node';\n\nimport { AuditLogger } from '@janus-idp/backstage-plugin-audit-log-node';\nimport {\n difference,\n fromPairs,\n isArray,\n isEqual,\n isPlainObject,\n omitBy,\n sortBy,\n toPairs,\n ValueKeyIteratee,\n} from 'lodash';\n\nimport {\n PermissionAction,\n PermissionInfo,\n RoleBasedPolicy,\n RoleConditionalPolicyDecision,\n Source,\n} from '@backstage-community/plugin-rbac-common';\n\nimport {\n HANDLE_RBAC_DATA_STAGE,\n RBAC_BACKEND,\n RoleAuditInfo,\n RoleEvents,\n} from './audit-log/audit-logger';\nimport { RoleMetadataDao, RoleMetadataStorage } from './database/role-metadata';\nimport { EnforcerDelegate } from './service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from './service/plugin-endpoints';\n\nexport function policyToString(policy: string[]): string {\n return `[${policy.join(', ')}]`;\n}\n\nexport function typedPolicyToString(policy: string[], type: string): string {\n return `${type}, ${policy.join(', ')}`;\n}\n\nexport function policiesToString(policies: string[][]): string {\n const policiesString = policies\n .map(policy => policyToString(policy))\n .join(',');\n return `[${policiesString}]`;\n}\n\nexport function typedPoliciesToString(\n policies: string[][],\n type: string,\n): string {\n const policiesString = policies\n .map(policy => {\n return policy.length !== 0 ? typedPolicyToString(policy, type) : '';\n })\n .join('\\n');\n return `\n ${policiesString}\n `;\n}\n\nexport function metadataStringToPolicy(policy: string): string[] {\n return policy.replace('[', '').replace(']', '').split(', ');\n}\n\nexport async function removeTheDifference(\n originalGroup: string[],\n addedGroup: string[],\n source: Source,\n roleEntityRef: string,\n enf: EnforcerDelegate,\n auditLogger: AuditLogger,\n modifiedBy: string,\n): Promise<void> {\n originalGroup.sort((a, b) => a.localeCompare(b));\n addedGroup.sort((a, b) => a.localeCompare(b));\n const missing = difference(originalGroup, addedGroup);\n\n const groupPolicies: string[][] = [];\n for (const missingRole of missing) {\n groupPolicies.push([missingRole, roleEntityRef]);\n }\n\n if (groupPolicies.length === 0) {\n return;\n }\n\n const roleMetadata = { source, modifiedBy, roleEntityRef };\n await enf.removeGroupingPolicies(groupPolicies, roleMetadata, false);\n\n const remainingMembers = await enf.getFilteredGroupingPolicy(\n 1,\n roleEntityRef,\n );\n const message =\n remainingMembers.length > 0\n ? 'Updated role: deleted members'\n : 'Deleted role';\n const eventName =\n remainingMembers.length > 0\n ? RoleEvents.UPDATE_ROLE\n : RoleEvents.DELETE_ROLE;\n await auditLogger.auditLog<RoleAuditInfo>({\n actorId: RBAC_BACKEND,\n message,\n eventName,\n metadata: {\n ...roleMetadata,\n members: groupPolicies.map(gp => gp[0]),\n },\n stage: HANDLE_RBAC_DATA_STAGE,\n status: 'succeeded',\n });\n}\n\nexport function transformArrayToPolicy(policyArray: string[]): RoleBasedPolicy {\n const [entityReference, permission, policy, effect] = policyArray;\n return { entityReference, permission, policy, effect };\n}\n\nexport function transformPolicyGroupToLowercase(policyArray: string[]) {\n if (\n policyArray.length > 1 &&\n policyArray[0].startsWith('g') &&\n (policyArray[1].startsWith('user') || policyArray[1].startsWith('group'))\n ) {\n policyArray[1] = policyArray[1].toLocaleLowerCase('en-US');\n }\n}\n\nexport function transformRolesGroupToLowercase(roles: string[][]) {\n return roles.map(role =>\n role.length >= 1\n ? [role[0].toLocaleLowerCase('en-US'), ...role.slice(1)]\n : role,\n );\n}\n\nexport function deepSortedEqual(\n obj1: Record<string, any>,\n obj2: Record<string, any>,\n excludeFields?: string[],\n): boolean {\n let copyObj1;\n let copyObj2;\n if (excludeFields) {\n const excludeFieldsPredicate: ValueKeyIteratee<any> = (_value, key) => {\n for (const field of excludeFields) {\n if (key === field) {\n return true;\n }\n }\n return false;\n };\n copyObj1 = omitBy(obj1, excludeFieldsPredicate);\n copyObj2 = omitBy(obj2, excludeFieldsPredicate);\n }\n\n const sortedObj1 = sortBy(toPairs(copyObj1 || obj1), ([key]) => key);\n const sortedObj2 = sortBy(toPairs(copyObj2 || obj2), ([key]) => key);\n\n return isEqual(sortedObj1, sortedObj2);\n}\n\nexport function isPermissionAction(action: string): action is PermissionAction {\n return ['create', 'read', 'update', 'delete', 'use'].includes(\n action as PermissionAction,\n );\n}\n\nexport async function buildRoleSourceMap(\n policies: string[][],\n roleMetadata: RoleMetadataStorage,\n): Promise<Map<string, Source | undefined>> {\n return await policies.reduce(\n async (\n acc: Promise<Map<string, Source | undefined>>,\n policy: string[],\n ): Promise<Map<string, Source | undefined>> => {\n const roleEntityRef = policy[0];\n const acummulator = await acc;\n if (!acummulator.has(roleEntityRef)) {\n const metadata = await roleMetadata.findRoleMetadata(roleEntityRef);\n acummulator.set(roleEntityRef, metadata?.source);\n }\n return acummulator;\n },\n Promise.resolve(new Map<string, Source | undefined>()),\n );\n}\n\nexport function mergeRoleMetadata(\n currentMetadata: RoleMetadataDao,\n newMetadata: RoleMetadataDao,\n): RoleMetadataDao {\n const mergedMetaData: RoleMetadataDao = { ...currentMetadata };\n mergedMetaData.lastModified =\n newMetadata.lastModified ?? new Date().toUTCString();\n mergedMetaData.modifiedBy = newMetadata.modifiedBy;\n mergedMetaData.description =\n newMetadata.description ?? currentMetadata.description;\n mergedMetaData.roleEntityRef = newMetadata.roleEntityRef;\n mergedMetaData.source = newMetadata.source;\n return mergedMetaData;\n}\n\nexport async function processConditionMapping(\n roleConditionPolicy: RoleConditionalPolicyDecision<PermissionAction>,\n pluginPermMetaData: PluginPermissionMetadataCollector,\n auth: AuthService,\n): Promise<RoleConditionalPolicyDecision<PermissionInfo>> {\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: roleConditionPolicy.pluginId,\n });\n\n const rule: MetadataResponse | undefined =\n await pluginPermMetaData.getMetadataByPluginId(\n roleConditionPolicy.pluginId,\n token,\n );\n if (!rule?.permissions) {\n throw new Error(\n `Unable to get permission list for plugin ${roleConditionPolicy.pluginId}`,\n );\n }\n\n const permInfo: PermissionInfo[] = [];\n for (const action of roleConditionPolicy.permissionMapping) {\n const perm = rule.permissions.find(\n permission =>\n permission.type === 'resource' &&\n (action === permission.attributes.action ||\n (action === 'use' && permission.attributes.action === undefined)),\n );\n if (!perm) {\n throw new Error(\n `Unable to find permission to get permission name for resource type '${\n roleConditionPolicy.resourceType\n }' and action ${JSON.stringify(action)}`,\n );\n }\n permInfo.push({ name: perm.name, action });\n }\n\n return {\n ...roleConditionPolicy,\n permissionMapping: permInfo,\n };\n}\n\nexport function deepSort(value: any): any {\n if (isArray(value)) {\n return sortBy(value.map(deepSort));\n } else if (isPlainObject(value)) {\n return fromPairs(\n sortBy(\n toPairs(value).map(([k, v]: [string, any]) => [k, deepSort(v)]),\n 0,\n ),\n );\n }\n return value;\n}\n\nexport function deepSortEqual(obj1: any, obj2: any): boolean {\n return isEqual(deepSort(obj1), deepSort(obj2));\n}\n"],"names":["auditLogger","difference","RoleEvents","RBAC_BACKEND","HANDLE_RBAC_DATA_STAGE","omitBy","sortBy","toPairs","isEqual","isArray","isPlainObject","fromPairs"],"mappings":"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"}
|
|
@@ -114,6 +114,7 @@ class RBACPermissionPolicy {
|
|
|
114
114
|
return { result: pluginPermissionCommon.AuthorizeResult.DENY };
|
|
115
115
|
}
|
|
116
116
|
const permissionName = request.permission.name;
|
|
117
|
+
await this.enforcer.loadPolicy();
|
|
117
118
|
const roles = await this.enforcer.getRolesForUser(userEntityRef);
|
|
118
119
|
if (pluginPermissionCommon.isResourcePermission(request.permission)) {
|
|
119
120
|
const resourceType = request.permission.resourceType;
|