Skip to content

Commit

Permalink
chore: Release v1.1.0 - See CHANELOG
Browse files Browse the repository at this point in the history
  • Loading branch information
Arun-KumarH committed Sep 20, 2023
1 parent 41a4395 commit 866d291
Show file tree
Hide file tree
Showing 15 changed files with 619 additions and 681 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.0.5 (September 20th, 2023)

- made all fields optionals in proto files

## 1.0.5 (July 28th, 2023)

- use generated server typings
Expand Down
6 changes: 6 additions & 0 deletions cfg/config_production.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
},
"dataStream": true,
"source": "access-control-srv"
},
"console": {
"handleExceptions": false,
"level": "silly",
"colorize": true,
"prettyPrint": true
}
},
"redis": {
Expand Down
865 changes: 396 additions & 469 deletions package-lock.json

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@restorecommerce/access-control-srv",
"version": "1.0.5",
"version": "1.1.0",
"description": "Access Control Service",
"main": "lib/start.js",
"author": "n-fuse GmbH",
Expand All @@ -17,14 +17,14 @@
"service"
],
"dependencies": {
"@restorecommerce/acs-client": "^1.1.14",
"@restorecommerce/chassis-srv": "^1.2.5",
"@restorecommerce/acs-client": "^1.1.17",
"@restorecommerce/chassis-srv": "^1.3.1",
"@restorecommerce/cluster-service": "^1.0.2",
"@restorecommerce/grpc-client": "^2.0.3",
"@restorecommerce/kafka-client": "^1.0.17",
"@restorecommerce/kafka-client": "^1.1.1",
"@restorecommerce/logger": "^1.2.4",
"@restorecommerce/rc-grpc-clients": "^5.0.1",
"@restorecommerce/resource-base-interface": "^1.2.5",
"@restorecommerce/rc-grpc-clients": "^5.1.1",
"@restorecommerce/resource-base-interface": "^1.3.0",
"@restorecommerce/service-config": "^1.0.6",
"apollo-boost": "^0.4.9",
"apollo-cache-inmemory": "^1.6.6",
Expand All @@ -38,29 +38,29 @@
"traverse": "^0.6.7"
},
"devDependencies": {
"@alenon/grpc-mock-server": "^3.0.21",
"@grpc/proto-loader": "^0.7.8",
"@types/lodash": "^4.14.196",
"@alenon/grpc-mock-server": "^3.1.1",
"@grpc/proto-loader": "^0.7.10",
"@types/lodash": "^4.14.198",
"@types/mocha": "^10.0.1",
"@types/nock": "^11.1.0",
"@types/node": "^20.4.5",
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/eslint-plugin-tslint": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"@types/node": "^20.6.3",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/eslint-plugin-tslint": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"coveralls": "^3.1.1",
"cross-env": "^7.0.3",
"eslint": "^8.45.0",
"eslint": "^8.49.0",
"eslint-plugin-prefer-arrow-functions": "^3.1.4",
"mocha": "^10.2.0",
"nock": "^13.3.2",
"nock": "^13.3.3",
"nodemon": "^3.0.1",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"rimraf": "^5.0.1",
"should": "^13.2.3",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"typescript": "^5.1.6"
"typescript": "^5.2.2"
},
"scripts": {
"start": "node lib/start.js",
Expand Down
6 changes: 3 additions & 3 deletions src/accessControlService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ export class AccessControlService implements AccessControlServiceImplementation
this.logger.info('Loading policies....');

const policiesCfg = this.cfg.get('policies');
const loadType = policiesCfg.type;
const loadType = policiesCfg?.type;
switch (loadType) {
case 'local':
this.logger.silly('Loading policies from local files....');
const path: string = policiesCfg.path;
this.accessController = await core.utils.loadPoliciesFromDoc(this.accessController, path);
const path: string = policiesCfg?.path;
this.accessController = await core?.utils?.loadPoliciesFromDoc(this.accessController, path);
break;
case 'database':
this.logger.silly('Loading policies from database....');
Expand Down
172 changes: 87 additions & 85 deletions src/core/accessController.ts

Large diffs are not rendered by default.

57 changes: 28 additions & 29 deletions src/core/hierarchicalScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,62 +51,62 @@ export const checkHierarchicalScope = async (ruleTarget: Target,
const reqTarget = request.target;
let currentResourceEntity: string;
// iterating through all targeted resources and retrieve relevant owners instances
for (let attribute of ruleTarget.resources) {
if (attribute.id == urns.get('entity')) { // resource type found
for (let attribute of ruleTarget.resources || []) {
if (attribute?.id == urns.get('entity')) { // resource type found
logger.debug('Evaluating resource entity match');
currentResourceEntity = attribute.value;
currentResourceEntity = attribute?.value;

let entitiesMatch = false;
// iterating request resources to filter all resources of a given type
for (let requestAttribute of reqTarget.resources) {
if (requestAttribute.id == attribute.id && requestAttribute.value == currentResourceEntity) {
for (let requestAttribute of reqTarget.resources || []) {
if (requestAttribute?.id == attribute?.id && requestAttribute?.value == currentResourceEntity) {
entitiesMatch = true; // a resource entity that matches the request and the rule's target
} else if (requestAttribute.id == attribute.id) {
} else if (requestAttribute?.id == attribute?.id) {
// rule entity, get ruleNS and entityRegexValue for rule
const value = currentResourceEntity;
let pattern = value.substring(value.lastIndexOf(':') + 1);
let nsEntityArray = pattern.split('.');
let pattern = value?.substring(value?.lastIndexOf(':') + 1);
let nsEntityArray = pattern?.split('.');
// firstElement could be either entity or namespace
let nsOrEntity = nsEntityArray[0];
let entityRegexValue = nsEntityArray[nsEntityArray.length - 1];
let reqNS, ruleNS;
if (nsOrEntity.toUpperCase() != entityRegexValue.toUpperCase()) {
if (nsOrEntity?.toUpperCase() != entityRegexValue?.toUpperCase()) {
// rule name space is present
ruleNS = nsOrEntity.toUpperCase();
ruleNS = nsOrEntity?.toUpperCase();
}

// request entity, get reqNS and requestEntityValue for request
let reqValue = requestAttribute.value;
const reqAttributeNS = reqValue.substring(0, reqValue.lastIndexOf(':'));
const ruleAttributeNS = value.substring(0, value.lastIndexOf(':'));
let reqValue = requestAttribute?.value;
const reqAttributeNS = reqValue?.substring(0, reqValue?.lastIndexOf(':'));
const ruleAttributeNS = value?.substring(0, value?.lastIndexOf(':'));
// verify namespace before entity name
if (reqAttributeNS != ruleAttributeNS) {
entitiesMatch = false;
}
let reqPattern = reqValue.substring(reqValue.lastIndexOf(':') + 1);
let reqNSEntityArray = reqPattern.split('.');
let reqPattern = reqValue?.substring(reqValue?.lastIndexOf(':') + 1);
let reqNSEntityArray = reqPattern?.split('.');
// firstElement could be either entity or namespace
let reqNSOrEntity = reqNSEntityArray[0];
let requestEntityValue = reqNSEntityArray[reqNSEntityArray.length - 1];
if (reqNSOrEntity.toUpperCase() != requestEntityValue.toUpperCase()) {
if (reqNSOrEntity?.toUpperCase() != requestEntityValue?.toUpperCase()) {
// request name space is present
reqNS = reqNSOrEntity.toUpperCase();
reqNS = reqNSOrEntity?.toUpperCase();
}

if ((reqNS && ruleNS && (reqNS === ruleNS)) || (!reqNS && !ruleNS)) {
const reExp = new RegExp(entityRegexValue);
if (requestEntityValue.match(reExp)) {
if (requestEntityValue?.match(reExp)) {
entitiesMatch = true;
}
}
}
else if (requestAttribute.id == urns.get('resourceID') && entitiesMatch) { // resource instance ID of a matching entity
const instanceID = requestAttribute.value;
else if (requestAttribute?.id == urns?.get('resourceID') && entitiesMatch) { // resource instance ID of a matching entity
const instanceID = requestAttribute?.value;
// found resource instance ID, iterating through the context to check if owners entities match the scoping entities
let ctxResource: Resource = _.find(ctxResources, ['instance.id', instanceID]);
// ctxResource = ctxResource.instance;
if (ctxResource) {
ctxResource = ctxResource.instance;
ctxResource = ctxResource?.instance;
} else {
// look up by ID
ctxResource = _.find(ctxResources, ['id', instanceID]);
Expand Down Expand Up @@ -149,13 +149,13 @@ export const checkHierarchicalScope = async (ruleTarget: Target,
// entitiesMatch = false;
}
}
} else if (attribute.id === urns.get('operation')) {
} else if (attribute?.id === urns.get('operation')) {
logger.debug('Evaluating resource operation match');
currentResourceEntity = attribute.value;
for (let reqAttribute of reqTarget.resources) {
currentResourceEntity = attribute?.value;
for (let reqAttribute of reqTarget.resources || []) {
// match Rule resource operation URN and operation name with request resource operation URN and operation name
if (reqAttribute.id === attribute.id && reqAttribute.value === attribute.value) {
if (ctxResources.length === 1) {
if (reqAttribute?.id === attribute?.id && reqAttribute?.value === attribute?.value) {
if (ctxResources?.length === 1) {
let meta;
if (ctxResources[0]?.instance) {
meta = ctxResources[0]?.instance?.meta;
Expand Down Expand Up @@ -205,12 +205,11 @@ export const checkHierarchicalScope = async (ruleTarget: Target,
}

// check if context subject_id contains HR scope if not make request 'createHierarchicalScopes'
if (context && context.subject && context.subject.token &&
_.isEmpty(context.subject.hierarchical_scopes)) {
if (context?.subject?.token && _.isEmpty(context.subject.hierarchical_scopes)) {
context = await accessController.createHRScope(context);
}

const roleAssociations = context.subject.role_associations;
const roleAssociations = context?.subject?.role_associations;
if (_.isEmpty(roleAssociations)) {
logger.debug('Role Associations not found');
return false; // impossible to evaluate context
Expand Down
2 changes: 1 addition & 1 deletion src/core/resource_adapters/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class GraphQLAdapter implements ResourceAdapter {
*/
async query(contextQuery: ContextQuery, request: Request): Promise<any[]> {
const filters = _.cloneDeep(contextQuery.filters);
const resources = request.target.resources;
const resources = request?.target?.resources ? request.target.resources : [];
let queryFilters = [];
for (let filtersObj of filters) {
for (let filter of filtersObj.filters) {
Expand Down
6 changes: 3 additions & 3 deletions src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const conditionMatches = (condition: string, request: Request): boolean =
};

const loadPolicies = (document: any, accessController: AccessController): AccessController => {
const policySets = document.policy_sets;
const policySets = document?.policy_sets ? document.policy_sets : [];

for (let policySetYaml of policySets) {

Expand Down Expand Up @@ -212,7 +212,7 @@ export async function checkAccessRequest(ctx: ACSClientContext, resource: Resour
let subject = ctx.subject;
// resolve subject id using findByToken api and update subject with id
let dbSubject;
if (subject && subject.token) {
if (subject?.token) {
const idsClient = await getUserServiceClient();
if (idsClient) {
dbSubject = await idsClient.findByToken({ token: subject.token });
Expand Down Expand Up @@ -264,7 +264,7 @@ export async function createMetadata(resources: any,
});
}

if (resources) {
if (resources.length > 0) {
for (let resource of resources) {
if (!resource.meta) {
resource.meta = {};
Expand Down
26 changes: 13 additions & 13 deletions src/core/verifyACL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const verifyACLList = async (ruleTarget: Target,
const reqTarget = request.target;
// iterating through all targeted resources and retrieve relevant target instances
let targetScopeEntInstances = new Map<string, string[]>(); // <org.Org, [a, b, c]> OR <user.User, [user1, user2 user3]>
for (let reqAttribute of reqTarget.resources) {
for (let reqAttribute of reqTarget.resources || []) {
if (reqAttribute.id == urns.get('resourceID') || (reqAttribute.id === urns.get('operation'))) {
const instanceID = reqAttribute.value;
let ctxResource: Resource = _.find(ctxResources, ['instance.id', instanceID]);
Expand All @@ -59,7 +59,7 @@ export const verifyACLList = async (ruleTarget: Target,
}

// verify ACL list
if (!_.isEmpty(aclList) && _.isArray(aclList)) {
if (aclList?.length > 0) {
for (let acl of aclList) {
let aclObj = acl.attributes;
if (aclObj.id === urns.get('aclIndicatoryEntity')) {
Expand All @@ -85,7 +85,7 @@ export const verifyACLList = async (ruleTarget: Target,
}

// check if context subject_id contains HR scope if not make request 'createHierarchicalScopes'
if (context && context.subject && context.subject.token &&
if (context?.subject?.token &&
_.isEmpty(context.subject.hierarchical_scopes)) {
context = await accessController.createHRScope(context);
}
Expand All @@ -99,20 +99,20 @@ export const verifyACLList = async (ruleTarget: Target,
let subjectScopedEntityInstances = new Map<string, string[]>();
let targetScopingEntities = [...targetScopeEntInstances.keys()]; // keys are the scopingEnt
for (let i = 0; i < roleAssociations.length; i += 1) {
const role: string = roleAssociations[i].role;
const attributes: Attribute[] = roleAssociations[i].attributes || [];
const role: string = roleAssociations[i]?.role;
const attributes: Attribute[] = roleAssociations[i]?.attributes || [];
if (scopedRoles.includes(role)) {
let roleScopingEntity;
for (let roleAttr of attributes) {
if (roleAttr.id === urns.get('roleScopingEntity') && targetScopingEntities.includes(roleAttr.value)) {
roleScopingEntity = roleAttr.value;
if (!subjectScopedEntityInstances.get(roleAttr.value)) {
subjectScopedEntityInstances.set(roleAttr.value, []);
if (roleAttr?.id === urns.get('roleScopingEntity') && targetScopingEntities.includes(roleAttr?.value)) {
roleScopingEntity = roleAttr?.value;
if (!subjectScopedEntityInstances.get(roleAttr?.value)) {
subjectScopedEntityInstances.set(roleAttr?.value, []);
}
if (roleAttr?.attributes?.length > 0) {
for (let roleInstObj of roleAttr.attributes) {
if(roleInstObj.id === urns.get('roleScopingInstance')) {
subjectScopedEntityInstances.get(roleScopingEntity).push(roleInstObj.value);
if(roleInstObj?.id === urns.get('roleScopingInstance')) {
subjectScopedEntityInstances?.get(roleScopingEntity)?.push(roleInstObj?.value);
}
}
}
Expand All @@ -121,7 +121,7 @@ export const verifyACLList = async (ruleTarget: Target,
}
}

const actionObj = reqTarget.actions;
const actionObj = reqTarget?.actions;
// verify targetScopeEntInstances with subjectScopedEntityInstances for create action

if (actionObj && actionObj[0] && actionObj[0].id === urns.get('actionID') &&
Expand Down Expand Up @@ -152,7 +152,7 @@ export const verifyACLList = async (ruleTarget: Target,
let validatedACLInstances: string[] = [];
if (actionObj && actionObj[0] && actionObj[0].id === urns.get('actionID') &&
(actionObj[0].value === urns.get('create'))) {
const hierarchical_scopes = context.subject.hierarchical_scopes;
const hierarchical_scopes = context?.subject?.hierarchical_scopes;
traverse(hierarchical_scopes).forEach((node: any): any => {
// match the role with HR node and validate all the targetInstances
if (scopedRoles.includes(node.role)) {
Expand Down
Loading

0 comments on commit 866d291

Please sign in to comment.