UNPKG

@backstage-community/plugin-rbac-backend

Version:
181 lines (177 loc) 5.87 kB
'use strict'; var errors = require('@backstage/errors'); const CONDITIONAL_TABLE = "role-condition-policies"; class DataBaseConditionalStorage { constructor(knex) { this.knex = knex; } async filterConditions(roleEntityRef, pluginId, resourceType, actions, permissionNames, trx) { const db = trx ?? this.knex; const daoRaws = await db.table(CONDITIONAL_TABLE).where((builder) => { if (pluginId) { builder.where("pluginId", pluginId); } if (resourceType) { builder.where("resourceType", resourceType); } if (roleEntityRef) { if (Array.isArray(roleEntityRef)) { builder.whereIn("roleEntityRef", roleEntityRef); } else { builder.where("roleEntityRef", roleEntityRef); } } }); let conditions = []; if (daoRaws) { conditions = daoRaws.map((dao) => this.daoToConditionalDecision(dao)); } if (permissionNames && permissionNames.length > 0) { conditions = conditions.filter((condition) => { return permissionNames.every( (permissionName) => condition.permissionMapping.map((permInfo) => permInfo.name).includes(permissionName) ); }); } if (actions && actions.length > 0) { conditions = conditions.filter((condition) => { return actions.every( (action) => condition.permissionMapping.map((permInfo) => permInfo.action).includes(action) ); }); } return conditions; } async createCondition(conditionalDecision) { await this.checkConflictedConditions( conditionalDecision.roleEntityRef, conditionalDecision.resourceType, conditionalDecision.pluginId, conditionalDecision.permissionMapping.map((permInfo) => permInfo.action) ); const conditionRaw = this.toDAO(conditionalDecision); const result = await this.knex.table(CONDITIONAL_TABLE).insert(conditionRaw).returning("id"); if (result && result?.length > 0) { return result[0].id; } throw new Error(`Failed to create the condition.`); } async checkConflictedConditions(roleEntityRef, resourceType, pluginId, queryConditionActions, idToExclude, trx) { const db = trx ?? this.knex; let conditionsForTheSameResource = await this.filterConditions( roleEntityRef, pluginId, resourceType, undefined, undefined, db ); conditionsForTheSameResource = conditionsForTheSameResource.filter( (c) => c.id !== idToExclude ); if (conditionsForTheSameResource) { const conflictedCondition = conditionsForTheSameResource.find( (condition) => { const conditionActions = condition.permissionMapping.map( (permInfo) => permInfo.action ); return queryConditionActions.some( (action) => conditionActions.includes(action) ); } ); if (conflictedCondition) { const conflictedActions = queryConditionActions.filter( (action) => conflictedCondition.permissionMapping.some((p) => p.action === action) ); throw new errors.ConflictError( `Found condition with conflicted permission action '${JSON.stringify( conflictedActions )}'. Role could have multiple conditions for the same resource type '${conflictedCondition.resourceType}', but with different permission action sets.` ); } } } async getCondition(id, trx) { const db = trx ?? this.knex; const daoRaw = await db.table(CONDITIONAL_TABLE).where("id", id).first(); if (daoRaw) { return this.daoToConditionalDecision(daoRaw); } return undefined; } async deleteCondition(id) { const condition = await this.getCondition(id); if (!condition) { throw new errors.NotFoundError(`Condition with id ${id} was not found`); } await this.knex?.table(CONDITIONAL_TABLE).delete().whereIn("id", [id]); } async updateCondition(id, conditionalDecision, trx) { const db = trx ?? this.knex; const condition = await this.getCondition(id, db); if (!condition) { throw new errors.NotFoundError(`Condition with id ${id} was not found`); } await this.checkConflictedConditions( conditionalDecision.roleEntityRef, conditionalDecision.resourceType, conditionalDecision.pluginId, conditionalDecision.permissionMapping.map((perm) => perm.action), id, db ); const conditionRaw = this.toDAO(conditionalDecision); conditionRaw.id = id; const result = await db.table(CONDITIONAL_TABLE).where("id", conditionRaw.id).update(conditionRaw).returning("id"); if (!result || result.length === 0) { throw new Error(`Failed to update the condition with id: ${id}.`); } } toDAO(conditionalDecision) { const { result, pluginId, resourceType, conditions, roleEntityRef, permissionMapping } = conditionalDecision; const conditionsJson = JSON.stringify(conditions); return { result, pluginId, resourceType, conditionsJson, roleEntityRef, permissions: JSON.stringify(permissionMapping) }; } daoToConditionalDecision(dao) { if (!dao.id) { throw new errors.InputError(`Missed id in the dao object: ${dao}`); } const { id, result, pluginId, resourceType, conditionsJson, roleEntityRef, permissions } = dao; const conditions = JSON.parse(conditionsJson); return { id, result, pluginId, resourceType, conditions, roleEntityRef, permissionMapping: JSON.parse(permissions) }; } } exports.CONDITIONAL_TABLE = CONDITIONAL_TABLE; exports.DataBaseConditionalStorage = DataBaseConditionalStorage; //# sourceMappingURL=conditional-storage.cjs.js.map