From bf97d863bc9710f16777bcee4676420a6e06fd1f Mon Sep 17 00:00:00 2001 From: Gerald Baulig Date: Fri, 3 May 2024 13:49:51 +0200 Subject: [PATCH] refactor(createhrscope): some small refactoring of createHRScope --- package-lock.json | 7 +++++++ package.json | 1 + src/core/accessController.ts | 32 +++++++++++++++----------------- src/core/hierarchicalScope.ts | 28 +++++++++++++++++++++------- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2cb25e7..c9fb2dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "@types/mocha": "^10.0.6", "@types/nock": "^11.1.0", "@types/node": "^20.12.7", + "@types/traverse": "^0.6.36", "@typescript-eslint/eslint-plugin": "^7.7.0", "@typescript-eslint/eslint-plugin-tslint": "^7.0.2", "@typescript-eslint/parser": "^7.7.0", @@ -3381,6 +3382,12 @@ "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, + "node_modules/@types/traverse": { + "version": "0.6.36", + "resolved": "https://registry.npmjs.org/@types/traverse/-/traverse-0.6.36.tgz", + "integrity": "sha512-0ko4fZgKQf2J/2FvDJHua9KZ19zJkfI5FxG1ZeEUhezEwuq6UL+4T0IxcBfmHilBeAj7OSUTwrm/lPnh8EB1/Q==", + "dev": true + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", diff --git a/package.json b/package.json index 4797441..2baea35 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@types/nock": "^11.1.0", "@types/node": "^20.12.7", "@typescript-eslint/eslint-plugin": "^7.7.0", + "@types/traverse": "^0.6.36", "@typescript-eslint/eslint-plugin-tslint": "^7.0.2", "@typescript-eslint/parser": "^7.7.0", "c8": "^9.1.0", diff --git a/src/core/accessController.ts b/src/core/accessController.ts index 19990b7..84949db 100644 --- a/src/core/accessController.ts +++ b/src/core/accessController.ts @@ -730,23 +730,16 @@ export class AccessController { let redisHRScopesKey; if (tokenFound?.interactive) { redisHRScopesKey = `cache:${subjectID}:hrScopes`; - } else if (tokenFound && !tokenFound.interactive) { - redisHRScopesKey = `cache:${subjectID}:${token}:hrScopes`; - } - let timeout = this.cfg.get('authorization:hrReqTimeout'); - if (!timeout) { - timeout = 300000; } - let hrScopes: any; - try { - hrScopes = await this.getRedisKey(redisHRScopesKey); - } catch (err) { - this.logger.info(`Subject or HR Scope not persisted in redis in acs`); + else if (tokenFound && !tokenFound.interactive) { + redisHRScopesKey = `cache:${subjectID}:${token}:hrScopes`; } - let keyExist; - if (redisHRScopesKey) { - keyExist = await this.redisClient.exists(redisHRScopesKey); + else { + return context; } + const timeout = this.cfg.get('authorization:hrReqTimeout') ?? 300000; + const keyExist = await this.redisClient.exists(redisHRScopesKey); + if (!keyExist) { const date = new Date().toISOString(); const tokenDate = token + ':' + date; @@ -759,14 +752,19 @@ export class AccessController { }, timeout); this.waiting[tokenDate].push({ resolve, reject, timeoutId }); }); + const subjectHRScopes = await this.getRedisKey(redisHRScopesKey); + Object.assign(context.subject, { hierarchical_scopes: subjectHRScopes }); } catch (err) { // unhandled promise rejection for timeout this.logger.error(`Error creating Hierarchical scope for subject ${tokenDate}`); } - const subjectHRScopes = await this.getRedisKey(redisHRScopesKey); - Object.assign(context.subject, { hierarchical_scopes: subjectHRScopes }); } else { - Object.assign(context.subject, { hierarchical_scopes: hrScopes }); + try { + const subjectHRScopes = await this.getRedisKey(redisHRScopesKey); + Object.assign(context.subject, { hierarchical_scopes: subjectHRScopes }); + } catch (err) { + this.logger.info(`Subject or HR Scope not persisted in redis in acs`); + } } return context; } diff --git a/src/core/hierarchicalScope.ts b/src/core/hierarchicalScope.ts index 3273fda..c0db561 100644 --- a/src/core/hierarchicalScope.ts +++ b/src/core/hierarchicalScope.ts @@ -1,14 +1,19 @@ import _ from 'lodash-es'; import traverse from 'traverse'; import { Logger } from 'winston'; -import { AccessController } from '.'; +import { AccessController } from './index.js'; import { Request } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/access_control.js'; import { Target } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/rule.js'; import { Attribute } from '@restorecommerce/rc-grpc-clients/dist/generated-server/io/restorecommerce/attribute.js'; import { Resource, ContextWithSubResolved } from './interfaces.js'; -export const checkHierarchicalScope = async (ruleTarget: Target, - request: Request, urns: Map, accessController: AccessController, logger?: Logger): Promise => { +export const checkHierarchicalScope = async ( + ruleTarget: Target, + request: Request, + urns: Map, + accessController: AccessController, + logger?: Logger +): Promise => { // 1) create a Map of resourceID with Owners for resource IDs which have the rule entity matching // 2) In HR scope match validate the Owner indicatory entity with vale from matching users Rule's role for // matching role scoping enitty with instance @@ -162,10 +167,18 @@ export const checkHierarchicalScope = async (ruleTarget: Target, return reducedUserRoleAssocs?.some((roleObj) => { // check if Rule's roleScoping Entity matches the Owner's role scoping entity and RoleAssociation RoleScoping entity (ex: Organization / User / Klasse etc) // and check if roleScoping Instance matches with owner instance - const match = roleObj?.attributes?.some((roleAttributeObject) => roleAttributeObject?.id === urns.get('roleScopingEntity') - && ownerObj?.id === urns.get('ownerEntity') && ownerObj.value === ruleRoleScopingEntity && ownerObj.value === roleAttributeObject?.value - && roleAttributeObject?.attributes?.some((roleInstObj) => - roleInstObj?.id === urns.get('roleScopingInstance') && ownerObj?.attributes?.find((ownerInstObj) => ownerInstObj?.value === roleInstObj?.value))); + const match = roleObj?.attributes?.some( + (roleAttributeObject) => roleAttributeObject?.id === urns.get('roleScopingEntity') + && ownerObj?.id === urns.get('ownerEntity') + && ownerObj.value === ruleRoleScopingEntity + && ownerObj.value === roleAttributeObject?.value + && roleAttributeObject?.attributes?.some( + (roleInstObj) => roleInstObj?.id === urns.get('roleScopingInstance') + && ownerObj?.attributes?.find( + (ownerInstObj) => ownerInstObj?.value === roleInstObj?.value + ) + ) + ); logger.debug('Match result for comparing owner indicatory entity and instance with role scoping entity and instance', { match }); return match; }); @@ -190,6 +203,7 @@ export const checkHierarchicalScope = async (ruleTarget: Target, if (context?.subject?.token && _.isEmpty(context.subject.hierarchical_scopes)) { context = await accessController.createHRScope(context); } + const reducedHRScopes = context?.subject?.hierarchical_scopes?.filter((hrObj) => hrObj?.role === ruleRole); for (let [resourceId, owners] of resourceIdOwnersMap) { const ownerInstances: string[] = owners.filter(