@backstage-community/plugin-rbac-backend 6.0.1 → 6.1.1
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 +21 -0
- package/dist/admin-permissions/admin-creation.cjs.js +28 -1
- package/dist/admin-permissions/admin-creation.cjs.js.map +1 -1
- package/dist/database/role-metadata.cjs.js +10 -0
- package/dist/database/role-metadata.cjs.js.map +1 -1
- package/dist/file-permissions/csv-file-watcher.cjs.js +10 -0
- package/dist/file-permissions/csv-file-watcher.cjs.js.map +1 -1
- package/dist/helper.cjs.js +29 -3
- package/dist/helper.cjs.js.map +1 -1
- package/dist/permissions/conditions.cjs.js +15 -0
- package/dist/permissions/conditions.cjs.js.map +1 -0
- package/dist/permissions/rules.cjs.js +41 -0
- package/dist/permissions/rules.cjs.js.map +1 -0
- package/dist/policies/permission-policy.cjs.js +13 -5
- package/dist/policies/permission-policy.cjs.js.map +1 -1
- package/dist/providers/connect-providers.cjs.js +5 -0
- package/dist/providers/connect-providers.cjs.js.map +1 -1
- package/dist/service/plugin-endpoints.cjs.js +10 -0
- package/dist/service/plugin-endpoints.cjs.js.map +1 -1
- package/dist/service/policies-rest-api.cjs.js +203 -56
- package/dist/service/policies-rest-api.cjs.js.map +1 -1
- package/dist/validation/condition-validation.cjs.js +5 -0
- package/dist/validation/condition-validation.cjs.js.map +1 -1
- package/dist/validation/policies-validation.cjs.js +12 -1
- package/dist/validation/policies-validation.cjs.js.map +1 -1
- package/migrations/20250305155143_migration.js +73 -0
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
### Dependencies
|
|
2
2
|
|
|
3
|
+
## 6.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 10a0d31: Fixes an issue where the correct permission name was not selected while processing new conditional policies to be added. This scenario happens whenever a plugin exports multiple permissions that have different resource types but similar actions. What would end up happening is the first matched action would be the one selected during processing even though it was not the correct permission and used for the conditional policy. This problem has been fixed and now the correct permission name and action are selected.
|
|
8
|
+
|
|
9
|
+
## 6.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- d278b4c: Adds the ability to assign ownership to roles that can then be used to conditionally filter roles, permission policies, and conditional policies. The conditional filter can now be accomplished through the use of the new RBAC conditional rule `IS_OWNER`.
|
|
14
|
+
|
|
15
|
+
`IS_OWNER` can be used to grant limited access to the RBAC plugins where in admins might want leads to control their own team's access.
|
|
16
|
+
|
|
17
|
+
Removed the resource type from the `policy.entity.create` permission to prevent conditional rules being applied to the permission. At the moment, the plugins will still continue to work as expected. However, it is strongly recommended updating all permission policies that utilize the resource type `policy-entity` with the action `create` (ex. `role:default/some_role, policy-entity, create, allow` to `role:default/some_role, policy.entity.create, create, allow`) to prevent any future degradation in service. A migration has been supplied to automatically update all permission policies that have not originated from the CSV file. The CSV file was skipped as a duplication event could happen during reloads / restarts. This means that the CSV file will need to be updated manually to ensure that all references to the old permission policy, resource type `policy-entity` with an action of `create`, have been updated to the named permission `policy.entity.create` with an action of `create`.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [d278b4c]
|
|
22
|
+
- @backstage-community/plugin-rbac-common@1.15.0
|
|
23
|
+
|
|
3
24
|
## 6.0.1
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -110,10 +110,37 @@ const addAdminPermissions = async (policies, enf, auditor$1) => {
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
};
|
|
113
|
+
const removeOldCreateAdminPermissions = async (enf, auditor$1) => {
|
|
114
|
+
const policyEntityCreate = [
|
|
115
|
+
"role:default/rbac_admin",
|
|
116
|
+
"policy-entity",
|
|
117
|
+
"create",
|
|
118
|
+
"allow"
|
|
119
|
+
];
|
|
120
|
+
if (await enf.hasPolicy(...policyEntityCreate)) {
|
|
121
|
+
const auditorEvent = await auditor$1.createEvent({
|
|
122
|
+
eventId: auditor.PermissionEvents.POLICY_WRITE,
|
|
123
|
+
severityLevel: "medium",
|
|
124
|
+
meta: { actionType: auditor.ActionType.DELETE, source: "configuration" }
|
|
125
|
+
});
|
|
126
|
+
try {
|
|
127
|
+
await enf.removePolicy(policyEntityCreate);
|
|
128
|
+
await auditorEvent.success({
|
|
129
|
+
meta: { policy: policyEntityCreate }
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
await auditorEvent.fail({
|
|
133
|
+
error,
|
|
134
|
+
meta: { policy: policyEntityCreate }
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
113
139
|
const setAdminPermissions = async (enf, auditor) => {
|
|
140
|
+
await removeOldCreateAdminPermissions(enf, auditor);
|
|
114
141
|
const adminPermissions = [
|
|
115
142
|
[ADMIN_ROLE_NAME, "policy-entity", "read", "allow"],
|
|
116
|
-
[ADMIN_ROLE_NAME, "policy
|
|
143
|
+
[ADMIN_ROLE_NAME, "policy.entity.create", "create", "allow"],
|
|
117
144
|
[ADMIN_ROLE_NAME, "policy-entity", "delete", "allow"],
|
|
118
145
|
[ADMIN_ROLE_NAME, "policy-entity", "update", "allow"],
|
|
119
146
|
// Needed for the RBAC frontend plugin.
|
|
@@ -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 { Knex } from 'knex';\n\nimport { ActionType, PermissionEvents, RoleEvents } from '../auditor/auditor';\n\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';\nimport { AuditorService } from '@backstage/backend-plugin-api';\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 auditor: AuditorService,\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 const addedRoleMembers = Array.from<string[]>(newGroupPolicies.entries());\n const meta = {\n ...getAdminRoleMetadata(),\n members: addedRoleMembers.map(gp => gp[0]),\n };\n const auditorEvent = await auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: {\n actionType: adminRoleMeta ? ActionType.UPDATE : ActionType.CREATE,\n source: meta.source,\n },\n });\n\n const trx = await knex.transaction();\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 await enf.addGroupingPolicies(\n addedRoleMembers,\n getAdminRoleMetadata(),\n trx,\n );\n\n await trx.commit();\n await auditorEvent.success({\n meta,\n });\n } catch (error) {\n await trx.rollback(error);\n await auditorEvent.fail({\n error,\n meta,\n });\n throw error;\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 auditor,\n ADMIN_ROLE_AUTHOR,\n );\n};\n\nconst addAdminPermissions = async (\n policies: string[][],\n enf: EnforcerDelegate,\n auditor: AuditorService,\n) => {\n const policiesToAdd: string[][] = [];\n for (const policy of policies) {\n if (!(await enf.hasPolicy(...policy))) {\n policiesToAdd.push(policy);\n }\n }\n\n const auditorEvent = await auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.CREATE, source: 'configuration' },\n });\n\n try {\n await enf.addPolicies(policiesToAdd);\n await auditorEvent.success({\n meta: { policies: policiesToAdd },\n });\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { policies: policiesToAdd },\n });\n }\n};\n\nexport const setAdminPermissions = async (\n enf: EnforcerDelegate,\n auditor: AuditorService,\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, auditor);\n};\n"],"names":["auditor","validateEntityReference","RoleEvents","ActionType","removeTheDifference","PermissionEvents"],"mappings":"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"}
|
|
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 { Knex } from 'knex';\n\nimport { ActionType, PermissionEvents, RoleEvents } from '../auditor/auditor';\n\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';\nimport { AuditorService } from '@backstage/backend-plugin-api';\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 auditor: AuditorService,\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 const addedRoleMembers = Array.from<string[]>(newGroupPolicies.entries());\n const meta = {\n ...getAdminRoleMetadata(),\n members: addedRoleMembers.map(gp => gp[0]),\n };\n const auditorEvent = await auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: {\n actionType: adminRoleMeta ? ActionType.UPDATE : ActionType.CREATE,\n source: meta.source,\n },\n });\n\n const trx = await knex.transaction();\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 await enf.addGroupingPolicies(\n addedRoleMembers,\n getAdminRoleMetadata(),\n trx,\n );\n\n await trx.commit();\n await auditorEvent.success({\n meta,\n });\n } catch (error) {\n await trx.rollback(error);\n await auditorEvent.fail({\n error,\n meta,\n });\n throw error;\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 auditor,\n ADMIN_ROLE_AUTHOR,\n );\n};\n\nconst addAdminPermissions = async (\n policies: string[][],\n enf: EnforcerDelegate,\n auditor: AuditorService,\n) => {\n const policiesToAdd: string[][] = [];\n for (const policy of policies) {\n if (!(await enf.hasPolicy(...policy))) {\n policiesToAdd.push(policy);\n }\n }\n\n const auditorEvent = await auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.CREATE, source: 'configuration' },\n });\n\n try {\n await enf.addPolicies(policiesToAdd);\n await auditorEvent.success({\n meta: { policies: policiesToAdd },\n });\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { policies: policiesToAdd },\n });\n }\n};\n\nconst removeOldCreateAdminPermissions = async (\n enf: EnforcerDelegate,\n auditor: AuditorService,\n) => {\n const policyEntityCreate = [\n 'role:default/rbac_admin',\n 'policy-entity',\n 'create',\n 'allow',\n ];\n if (await enf.hasPolicy(...policyEntityCreate)) {\n const auditorEvent = await auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.DELETE, source: 'configuration' },\n });\n\n try {\n await enf.removePolicy(policyEntityCreate);\n await auditorEvent.success({\n meta: { policy: policyEntityCreate },\n });\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: { policy: policyEntityCreate },\n });\n }\n }\n};\n\nexport const setAdminPermissions = async (\n enf: EnforcerDelegate,\n auditor: AuditorService,\n) => {\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n await removeOldCreateAdminPermissions(enf, auditor);\n const adminPermissions = [\n [ADMIN_ROLE_NAME, 'policy-entity', 'read', 'allow'],\n [ADMIN_ROLE_NAME, 'policy.entity.create', '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, auditor);\n};\n"],"names":["auditor","validateEntityReference","RoleEvents","ActionType","removeTheDifference","PermissionEvents"],"mappings":"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"}
|
|
@@ -15,6 +15,15 @@ class DataBaseRoleMetadataStorage {
|
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
+
async filterForOwnerRoleMetadata(filter) {
|
|
19
|
+
const roleMetadata = await this.knex.table(ROLE_METADATA_TABLE);
|
|
20
|
+
if (filter) {
|
|
21
|
+
return roleMetadata.filter((role) => {
|
|
22
|
+
return helper.matches(role, filter);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return roleMetadata;
|
|
26
|
+
}
|
|
18
27
|
async findRoleMetadata(roleEntityRef, trx) {
|
|
19
28
|
const db = trx || this.knex;
|
|
20
29
|
return await db.table(ROLE_METADATA_TABLE).where("roleEntityRef", roleEntityRef).first();
|
|
@@ -76,6 +85,7 @@ function daoToMetadata(dao) {
|
|
|
76
85
|
return {
|
|
77
86
|
source: dao.source,
|
|
78
87
|
description: dao.description,
|
|
88
|
+
owner: dao.owner,
|
|
79
89
|
author: dao.author,
|
|
80
90
|
modifiedBy: dao.modifiedBy,
|
|
81
91
|
createdAt: dao.createdAt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-metadata.cjs.js","sources":["../../src/database/role-metadata.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ConflictError, InputError, NotFoundError } from '@backstage/errors';\n\nimport { Knex } from 'knex';\n\nimport type {\n RoleMetadata,\n Source,\n} from '@backstage-community/plugin-rbac-common';\n\nimport { deepSortedEqual } from '../helper';\n\nexport const ROLE_METADATA_TABLE = 'role-metadata';\n\nexport interface RoleMetadataDao extends RoleMetadata {\n id?: number;\n roleEntityRef: string;\n source: Source;\n modifiedBy: string;\n}\n\nexport interface RoleMetadataStorage {\n filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]>;\n findRoleMetadata(\n roleEntityRef: string,\n trx?: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined>;\n createRoleMetadata(\n roleMetadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number>;\n updateRoleMetadata(\n roleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void>;\n removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void>;\n}\n\nexport class DataBaseRoleMetadataStorage implements RoleMetadataStorage {\n constructor(private readonly knex: Knex<any, any[]>) {}\n\n async filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]> {\n return await this.knex.table(ROLE_METADATA_TABLE).where(builder => {\n if (source) {\n builder.where('source', source);\n }\n });\n }\n\n async findRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined> {\n const db = trx || this.knex;\n return await db\n .table(ROLE_METADATA_TABLE)\n .where('roleEntityRef', roleEntityRef)\n // roleEntityRef should be unique.\n .first();\n }\n\n async createRoleMetadata(\n metadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number> {\n if (await this.findRoleMetadata(metadata.roleEntityRef, trx)) {\n throw new ConflictError(\n `A metadata for role ${metadata.roleEntityRef} has already been stored`,\n );\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .insert(metadata)\n .returning<[{ id: number }]>('id');\n if (result && result?.length > 0) {\n return result[0].id;\n }\n\n throw new Error(\n `Failed to create the role metadata: '${JSON.stringify(metadata)}'.`,\n );\n }\n\n async updateRoleMetadata(\n newRoleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n const currentMetadataDao = await this.findRoleMetadata(\n oldRoleEntityRef,\n trx,\n );\n\n if (!currentMetadataDao) {\n throw new NotFoundError(\n `A metadata for role '${oldRoleEntityRef}' was not found`,\n );\n }\n\n if (\n currentMetadataDao.source !== 'legacy' &&\n currentMetadataDao.source !== newRoleMetadata.source\n ) {\n throw new InputError(`The RoleMetadata.source field is 'read-only'.`);\n }\n\n if (deepSortedEqual(currentMetadataDao, newRoleMetadata)) {\n return;\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .where('id', currentMetadataDao.id)\n .update(newRoleMetadata)\n .returning('id');\n\n if (!externalTrx) {\n await trx.commit();\n }\n\n if (!result || result.length === 0) {\n throw new Error(\n `Failed to update the role metadata '${JSON.stringify(\n currentMetadataDao,\n )}' with new value: '${JSON.stringify(newRoleMetadata)}'.`,\n );\n }\n }\n\n async removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void> {\n const metadataDao = await this.findRoleMetadata(roleEntityRef, trx);\n if (!metadataDao) {\n throw new NotFoundError(\n `A metadata for role '${roleEntityRef}' was not found`,\n );\n }\n\n await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .delete()\n .whereIn('id', [metadataDao.id!]);\n }\n}\n\nexport function daoToMetadata(dao: RoleMetadataDao): RoleMetadata {\n return {\n source: dao.source,\n description: dao.description,\n author: dao.author,\n modifiedBy: dao.modifiedBy,\n createdAt: dao.createdAt,\n lastModified: dao.lastModified,\n };\n}\n"],"names":["ConflictError","NotFoundError","InputError","deepSortedEqual"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"role-metadata.cjs.js","sources":["../../src/database/role-metadata.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ConflictError, InputError, NotFoundError } from '@backstage/errors';\n\nimport { Knex } from 'knex';\n\nimport type {\n RoleMetadata,\n Source,\n} from '@backstage-community/plugin-rbac-common';\n\nimport { deepSortedEqual } from '../helper';\nimport { RBACFilters } from '../permissions';\nimport { matches } from '../helper';\n\nexport const ROLE_METADATA_TABLE = 'role-metadata';\n\nexport interface RoleMetadataDao extends RoleMetadata {\n id?: number;\n roleEntityRef: string;\n source: Source;\n modifiedBy: string;\n}\n\nexport interface RoleMetadataStorage {\n filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]>;\n filterForOwnerRoleMetadata(filter?: RBACFilters): Promise<RoleMetadataDao[]>;\n findRoleMetadata(\n roleEntityRef: string,\n trx?: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined>;\n createRoleMetadata(\n roleMetadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number>;\n updateRoleMetadata(\n roleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void>;\n removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void>;\n}\n\nexport class DataBaseRoleMetadataStorage implements RoleMetadataStorage {\n constructor(private readonly knex: Knex<any, any[]>) {}\n\n async filterRoleMetadata(source?: Source): Promise<RoleMetadataDao[]> {\n return await this.knex.table(ROLE_METADATA_TABLE).where(builder => {\n if (source) {\n builder.where('source', source);\n }\n });\n }\n\n async filterForOwnerRoleMetadata(\n filter?: RBACFilters,\n ): Promise<RoleMetadataDao[]> {\n const roleMetadata: RoleMetadataDao[] =\n await this.knex.table(ROLE_METADATA_TABLE);\n\n if (filter) {\n return roleMetadata.filter(role => {\n return matches(role as RoleMetadata, filter);\n });\n }\n\n return roleMetadata;\n }\n\n async findRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<RoleMetadataDao | undefined> {\n const db = trx || this.knex;\n return await db\n .table(ROLE_METADATA_TABLE)\n .where('roleEntityRef', roleEntityRef)\n // roleEntityRef should be unique.\n .first();\n }\n\n async createRoleMetadata(\n metadata: RoleMetadataDao,\n trx: Knex.Transaction,\n ): Promise<number> {\n if (await this.findRoleMetadata(metadata.roleEntityRef, trx)) {\n throw new ConflictError(\n `A metadata for role ${metadata.roleEntityRef} has already been stored`,\n );\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .insert(metadata)\n .returning<[{ id: number }]>('id');\n if (result && result?.length > 0) {\n return result[0].id;\n }\n\n throw new Error(\n `Failed to create the role metadata: '${JSON.stringify(metadata)}'.`,\n );\n }\n\n async updateRoleMetadata(\n newRoleMetadata: RoleMetadataDao,\n oldRoleEntityRef: string,\n externalTrx?: Knex.Transaction,\n ): Promise<void> {\n const trx = externalTrx ?? (await this.knex.transaction());\n const currentMetadataDao = await this.findRoleMetadata(\n oldRoleEntityRef,\n trx,\n );\n\n if (!currentMetadataDao) {\n throw new NotFoundError(\n `A metadata for role '${oldRoleEntityRef}' was not found`,\n );\n }\n\n if (\n currentMetadataDao.source !== 'legacy' &&\n currentMetadataDao.source !== newRoleMetadata.source\n ) {\n throw new InputError(`The RoleMetadata.source field is 'read-only'.`);\n }\n\n if (deepSortedEqual(currentMetadataDao, newRoleMetadata)) {\n return;\n }\n\n const result = await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .where('id', currentMetadataDao.id)\n .update(newRoleMetadata)\n .returning('id');\n\n if (!externalTrx) {\n await trx.commit();\n }\n\n if (!result || result.length === 0) {\n throw new Error(\n `Failed to update the role metadata '${JSON.stringify(\n currentMetadataDao,\n )}' with new value: '${JSON.stringify(newRoleMetadata)}'.`,\n );\n }\n }\n\n async removeRoleMetadata(\n roleEntityRef: string,\n trx: Knex.Transaction,\n ): Promise<void> {\n const metadataDao = await this.findRoleMetadata(roleEntityRef, trx);\n if (!metadataDao) {\n throw new NotFoundError(\n `A metadata for role '${roleEntityRef}' was not found`,\n );\n }\n\n await trx<RoleMetadataDao>(ROLE_METADATA_TABLE)\n .delete()\n .whereIn('id', [metadataDao.id!]);\n }\n}\n\nexport function daoToMetadata(dao: RoleMetadataDao): RoleMetadata {\n return {\n source: dao.source,\n description: dao.description,\n owner: dao.owner,\n author: dao.author,\n modifiedBy: dao.modifiedBy,\n createdAt: dao.createdAt,\n lastModified: dao.lastModified,\n };\n}\n"],"names":["matches","ConflictError","NotFoundError","InputError","deepSortedEqual"],"mappings":"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"}
|
|
@@ -344,6 +344,11 @@ class CSVFileWatcher extends fileWatcher.AbstractFileWatcher {
|
|
|
344
344
|
)) {
|
|
345
345
|
policies.push(policy);
|
|
346
346
|
}
|
|
347
|
+
if (policy[1] === "policy-entity" && policy[2] === "create" && !remove) {
|
|
348
|
+
this.logger.warn(
|
|
349
|
+
`Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${policy} to use 'policy.entity.create' instead of 'policy-entity' from source csv-file`
|
|
350
|
+
);
|
|
351
|
+
}
|
|
347
352
|
}
|
|
348
353
|
for (const groupPolicy of groupPoliciesToEdit) {
|
|
349
354
|
if (!await enforcerTwo.hasGroupingPolicy(...groupPolicy) && await this.validateAddedGroupPolicy(
|
|
@@ -434,6 +439,11 @@ class CSVFileWatcher extends fileWatcher.AbstractFileWatcher {
|
|
|
434
439
|
convertedPolicy.splice(0, 1);
|
|
435
440
|
if (await this.validateAddedPolicy(convertedPolicy, tempEnforcer))
|
|
436
441
|
this.csvFilePolicies.addedPolicies.push(convertedPolicy);
|
|
442
|
+
if (convertedPolicy[1] === "policy-entity" && convertedPolicy[2] === "create") {
|
|
443
|
+
this.logger.warn(
|
|
444
|
+
`Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${convertedPolicy} to use 'policy.entity.create' instead of 'policy-entity' from source csv-file`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
437
447
|
} else if (convertedPolicy[0] === "g") {
|
|
438
448
|
convertedPolicy.splice(0, 1);
|
|
439
449
|
if (await this.validateAddedGroupPolicy(convertedPolicy, tempEnforcer))
|
|
@@ -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 {\n AuditorService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\nimport { Enforcer, newEnforcer, newModelFromString } from 'casbin';\nimport { parse } from 'csv-parse/sync';\nimport { difference } from 'lodash';\n\nimport { ActionType, PermissionEvents, RoleEvents } from '../auditor/auditor';\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 removedPolicies: string[][];\n addedGroupPolicies: Map<string, string[]>;\n removedGroupPolicies: Map<string, 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 auditor: AuditorService,\n ) {\n super(filePath, allowReload, logger);\n this.currentContent = [];\n this.csvFilePolicies = {\n addedPolicies: [],\n removedPolicies: [],\n addedGroupPolicies: new Map<string, string[]>(),\n removedGroupPolicies: new Map<string, string[]>(),\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.filterPoliciesAndRoles(\n this.enforcer,\n tempEnforcer,\n this.csvFilePolicies.removedPolicies,\n this.csvFilePolicies.removedGroupPolicies,\n true,\n );\n\n await this.filterPoliciesAndRoles(\n tempEnforcer,\n this.enforcer,\n this.csvFilePolicies.addedPolicies,\n this.csvFilePolicies.addedGroupPolicies,\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);\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 await this.findFileContentDiff(\n currentFlatContent,\n newFlatContent,\n tempEnforcer,\n );\n\n await this.updatePolicies(newContent);\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 */\n private async updatePolicies(newContent: string[][]): Promise<void> {\n this.currentContent = newContent;\n\n if (this.csvFilePolicies.addedPolicies.length > 0)\n await this.addPermissionPolicies();\n if (this.csvFilePolicies.removedPolicies.length > 0)\n await this.removePermissionPolicies();\n if (this.csvFilePolicies.addedGroupPolicies.size > 0) await this.addRoles();\n if (this.csvFilePolicies.removedGroupPolicies.size > 0)\n await this.removeRoles();\n }\n\n /**\n * addPermissionPolicies will add the new permission policies that are present in the CSV file.\n */\n private async addPermissionPolicies(): Promise<void> {\n const auditorEvent = await this.auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.CREATE, source: 'csv-file' },\n });\n\n try {\n await this.enforcer.addPolicies(this.csvFilePolicies.addedPolicies);\n await auditorEvent.success({\n meta: { policies: this.csvFilePolicies.addedPolicies },\n });\n } catch (e) {\n await auditorEvent.fail({\n meta: { policies: this.csvFilePolicies.addedPolicies },\n error: e,\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 const auditorEvent = await this.auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.DELETE, source: 'csv-file' },\n });\n\n try {\n await this.enforcer.removePolicies(this.csvFilePolicies.removedPolicies);\n await auditorEvent.success({\n meta: { policies: this.csvFilePolicies.removedPolicies },\n });\n } catch (e) {\n await auditorEvent.fail({\n meta: { policies: this.csvFilePolicies.removedPolicies },\n error: e,\n });\n }\n\n this.csvFilePolicies.removedPolicies = [];\n }\n\n /**\n * addRoles will add the new roles that are present in the CSV file.\n */\n private async addRoles(): Promise<void> {\n const changedPolicies: {\n addedPolicies: string[][];\n updatedPolicies: string[][];\n failedPolicies: { error: string; policies: string[][] }[];\n } = {\n addedPolicies: [],\n updatedPolicies: [],\n failedPolicies: [],\n };\n\n const auditorEvent = await this.auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.CREATE_OR_UPDATE, source: 'csv-file' },\n });\n\n for (const [key, value] of this.csvFilePolicies.addedGroupPolicies) {\n const groupPolicies = value.map(member => {\n return [member, key];\n });\n\n const roleMetadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef: key,\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n\n try {\n const currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n roleMetadata.roleEntityRef,\n );\n\n await this.enforcer.addGroupingPolicies(groupPolicies, roleMetadata);\n\n if (currentMetadata) {\n changedPolicies.updatedPolicies.push(...groupPolicies);\n } else {\n changedPolicies.addedPolicies.push(...groupPolicies);\n }\n } catch (e) {\n changedPolicies.failedPolicies.push({\n error: e,\n policies: groupPolicies,\n });\n }\n }\n\n if (changedPolicies.failedPolicies.length > 0) {\n await auditorEvent.fail({\n error: new Error(\n `Failed to add or update group policies after modification ${this.filePath}.`,\n ),\n meta: { ...changedPolicies },\n });\n } else {\n await auditorEvent.success({\n meta: {\n addedPolicies: changedPolicies.addedPolicies,\n updatedPolicies: changedPolicies.updatedPolicies,\n },\n });\n }\n\n this.csvFilePolicies.addedGroupPolicies = new Map<string, string[]>();\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 [key, value] of this.csvFilePolicies.removedGroupPolicies) {\n // This requires knowledge of whether or not it is an update\n const oldGroupingPolicies = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n key,\n );\n const groupPolicies = value.map(member => {\n return [member, key];\n });\n\n const roleMetadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef: key,\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n const isUpdate =\n oldGroupingPolicies.length > 1 &&\n oldGroupingPolicies.length !== groupPolicies.length;\n const actionType = isUpdate ? ActionType.UPDATE : ActionType.DELETE;\n\n const meta = {\n ...roleMetadata,\n members: value,\n };\n const auditorEvent = await this.auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: { actionType, source: meta.source },\n });\n\n try {\n await this.enforcer.removeGroupingPolicies(\n groupPolicies,\n roleMetadata,\n isUpdate,\n );\n await auditorEvent.success({ meta });\n } catch (e) {\n await auditorEvent.fail({\n meta,\n error: e,\n });\n }\n }\n\n this.csvFilePolicies.removedGroupPolicies = new Map<string, string[]>();\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 const filteredPolicies = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n fileRole,\n );\n for (const groupPolicy of filteredPolicies) {\n this.addGroupPolicyToMap(\n this.csvFilePolicies.removedGroupPolicies,\n groupPolicy[1],\n groupPolicy[0],\n );\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 async filterPoliciesAndRoles(\n enforcerOne: Enforcer | EnforcerDelegate,\n enforcerTwo: Enforcer | EnforcerDelegate,\n policies: string[][],\n groupPolicies: Map<string, string[]>,\n remove?: boolean,\n ) {\n // Check for any policies that need to be edited by comparing policies from\n // one enforcer to the other\n const policiesToEdit = await enforcerOne.getPolicy();\n const groupPoliciesToEdit = await enforcerOne.getGroupingPolicy();\n\n for (const policy of policiesToEdit) {\n if (\n !(await enforcerTwo.hasPolicy(...policy)) &&\n (await this.validateAddedPolicy(\n policy,\n enforcerOne as Enforcer,\n remove,\n ))\n ) {\n policies.push(policy);\n }\n }\n\n for (const groupPolicy of groupPoliciesToEdit) {\n if (\n !(await enforcerTwo.hasGroupingPolicy(...groupPolicy)) &&\n (await this.validateAddedGroupPolicy(\n groupPolicy,\n enforcerOne as Enforcer,\n remove,\n ))\n ) {\n this.addGroupPolicyToMap(groupPolicies, groupPolicy[1], groupPolicy[0]);\n }\n }\n }\n\n async validateAddedPolicy(\n policy: string[],\n tempEnforcer: Enforcer,\n remove?: boolean,\n ): Promise<boolean> {\n const transformedPolicy = transformArrayToPolicy(policy);\n const metadata = await this.roleMetadataStorage.findRoleMetadata(policy[0]);\n\n if (remove) {\n return metadata?.source === 'csv-file';\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 return false;\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 return false;\n }\n\n err = await checkForDuplicatePolicies(tempEnforcer, policy, this.filePath!);\n if (err) {\n this.logger.warn(err.message);\n return false;\n }\n\n return true;\n }\n\n async validateAddedGroupPolicy(\n groupPolicy: string[],\n tempEnforcer: Enforcer,\n remove?: boolean,\n ): Promise<boolean> {\n const metadata = await this.roleMetadataStorage.findRoleMetadata(\n groupPolicy[1],\n );\n\n if (remove) {\n return metadata?.source === 'csv-file';\n }\n\n let err = await validateGroupingPolicy(groupPolicy, metadata, 'csv-file');\n if (err) {\n this.logger.warn(\n `${err.message}, error originates from file ${this.filePath}`,\n );\n return false;\n }\n\n err = await checkForDuplicateGroupPolicies(\n tempEnforcer,\n groupPolicy,\n this.filePath!,\n );\n if (err) {\n this.logger.warn(err.message);\n return false;\n }\n\n return true;\n }\n\n async findFileContentDiff(\n currentFlatContent: string[],\n newFlatContent: string[],\n tempEnforcer: Enforcer,\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.addGroupPolicyToMap(\n this.csvFilePolicies.removedGroupPolicies,\n convertedPolicy[1],\n convertedPolicy[0],\n );\n }\n });\n\n for (const policy of diffAdded) {\n const convertedPolicy = metadataStringToPolicy(policy);\n if (convertedPolicy[0] === 'p') {\n convertedPolicy.splice(0, 1);\n if (await this.validateAddedPolicy(convertedPolicy, tempEnforcer))\n this.csvFilePolicies.addedPolicies.push(convertedPolicy);\n } else if (convertedPolicy[0] === 'g') {\n convertedPolicy.splice(0, 1);\n if (await this.validateAddedGroupPolicy(convertedPolicy, tempEnforcer))\n this.addGroupPolicyToMap(\n this.csvFilePolicies.addedGroupPolicies,\n convertedPolicy[1],\n convertedPolicy[0],\n );\n }\n }\n }\n\n addGroupPolicyToMap(\n groupPolicyMap: Map<string, string[]>,\n key: string,\n value: string,\n ) {\n if (!groupPolicyMap.has(key)) {\n groupPolicyMap.set(key, []);\n }\n groupPolicyMap.get(key)?.push(value);\n }\n}\n"],"names":["AbstractFileWatcher","parse","transformPolicyGroupToLowercase","newEnforcer","newModelFromString","MODEL","LowercaseFileAdapter","mergeRoleMetadata","policyToString","PermissionEvents","ActionType","RoleEvents","transformArrayToPolicy","validatePolicy","validateSource","checkForDuplicatePolicies","validateGroupingPolicy","checkForDuplicateGroupPolicies","difference","metadataStringToPolicy"],"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 {\n AuditorService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\nimport { Enforcer, newEnforcer, newModelFromString } from 'casbin';\nimport { parse } from 'csv-parse/sync';\nimport { difference } from 'lodash';\n\nimport { ActionType, PermissionEvents, RoleEvents } from '../auditor/auditor';\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 removedPolicies: string[][];\n addedGroupPolicies: Map<string, string[]>;\n removedGroupPolicies: Map<string, 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 auditor: AuditorService,\n ) {\n super(filePath, allowReload, logger);\n this.currentContent = [];\n this.csvFilePolicies = {\n addedPolicies: [],\n removedPolicies: [],\n addedGroupPolicies: new Map<string, string[]>(),\n removedGroupPolicies: new Map<string, string[]>(),\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.filterPoliciesAndRoles(\n this.enforcer,\n tempEnforcer,\n this.csvFilePolicies.removedPolicies,\n this.csvFilePolicies.removedGroupPolicies,\n true,\n );\n\n await this.filterPoliciesAndRoles(\n tempEnforcer,\n this.enforcer,\n this.csvFilePolicies.addedPolicies,\n this.csvFilePolicies.addedGroupPolicies,\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);\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 await this.findFileContentDiff(\n currentFlatContent,\n newFlatContent,\n tempEnforcer,\n );\n\n await this.updatePolicies(newContent);\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 */\n private async updatePolicies(newContent: string[][]): Promise<void> {\n this.currentContent = newContent;\n\n if (this.csvFilePolicies.addedPolicies.length > 0)\n await this.addPermissionPolicies();\n if (this.csvFilePolicies.removedPolicies.length > 0)\n await this.removePermissionPolicies();\n if (this.csvFilePolicies.addedGroupPolicies.size > 0) await this.addRoles();\n if (this.csvFilePolicies.removedGroupPolicies.size > 0)\n await this.removeRoles();\n }\n\n /**\n * addPermissionPolicies will add the new permission policies that are present in the CSV file.\n */\n private async addPermissionPolicies(): Promise<void> {\n const auditorEvent = await this.auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.CREATE, source: 'csv-file' },\n });\n\n try {\n await this.enforcer.addPolicies(this.csvFilePolicies.addedPolicies);\n await auditorEvent.success({\n meta: { policies: this.csvFilePolicies.addedPolicies },\n });\n } catch (e) {\n await auditorEvent.fail({\n meta: { policies: this.csvFilePolicies.addedPolicies },\n error: e,\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 const auditorEvent = await this.auditor.createEvent({\n eventId: PermissionEvents.POLICY_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.DELETE, source: 'csv-file' },\n });\n\n try {\n await this.enforcer.removePolicies(this.csvFilePolicies.removedPolicies);\n await auditorEvent.success({\n meta: { policies: this.csvFilePolicies.removedPolicies },\n });\n } catch (e) {\n await auditorEvent.fail({\n meta: { policies: this.csvFilePolicies.removedPolicies },\n error: e,\n });\n }\n\n this.csvFilePolicies.removedPolicies = [];\n }\n\n /**\n * addRoles will add the new roles that are present in the CSV file.\n */\n private async addRoles(): Promise<void> {\n const changedPolicies: {\n addedPolicies: string[][];\n updatedPolicies: string[][];\n failedPolicies: { error: string; policies: string[][] }[];\n } = {\n addedPolicies: [],\n updatedPolicies: [],\n failedPolicies: [],\n };\n\n const auditorEvent = await this.auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: { actionType: ActionType.CREATE_OR_UPDATE, source: 'csv-file' },\n });\n\n for (const [key, value] of this.csvFilePolicies.addedGroupPolicies) {\n const groupPolicies = value.map(member => {\n return [member, key];\n });\n\n const roleMetadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef: key,\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n\n try {\n const currentMetadata = await this.roleMetadataStorage.findRoleMetadata(\n roleMetadata.roleEntityRef,\n );\n\n await this.enforcer.addGroupingPolicies(groupPolicies, roleMetadata);\n\n if (currentMetadata) {\n changedPolicies.updatedPolicies.push(...groupPolicies);\n } else {\n changedPolicies.addedPolicies.push(...groupPolicies);\n }\n } catch (e) {\n changedPolicies.failedPolicies.push({\n error: e,\n policies: groupPolicies,\n });\n }\n }\n\n if (changedPolicies.failedPolicies.length > 0) {\n await auditorEvent.fail({\n error: new Error(\n `Failed to add or update group policies after modification ${this.filePath}.`,\n ),\n meta: { ...changedPolicies },\n });\n } else {\n await auditorEvent.success({\n meta: {\n addedPolicies: changedPolicies.addedPolicies,\n updatedPolicies: changedPolicies.updatedPolicies,\n },\n });\n }\n\n this.csvFilePolicies.addedGroupPolicies = new Map<string, string[]>();\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 [key, value] of this.csvFilePolicies.removedGroupPolicies) {\n // This requires knowledge of whether or not it is an update\n const oldGroupingPolicies = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n key,\n );\n const groupPolicies = value.map(member => {\n return [member, key];\n });\n\n const roleMetadata: RoleMetadataDao = {\n source: 'csv-file',\n roleEntityRef: key,\n author: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n modifiedBy: CSV_PERMISSION_POLICY_FILE_AUTHOR,\n };\n const isUpdate =\n oldGroupingPolicies.length > 1 &&\n oldGroupingPolicies.length !== groupPolicies.length;\n const actionType = isUpdate ? ActionType.UPDATE : ActionType.DELETE;\n\n const meta = {\n ...roleMetadata,\n members: value,\n };\n const auditorEvent = await this.auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: { actionType, source: meta.source },\n });\n\n try {\n await this.enforcer.removeGroupingPolicies(\n groupPolicies,\n roleMetadata,\n isUpdate,\n );\n await auditorEvent.success({ meta });\n } catch (e) {\n await auditorEvent.fail({\n meta,\n error: e,\n });\n }\n }\n\n this.csvFilePolicies.removedGroupPolicies = new Map<string, string[]>();\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 const filteredPolicies = await this.enforcer.getFilteredGroupingPolicy(\n 1,\n fileRole,\n );\n for (const groupPolicy of filteredPolicies) {\n this.addGroupPolicyToMap(\n this.csvFilePolicies.removedGroupPolicies,\n groupPolicy[1],\n groupPolicy[0],\n );\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 async filterPoliciesAndRoles(\n enforcerOne: Enforcer | EnforcerDelegate,\n enforcerTwo: Enforcer | EnforcerDelegate,\n policies: string[][],\n groupPolicies: Map<string, string[]>,\n remove?: boolean,\n ) {\n // Check for any policies that need to be edited by comparing policies from\n // one enforcer to the other\n const policiesToEdit = await enforcerOne.getPolicy();\n const groupPoliciesToEdit = await enforcerOne.getGroupingPolicy();\n\n for (const policy of policiesToEdit) {\n if (\n !(await enforcerTwo.hasPolicy(...policy)) &&\n (await this.validateAddedPolicy(\n policy,\n enforcerOne as Enforcer,\n remove,\n ))\n ) {\n policies.push(policy);\n }\n\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n if (policy[1] === 'policy-entity' && policy[2] === 'create' && !remove) {\n this.logger.warn(\n `Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${policy} to use 'policy.entity.create' instead of 'policy-entity' from source csv-file`,\n );\n }\n }\n\n for (const groupPolicy of groupPoliciesToEdit) {\n if (\n !(await enforcerTwo.hasGroupingPolicy(...groupPolicy)) &&\n (await this.validateAddedGroupPolicy(\n groupPolicy,\n enforcerOne as Enforcer,\n remove,\n ))\n ) {\n this.addGroupPolicyToMap(groupPolicies, groupPolicy[1], groupPolicy[0]);\n }\n }\n }\n\n async validateAddedPolicy(\n policy: string[],\n tempEnforcer: Enforcer,\n remove?: boolean,\n ): Promise<boolean> {\n const transformedPolicy = transformArrayToPolicy(policy);\n const metadata = await this.roleMetadataStorage.findRoleMetadata(policy[0]);\n\n if (remove) {\n return metadata?.source === 'csv-file';\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 return false;\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 return false;\n }\n\n err = await checkForDuplicatePolicies(tempEnforcer, policy, this.filePath!);\n if (err) {\n this.logger.warn(err.message);\n return false;\n }\n\n return true;\n }\n\n async validateAddedGroupPolicy(\n groupPolicy: string[],\n tempEnforcer: Enforcer,\n remove?: boolean,\n ): Promise<boolean> {\n const metadata = await this.roleMetadataStorage.findRoleMetadata(\n groupPolicy[1],\n );\n\n if (remove) {\n return metadata?.source === 'csv-file';\n }\n\n let err = await validateGroupingPolicy(groupPolicy, metadata, 'csv-file');\n if (err) {\n this.logger.warn(\n `${err.message}, error originates from file ${this.filePath}`,\n );\n return false;\n }\n\n err = await checkForDuplicateGroupPolicies(\n tempEnforcer,\n groupPolicy,\n this.filePath!,\n );\n if (err) {\n this.logger.warn(err.message);\n return false;\n }\n\n return true;\n }\n\n async findFileContentDiff(\n currentFlatContent: string[],\n newFlatContent: string[],\n tempEnforcer: Enforcer,\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.addGroupPolicyToMap(\n this.csvFilePolicies.removedGroupPolicies,\n convertedPolicy[1],\n convertedPolicy[0],\n );\n }\n });\n\n for (const policy of diffAdded) {\n const convertedPolicy = metadataStringToPolicy(policy);\n if (convertedPolicy[0] === 'p') {\n convertedPolicy.splice(0, 1);\n if (await this.validateAddedPolicy(convertedPolicy, tempEnforcer))\n this.csvFilePolicies.addedPolicies.push(convertedPolicy);\n\n // TODO: Temporary workaround to prevent breakages after the removal of the resource type `policy-entity` from the permission `policy.entity.create`\n if (\n convertedPolicy[1] === 'policy-entity' &&\n convertedPolicy[2] === 'create'\n ) {\n this.logger.warn(\n `Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${convertedPolicy} to use 'policy.entity.create' instead of 'policy-entity' from source csv-file`,\n );\n }\n } else if (convertedPolicy[0] === 'g') {\n convertedPolicy.splice(0, 1);\n if (await this.validateAddedGroupPolicy(convertedPolicy, tempEnforcer))\n this.addGroupPolicyToMap(\n this.csvFilePolicies.addedGroupPolicies,\n convertedPolicy[1],\n convertedPolicy[0],\n );\n }\n }\n }\n\n addGroupPolicyToMap(\n groupPolicyMap: Map<string, string[]>,\n key: string,\n value: string,\n ) {\n if (!groupPolicyMap.has(key)) {\n groupPolicyMap.set(key, []);\n }\n groupPolicyMap.get(key)?.push(value);\n }\n}\n"],"names":["AbstractFileWatcher","parse","transformPolicyGroupToLowercase","newEnforcer","newModelFromString","MODEL","LowercaseFileAdapter","mergeRoleMetadata","policyToString","PermissionEvents","ActionType","RoleEvents","transformArrayToPolicy","validatePolicy","validateSource","checkForDuplicatePolicies","validateGroupingPolicy","checkForDuplicateGroupPolicies","difference","metadataStringToPolicy"],"mappings":"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"}
|
package/dist/helper.cjs.js
CHANGED
|
@@ -117,6 +117,7 @@ function mergeRoleMetadata(currentMetadata, newMetadata) {
|
|
|
117
117
|
mergedMetaData.description = newMetadata.description ?? currentMetadata.description;
|
|
118
118
|
mergedMetaData.roleEntityRef = newMetadata.roleEntityRef;
|
|
119
119
|
mergedMetaData.source = newMetadata.source;
|
|
120
|
+
mergedMetaData.owner = newMetadata.owner ?? currentMetadata.owner;
|
|
120
121
|
return mergedMetaData;
|
|
121
122
|
}
|
|
122
123
|
async function processConditionMapping(roleConditionPolicy, pluginPermMetaData, auth) {
|
|
@@ -135,9 +136,15 @@ async function processConditionMapping(roleConditionPolicy, pluginPermMetaData,
|
|
|
135
136
|
}
|
|
136
137
|
const permInfo = [];
|
|
137
138
|
for (const action of roleConditionPolicy.permissionMapping) {
|
|
138
|
-
const perm = rule.permissions.find(
|
|
139
|
-
(permission
|
|
140
|
-
|
|
139
|
+
const perm = rule.permissions.find((permission) => {
|
|
140
|
+
if (permission.type === "resource") {
|
|
141
|
+
const isCorrectResourceType = permission.resourceType === roleConditionPolicy.resourceType;
|
|
142
|
+
const isCorrectAction = action === permission.attributes.action;
|
|
143
|
+
const undefinedAction = action === "use" && permission.attributes.action === undefined;
|
|
144
|
+
return isCorrectResourceType && (isCorrectAction || undefinedAction);
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
});
|
|
141
148
|
if (!perm) {
|
|
142
149
|
throw new Error(
|
|
143
150
|
`Unable to find permission to get permission name for resource type '${roleConditionPolicy.resourceType}' and action ${JSON.stringify(action)}`
|
|
@@ -166,12 +173,31 @@ function deepSort(value) {
|
|
|
166
173
|
function deepSortEqual(obj1, obj2) {
|
|
167
174
|
return lodash.isEqual(deepSort(obj1), deepSort(obj2));
|
|
168
175
|
}
|
|
176
|
+
const matches = (role, filters) => {
|
|
177
|
+
if (!filters) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
if (!role) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
if ("allOf" in filters) {
|
|
184
|
+
return filters.allOf.every((filter) => matches(role, filter));
|
|
185
|
+
}
|
|
186
|
+
if ("anyOf" in filters) {
|
|
187
|
+
return filters.anyOf.some((filter) => matches(role, filter));
|
|
188
|
+
}
|
|
189
|
+
if ("not" in filters) {
|
|
190
|
+
return !matches(role, filters.not);
|
|
191
|
+
}
|
|
192
|
+
return filters.values.includes(role.owner);
|
|
193
|
+
};
|
|
169
194
|
|
|
170
195
|
exports.buildRoleSourceMap = buildRoleSourceMap;
|
|
171
196
|
exports.deepSort = deepSort;
|
|
172
197
|
exports.deepSortEqual = deepSortEqual;
|
|
173
198
|
exports.deepSortedEqual = deepSortedEqual;
|
|
174
199
|
exports.isPermissionAction = isPermissionAction;
|
|
200
|
+
exports.matches = matches;
|
|
175
201
|
exports.mergeRoleMetadata = mergeRoleMetadata;
|
|
176
202
|
exports.metadataStringToPolicy = metadataStringToPolicy;
|
|
177
203
|
exports.policiesToString = policiesToString;
|
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 { AuditorService, AuthService } from '@backstage/backend-plugin-api';\nimport type { MetadataResponse } from '@backstage/plugin-permission-node';\n\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 { ActionType, RoleEvents } from './auditor/auditor';\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 auditor: AuditorService,\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 const existingMembers = await enf.getFilteredGroupingPolicy(1, roleEntityRef);\n const actionType =\n existingMembers.length === missing.length\n ? ActionType.DELETE\n : ActionType.UPDATE;\n const auditorMeta = {\n ...roleMetadata,\n members: groupPolicies.map(gp => gp[0]),\n };\n const auditorEvent = await auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: { actionType, source: auditorMeta.source },\n });\n\n try {\n await enf.removeGroupingPolicies(groupPolicies, roleMetadata, false);\n await auditorEvent.success({ meta: auditorMeta });\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: auditorMeta,\n });\n throw error;\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":["auditor","difference","ActionType","RoleEvents","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 { AuditorService, AuthService } from '@backstage/backend-plugin-api';\nimport type { MetadataResponse } from '@backstage/plugin-permission-node';\n\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 { ActionType, RoleEvents } from './auditor/auditor';\nimport { RoleMetadataDao, RoleMetadataStorage } from './database/role-metadata';\nimport { EnforcerDelegate } from './service/enforcer-delegate';\nimport { PluginPermissionMetadataCollector } from './service/plugin-endpoints';\nimport { RoleMetadata } from '@backstage-community/plugin-rbac-common';\nimport { RBACFilters } from './permissions';\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 auditor: AuditorService,\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 const existingMembers = await enf.getFilteredGroupingPolicy(1, roleEntityRef);\n const actionType =\n existingMembers.length === missing.length\n ? ActionType.DELETE\n : ActionType.UPDATE;\n const auditorMeta = {\n ...roleMetadata,\n members: groupPolicies.map(gp => gp[0]),\n };\n const auditorEvent = await auditor.createEvent({\n eventId: RoleEvents.ROLE_WRITE,\n severityLevel: 'medium',\n meta: { actionType, source: auditorMeta.source },\n });\n\n try {\n await enf.removeGroupingPolicies(groupPolicies, roleMetadata, false);\n await auditorEvent.success({ meta: auditorMeta });\n } catch (error) {\n await auditorEvent.fail({\n error,\n meta: auditorMeta,\n });\n throw error;\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 mergedMetaData.owner = newMetadata.owner ?? currentMetadata.owner;\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(permission => {\n if (permission.type === 'resource') {\n const isCorrectResourceType =\n permission.resourceType === roleConditionPolicy.resourceType;\n const isCorrectAction = action === permission.attributes.action;\n const undefinedAction =\n action === 'use' && permission.attributes.action === undefined;\n\n return isCorrectResourceType && (isCorrectAction || undefinedAction);\n }\n return false;\n });\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\nexport const matches = (\n role?: RoleMetadata,\n filters?: RBACFilters,\n): boolean => {\n if (!filters) {\n return true;\n }\n\n if (!role) {\n return false;\n }\n\n if ('allOf' in filters) {\n return filters.allOf.every(filter => matches(role, filter));\n }\n\n if ('anyOf' in filters) {\n return filters.anyOf.some(filter => matches(role, filter));\n }\n\n if ('not' in filters) {\n return !matches(role, filters.not);\n }\n\n return filters.values.includes(role.owner);\n};\n"],"names":["auditor","difference","ActionType","RoleEvents","omitBy","sortBy","toPairs","isEqual","isArray","isPlainObject","fromPairs"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var pluginRbacCommon = require('@backstage-community/plugin-rbac-common');
|
|
4
|
+
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
5
|
+
var rules = require('./rules.cjs.js');
|
|
6
|
+
|
|
7
|
+
pluginPermissionNode.createConditionExports({
|
|
8
|
+
pluginId: "permission",
|
|
9
|
+
resourceType: pluginRbacCommon.RESOURCE_TYPE_POLICY_ENTITY,
|
|
10
|
+
rules: rules.rules
|
|
11
|
+
});
|
|
12
|
+
const transformConditions = pluginPermissionNode.createConditionTransformer(Object.values(rules.rules));
|
|
13
|
+
|
|
14
|
+
exports.transformConditions = transformConditions;
|
|
15
|
+
//# sourceMappingURL=conditions.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conditions.cjs.js","sources":["../../src/permissions/conditions.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { RESOURCE_TYPE_POLICY_ENTITY } from '@backstage-community/plugin-rbac-common';\nimport {\n ConditionTransformer,\n createConditionExports,\n createConditionTransformer,\n} from '@backstage/plugin-permission-node';\n\nimport { rules, RBACFilter } from './rules';\n\nconst { conditions, createConditionalDecision } = createConditionExports({\n pluginId: 'permission',\n resourceType: RESOURCE_TYPE_POLICY_ENTITY,\n rules,\n});\n\nexport const rbacConditions = conditions;\n\nexport const createRBACConditionalDecision = createConditionalDecision;\n\nexport const transformConditions: ConditionTransformer<RBACFilter> =\n createConditionTransformer(Object.values(rules));\n"],"names":["createConditionExports","RESOURCE_TYPE_POLICY_ENTITY","rules","createConditionTransformer"],"mappings":";;;;;;AAwBkDA,2CAAuB,CAAA;AAAA,EACvE,QAAU,EAAA,YAAA;AAAA,EACV,YAAc,EAAAC,4CAAA;AAAA,SACdC;AACF,CAAC;AAMM,MAAM,mBACX,GAAAC,+CAAA,CAA2B,MAAO,CAAA,MAAA,CAAOD,WAAK,CAAC;;;;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
4
|
+
var pluginRbacCommon = require('@backstage-community/plugin-rbac-common');
|
|
5
|
+
var zod = require('zod');
|
|
6
|
+
var zodToJsonSchema = require('zod-to-json-schema');
|
|
7
|
+
|
|
8
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var zodToJsonSchema__default = /*#__PURE__*/_interopDefaultCompat(zodToJsonSchema);
|
|
11
|
+
|
|
12
|
+
const createRBACPermissionRule = pluginPermissionNode.makeCreatePermissionRule();
|
|
13
|
+
const isOwner = createRBACPermissionRule({
|
|
14
|
+
name: "IS_OWNER",
|
|
15
|
+
description: "Should allow access to RBAC roles and Permissions through ownership",
|
|
16
|
+
resourceType: pluginRbacCommon.RESOURCE_TYPE_POLICY_ENTITY,
|
|
17
|
+
paramsSchema: zod.z.object({
|
|
18
|
+
owners: zod.z.string().array().describe("List of entity refs to match against")
|
|
19
|
+
}),
|
|
20
|
+
apply: (roleMeta, { owners }) => {
|
|
21
|
+
if (!roleMeta.owner) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return owners.includes(roleMeta.owner);
|
|
25
|
+
},
|
|
26
|
+
toQuery: ({ owners }) => ({
|
|
27
|
+
key: "owners",
|
|
28
|
+
values: owners
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
const rbacRules = {
|
|
32
|
+
name: isOwner.name,
|
|
33
|
+
description: isOwner.description,
|
|
34
|
+
resourceType: isOwner.resourceType,
|
|
35
|
+
paramsSchema: zodToJsonSchema__default.default(isOwner.paramsSchema ?? zod.z.object({}))
|
|
36
|
+
};
|
|
37
|
+
const rules = { isOwner };
|
|
38
|
+
|
|
39
|
+
exports.rbacRules = rbacRules;
|
|
40
|
+
exports.rules = rules;
|
|
41
|
+
//# sourceMappingURL=rules.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.cjs.js","sources":["../../src/permissions/rules.ts"],"sourcesContent":["/*\n * Copyright 2025 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 { makeCreatePermissionRule } from '@backstage/plugin-permission-node';\nimport {\n RESOURCE_TYPE_POLICY_ENTITY,\n RoleMetadata,\n} from '@backstage-community/plugin-rbac-common';\nimport { z } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\n\nexport type RBACFilter = {\n key: string;\n values: any[];\n};\n\nexport type RBACFilters =\n | { anyOf: RBACFilters[] }\n | { allOf: RBACFilters[] }\n | { not: RBACFilters }\n | RBACFilter;\n\nconst createRBACPermissionRule = makeCreatePermissionRule<\n RoleMetadata,\n RBACFilter,\n typeof RESOURCE_TYPE_POLICY_ENTITY\n>();\n\nconst isOwner = createRBACPermissionRule({\n name: 'IS_OWNER',\n description:\n 'Should allow access to RBAC roles and Permissions through ownership',\n resourceType: RESOURCE_TYPE_POLICY_ENTITY,\n paramsSchema: z.object({\n owners: z.string().array().describe('List of entity refs to match against'),\n }),\n apply: (roleMeta: RoleMetadata, { owners }) => {\n if (!roleMeta.owner) {\n return false;\n }\n return owners.includes(roleMeta.owner);\n },\n toQuery: ({ owners }) => ({\n key: 'owners',\n values: owners,\n }),\n});\n\nexport const rbacRules = {\n name: isOwner.name,\n description: isOwner.description,\n resourceType: isOwner.resourceType,\n paramsSchema: zodToJsonSchema(isOwner.paramsSchema ?? z.object({})),\n};\n\nexport const rules = { isOwner };\n"],"names":["makeCreatePermissionRule","RESOURCE_TYPE_POLICY_ENTITY","z","zodToJsonSchema"],"mappings":";;;;;;;;;;;AAkCA,MAAM,2BAA2BA,6CAI/B,EAAA;AAEF,MAAM,UAAU,wBAAyB,CAAA;AAAA,EACvC,IAAM,EAAA,UAAA;AAAA,EACN,WACE,EAAA,qEAAA;AAAA,EACF,YAAc,EAAAC,4CAAA;AAAA,EACd,YAAA,EAAcC,MAAE,MAAO,CAAA;AAAA,IACrB,QAAQA,KAAE,CAAA,MAAA,GAAS,KAAM,EAAA,CAAE,SAAS,sCAAsC;AAAA,GAC3E,CAAA;AAAA,EACD,KAAO,EAAA,CAAC,QAAwB,EAAA,EAAE,QAAa,KAAA;AAC7C,IAAI,IAAA,CAAC,SAAS,KAAO,EAAA;AACnB,MAAO,OAAA,KAAA;AAAA;AAET,IAAO,OAAA,MAAA,CAAO,QAAS,CAAA,QAAA,CAAS,KAAK,CAAA;AAAA,GACvC;AAAA,EACA,OAAS,EAAA,CAAC,EAAE,MAAA,EAAc,MAAA;AAAA,IACxB,GAAK,EAAA,QAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACV;AACF,CAAC,CAAA;AAEM,MAAM,SAAY,GAAA;AAAA,EACvB,MAAM,OAAQ,CAAA,IAAA;AAAA,EACd,aAAa,OAAQ,CAAA,WAAA;AAAA,EACrB,cAAc,OAAQ,CAAA,YAAA;AAAA,EACtB,YAAA,EAAcC,iCAAgB,OAAQ,CAAA,YAAA,IAAgBD,MAAE,MAAO,CAAA,EAAE,CAAC;AACpE;AAEa,MAAA,KAAA,GAAQ,EAAE,OAAQ;;;;;"}
|
|
@@ -110,6 +110,19 @@ class RBACPermissionPolicy {
|
|
|
110
110
|
}
|
|
111
111
|
const permissionName = request.permission.name;
|
|
112
112
|
const roles = await this.enforcer.getRolesForUser(userEntityRef);
|
|
113
|
+
const hasNamedPermission = await this.hasImplicitPermissionSpecifiedByName(
|
|
114
|
+
permissionName,
|
|
115
|
+
action,
|
|
116
|
+
roles
|
|
117
|
+
);
|
|
118
|
+
if (request.permission.name === "policy.entity.create" && !hasNamedPermission) {
|
|
119
|
+
request.permission = {
|
|
120
|
+
attributes: { action: "create" },
|
|
121
|
+
type: "resource",
|
|
122
|
+
resourceType: "policy-entity",
|
|
123
|
+
name: "policy.entity.create"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
113
126
|
if (pluginPermissionCommon.isResourcePermission(request.permission)) {
|
|
114
127
|
const resourceType = request.permission.resourceType;
|
|
115
128
|
if (user) {
|
|
@@ -124,11 +137,6 @@ class RBACPermissionPolicy {
|
|
|
124
137
|
return conditionResult;
|
|
125
138
|
}
|
|
126
139
|
}
|
|
127
|
-
const hasNamedPermission = await this.hasImplicitPermissionSpecifiedByName(
|
|
128
|
-
permissionName,
|
|
129
|
-
action,
|
|
130
|
-
roles
|
|
131
|
-
);
|
|
132
140
|
const obj = hasNamedPermission ? permissionName : resourceType;
|
|
133
141
|
status = await this.isAuthorized(userEntityRef, obj, action, roles);
|
|
134
142
|
} else {
|