UNPKG

@backstage-community/plugin-rbac-backend

Version:
227 lines (223 loc) 8.01 kB
'use strict'; var casbin = require('casbin'); var auditor = require('../auditor/auditor.cjs.js'); var helper = require('../helper.cjs.js'); var permissionModel = require('../service/permission-model.cjs.js'); var policiesValidation = require('../validation/policies-validation.cjs.js'); class Connection { constructor(id, enforcer, roleMetadataStorage, logger, auditor) { this.id = id; this.enforcer = enforcer; this.roleMetadataStorage = roleMetadataStorage; this.logger = logger; this.auditor = auditor; } async applyRoles(roles) { const lowercasedRoles = helper.transformRolesGroupToLowercase(roles); const stringPolicy = helper.typedPoliciesToString(lowercasedRoles, "g"); const providerRolesforRemoval = []; const tempEnforcer = await casbin.newEnforcer( casbin.newModelFromString(permissionModel.MODEL), new casbin.StringAdapter(stringPolicy) ); const providerRoles = await this.getProviderRoles(); await this.enforcer.loadPolicy(); for (const providerRole of providerRoles) { providerRolesforRemoval.push( ...await this.enforcer.getFilteredGroupingPolicy(1, providerRole) ); } await this.removeRoles(providerRolesforRemoval, tempEnforcer); await this.addRoles(lowercasedRoles); } async applyPermissions(permissions) { const stringPolicy = helper.typedPoliciesToString(permissions, "p"); const providerPermissions = []; const tempEnforcer = await casbin.newEnforcer( casbin.newModelFromString(permissionModel.MODEL), new casbin.StringAdapter(stringPolicy) ); const providerRoles = await this.getProviderRoles(); await this.enforcer.loadPolicy(); for (const providerRole of providerRoles) { providerPermissions.push( ...await this.enforcer.getFilteredPolicy(0, providerRole) ); } await this.removePermissions(providerPermissions, tempEnforcer); await this.addPermissions(permissions); } async addRoles(roles) { for (const role of roles) { if (!await this.enforcer.hasGroupingPolicy(...role)) { const metadata = await this.roleMetadataStorage.findRoleMetadata( role[1] ); const err = await policiesValidation.validateGroupingPolicy(role, metadata, this.id); if (err) { this.logger.warn(err.message); continue; } let roleMeta = await this.roleMetadataStorage.findRoleMetadata(role[1]); if (!roleMeta) { roleMeta = { modifiedBy: this.id, source: this.id, roleEntityRef: role[1] }; } const auditorMeta = { ...roleMeta, members: [role[0]] }; const auditorEvent = await this.auditor.createEvent({ eventId: auditor.RoleEvents.ROLE_WRITE, severityLevel: "medium", meta: { actionType: roleMeta ? auditor.ActionType.UPDATE : auditor.ActionType.CREATE, source: auditorMeta.source } }); try { await this.enforcer.addGroupingPolicy(role, roleMeta); await auditorEvent.success({ meta: auditorMeta }); } catch (error) { await auditorEvent.fail({ error, meta: auditorMeta }); } } } } async removeRoles(providerRoles, tempEnforcer) { const lowercasedProviderRoles = helper.transformRolesGroupToLowercase(providerRoles); for (const role of lowercasedProviderRoles) { if (!await tempEnforcer.hasGroupingPolicy(...role)) { const roleMeta = await this.roleMetadataStorage.findRoleMetadata( role[1] ); const currentRole = await this.enforcer.getFilteredGroupingPolicy( 1, role[1] ); if (!roleMeta) { this.logger.warn("role does not exist"); continue; } const singleRole = roleMeta && currentRole.length === 1; const actionType = singleRole ? auditor.ActionType.DELETE : auditor.ActionType.UPDATE; const auditorMeta = { ...roleMeta, members: [role[0]] }; const auditorEvent = await this.auditor.createEvent({ eventId: auditor.RoleEvents.ROLE_WRITE, severityLevel: "medium", meta: { actionType, source: roleMeta.source } }); try { await this.enforcer.removeGroupingPolicy( role, roleMeta, actionType === auditor.ActionType.UPDATE ); await auditorEvent.success({ meta: auditorMeta }); } catch (error) { await auditorEvent.fail({ error, meta: auditorMeta }); } } } } async addPermissions(permissions) { for (const permission of permissions) { if (permission[1] === "policy-entity" && permission[2] === "create") { this.logger.warn( `Permission policy with resource type 'policy-entity' and action 'create' has been removed. Please consider updating policy ${permission} to use 'policy.entity.create' instead of 'policy-entity' from source ${this.id}` ); } if (!await this.enforcer.hasPolicy(...permission)) { const transformedPolicy = helper.transformArrayToPolicy(permission); const metadata = await this.roleMetadataStorage.findRoleMetadata( permission[0] ); const auditorMeta = { policies: [permission] }; const auditorEvent = await this.auditor.createEvent({ eventId: auditor.PermissionEvents.POLICY_WRITE, severityLevel: "medium", meta: { actionType: auditor.ActionType.CREATE, source: this.id } }); let err = policiesValidation.validatePolicy(transformedPolicy); if (err) { auditorEvent.fail({ error: err, meta: auditorMeta }); continue; } err = await policiesValidation.validateSource(this.id, metadata); if (err) { auditorEvent.fail({ error: err, meta: auditorMeta }); continue; } try { await this.enforcer.addPolicy(permission); await auditorEvent.success({ meta: auditorMeta }); } catch (error) { await auditorEvent.fail({ error, meta: auditorMeta }); } } } } async removePermissions(providerPermissions, tempEnforcer) { for (const permission of providerPermissions) { if (!await tempEnforcer.hasPolicy(...permission)) { const auditorMeta = { policies: [permission] }; const auditorEvent = await this.auditor?.createEvent({ eventId: auditor.PermissionEvents.POLICY_WRITE, severityLevel: "medium", meta: { actionType: auditor.ActionType.DELETE, source: this.id } }); try { await this.enforcer.removePolicy(permission); await auditorEvent.success({ meta: auditorMeta }); } catch (error) { await auditorEvent.fail({ error, meta: auditorMeta }); } } } } async getProviderRoles() { const currentRoles = await this.roleMetadataStorage.filterRoleMetadata( this.id ); return currentRoles.map((meta) => meta.roleEntityRef); } } async function connectRBACProviders(providers, enforcer, roleMetadataStorage, logger, auditor) { await Promise.all( providers.map(async (provider) => { try { const connection = new Connection( provider.getProviderName(), enforcer, roleMetadataStorage, logger, auditor ); return provider.connect(connection); } catch (error) { throw new Error( `Unable to connect provider ${provider.getProviderName()}, ${error}` ); } }) ); } exports.Connection = Connection; exports.connectRBACProviders = connectRBACProviders; //# sourceMappingURL=connect-providers.cjs.js.map