import { Injectable } from '@nestjs/common'; import { RedisImplService } from '../../../database/redis/services'; import { AppLogger } from '../../../logger'; import { RedisKeyUtil } from '../../../database/redis/utils'; import { ApiErrors } from '../enums'; import { ApiService } from '../communication-manager/http'; import { PermissionGuardService } from './permission.guard.service'; import { GetUserProjectResourceAclResponseDto } from '../models/dto'; import { AclUtil } from '../utils'; import { GetAclResponseDto } from '../models/dto'; import { AclResourcePermissions } from '../interfaces'; import {AuthorizationGuardModuleConfig} from '../authorization.guard.module'; @Injectable() export class AclGuardService { protected TAG: string = `${this.constructor.name}`; constructor(private readonly redisService: RedisImplService, private readonly config: AuthorizationGuardModuleConfig, private readonly apiService: ApiService) { AppLogger.log('Init', this.TAG); } public async getProjectResourceAcl(accessToken: string, userId: string, projectShortId: string, resourceName: string, resourceIds: string = null): Promise { let resourceIdsArray: string[]; if (resourceIds) { resourceIdsArray = resourceIds.split(','); } let resourcePermissions: AclResourcePermissions = await this.getUserResourceAclFromRedis(userId, projectShortId, resourceName, resourceIdsArray); if (resourcePermissions) { AppLogger.log(`Successfully getProjectResourceAcl from Redis for user: ${userId}`, this.TAG); return resourcePermissions; } const getUserProjectResourceAclResponseDto: GetUserProjectResourceAclResponseDto[] = await this.getUserProjectResourceAclFromNetwork(accessToken); AppLogger.debug(`Get user acl network response: ${JSON.stringify(getUserProjectResourceAclResponseDto)}`, this.TAG); if (!getUserProjectResourceAclResponseDto || !getUserProjectResourceAclResponseDto.length) { AppLogger.debug(`No acls for user - ${userId}`, this.TAG); return null; } const aclIds: string[] = AclUtil.extractAclIdsFromUserProjectResourceAclResponseDto(getUserProjectResourceAclResponseDto); if (!aclIds || !aclIds.length) { AppLogger.debug(`No acls for user - ${userId}`, this.TAG); return null; } const aclResponse: GetAclResponseDto[] = await this.getAclByIds(accessToken); resourcePermissions = AclUtil.matchAclToResourseId(getUserProjectResourceAclResponseDto, aclResponse); this.setUserResourceAclOnRedis(userId, projectShortId, resourceName, resourcePermissions); return resourcePermissions; } private async getAclByIds(accessToken: string): Promise { AppLogger.crudRequest(`get`, `RoleService`, this.config.aclByIdUrl, this.TAG); const aclResponse: GetAclResponseDto[] = await this.apiService.getAclByIdsNetworkRequest(accessToken); if (!aclResponse) { AppLogger.error(ApiErrors.FAILED_GET_ACL_BY_IDS, this.TAG); return null; } AppLogger.crudSuccess(`get`, `RoleService`, this.config.aclByIdUrl, this.TAG); return aclResponse; } private async getUserResourceAclFromRedis(userId: string, projectShortId: string, resourceName: string, resourceIds: string[] = null): Promise { try { AppLogger.log(`Trying to getUserResourceAclFromRedis for user: ${userId}, project: ${projectShortId} Resource name: ${resourceName}`, this.TAG); const stringObject: { [key: string]: string } = await this.redisService .hGetAll(RedisKeyUtil.accountProjectAcl(userId, projectShortId, resourceName)); if (!stringObject) { return null; } return AclUtil.aclResourcePermissionsObjectToAclResourcePermission(stringObject, resourceIds); } catch (e) { AppLogger.error(`Failed to getUserResourceAclFromRedis for user: ${userId}, project: ${projectShortId}`, this.TAG); return null; } } private async setUserResourceAclOnRedis(userId: string, projectShortId: string, resourceName: string, resourcePermissions: AclResourcePermissions): Promise { try { AppLogger.log(`Trying to setUserResourceAclFromRedis for user: ${userId}, project: ${projectShortId}, resourceName: ${resourceName}`); const stringValue: string[] = AclUtil.resourcePermissionsObjectToStringArray(resourcePermissions); const result: boolean = await this.redisService.hmSet([RedisKeyUtil.accountProjectAcl(userId, projectShortId, resourceName), ...stringValue]); if (result) { AppLogger.debug(`Successfully setUserResourceAclFromRedis for user: ${userId}, project: ${projectShortId}`); this.redisService.setExpireToKey(RedisKeyUtil.accountProjectAcl(userId, projectShortId, resourceName), PermissionGuardService.REDIS_KEY_TTL); return true; } AppLogger.error(`Failed to setUserResourceAclFromRedis for user: ${userId}, project: ${projectShortId}`, this.TAG); return false; } catch (e) { AppLogger.error(`Failed to setUserResourceAclFromRedis for user: ${userId}, project: ${projectShortId}`, this.TAG); return false; } } private async getUserProjectResourceAclFromNetwork(accessToken: string): Promise { AppLogger.crudRequest(`get`, `AccountService`, this.config.userProjectResourceAclUrl, this.TAG); const resourceIdAcls: GetUserProjectResourceAclResponseDto[] = await this.apiService.getAclForUserProjectResourceNameNetworkRequest(accessToken); if (!resourceIdAcls) { AppLogger.error(ApiErrors.FAILED_GET_USER_RESOURCE_ACL, this.TAG); return null; } AppLogger.crudSuccess(`get`, `AccountService`, this.config.userProjectResourceAclUrl, this.TAG); return resourceIdAcls; } }