import { Injectable } from '@nestjs/common'; import { AppLogger } from '../../../logger'; import { UserPermission } from '../interfaces'; import { ConditionalOperator, ConditionalStrategy, PermissionModeConditional, } from '../interfaces'; import { ScopeType } from '../interfaces'; import { PermissionGuardService } from './permission.guard.service'; @Injectable() export class AuthorizationGuardService { protected TAG: string = `${this.constructor.name}`; constructor() { AppLogger.log('Init', this.TAG); } public hasPermission(userPermissions: UserPermission, permissionModes: Array>, requestParams: any, resourcesIds: string = null): M { for (const permissionMode of permissionModes) { let scopeId: string = ''; if (!permissionMode.subject) { AppLogger.error(`Illegal param name: ${JSON.stringify(requestParams)}`, this.TAG); return null; } AppLogger.debug(`Scope: ${permissionMode.subject.type}`, this.TAG); if (permissionMode.subject.type === ScopeType.PROJECT) { if (!permissionMode.subject.paramName || !requestParams || !requestParams[permissionMode.subject.paramName]) { AppLogger.error(`Illegal param name: ${JSON.stringify(requestParams)}`, this.TAG); return null; } scopeId = requestParams[permissionMode.subject.paramName]; } else if (permissionMode.subject.type === ScopeType.SYSTEM) { scopeId = PermissionGuardService.SYSTEM_KEY; } else if (permissionMode.subject.type === ScopeType.ACL) { scopeId = PermissionGuardService.ACL_KEY; } else { AppLogger.error(`Illegal Scope`, this.TAG); return null; } let permissions: { [permission: string]: boolean } = null; const conditionalStrategy: ConditionalStrategy = permissionMode.conditionalStrategy || ConditionalStrategy.ALL_REQUIRED; const conditionalOperator: ConditionalOperator = permissionMode.operator || ConditionalOperator.IS; if (!scopeId) { AppLogger.error(`There is no id for scope: ${permissionMode.subject.type}`, this.TAG); return null; } if (resourcesIds && permissionMode.subject.type === ScopeType.ACL) { let hasPermission: boolean = true; AppLogger.debug(`Permission for mode: ${ScopeType.ACL}, permissions: ${JSON.stringify(userPermissions[scopeId])}`, this.TAG); for (const resourceId in userPermissions[scopeId]) { if (userPermissions[scopeId].hasOwnProperty(resourceId)) { AppLogger.debug(`Trying to get user permission for scope id: ${scopeId} and resource id: ${resourceId}`, this.TAG); AppLogger.debug(`user permission for scope id: ${scopeId} and resource id: ${resourceId} are: ${JSON.stringify(userPermissions[scopeId][resourceId])}`, this.TAG); permissions = userPermissions[scopeId][resourceId] as { [permission: string]: boolean }; if (!permissions) { AppLogger.debug(`There is no permission for resource: ${resourceId}`, this.TAG); return null; } AppLogger.debug(`Trying to get permission mode for scope: ${scopeId} resource id: ${resourceId} user permissions ${JSON.stringify(permissions)}`, this.TAG); const resourceMode: M = this.getPermissionsMode(permissions, permissionMode, conditionalStrategy, conditionalOperator); if (!resourceMode) { AppLogger.error(`There is no mode for resource: ${resourceId}`, this.TAG); hasPermission = false; break; } } } AppLogger.debug(`Has permission status: ${hasPermission}`, this.TAG); if (hasPermission) { return permissionMode.mode; } } else { AppLogger.debug(`get permissions mode without resource ids`, this.TAG); permissions = userPermissions[scopeId] as { [permission: string]: boolean }; if (!permissions) { AppLogger.error(`There is no permissions for scope id: ${scopeId}`, this.TAG); return null; } const mode: M = this.getPermissionsMode(permissions, permissionMode, conditionalStrategy, conditionalOperator); if (mode) { return mode; } } } return null; } private getPermissionsMode(permissions: { [permission: string]: boolean }, permissionMode: PermissionModeConditional, conditionalStrategy: ConditionalStrategy, conditionalOperator: ConditionalOperator): M { let hasPermission: boolean = true; switch (conditionalStrategy) { case ConditionalStrategy.ALL_REQUIRED: hasPermission = permissionMode.permissions .every((permission) => { if (conditionalOperator === ConditionalOperator.IS) { return permissions[permission]; } else if (conditionalOperator === ConditionalOperator.IS_NOT) { return !permissions[permission]; } }); break; case ConditionalStrategy.AT_LEAST_ONE: hasPermission = permissionMode.permissions .some((permission) => { if (conditionalOperator === ConditionalOperator.IS) { return permissions[permission]; } else if (conditionalOperator === ConditionalOperator.IS_NOT) { return !permissions[permission]; } }); } if (hasPermission) { return permissionMode.mode; } return null; } }