Skip to content

Commit e501cd5

Browse files
committed
feat: make scope optional and verify the owner entity and instance with matching role scoping entity and role scoping instance value respectively
1 parent cc475bf commit e501cd5

File tree

3 files changed

+99
-277
lines changed

3 files changed

+99
-277
lines changed

src/core/accessController.ts

Lines changed: 18 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -764,136 +764,39 @@ export class AccessController {
764764
}
765765

766766
/**
767-
* Check if the attributes of subject from a rule, policy
768-
* or policy set match the attributes from a request.
767+
* Check if the Rule's Subject Role matches with atleast
768+
* one of the user role associations role value
769769
*
770770
* @param ruleAttributes
771771
* @param requestSubAttributes
772+
* @param request
772773
*/
773774
private async checkSubjectMatches(ruleSubAttributes: Attribute[],
774775
requestSubAttributes: Attribute[], request: Request): Promise<boolean> {
775-
// 1) Check if the rule subject entity exists, if so then check
776-
// request->target->subject->orgInst or roleScopeInst matches with
777-
// context->subject->role_associations->roleScopeInst or hierarchical_scope
778-
// 2) if 1 is true then subject match is considered
779-
// 3) If rule subject entity does not exist (as for master data resources)
780-
// then check context->subject->role_associations->role against
781-
// Rule->subject->role
782-
const scopingEntityURN = this.urns.get('roleScopingEntity'); // urn:restorecommerce:acs:names:roleScopingEntity
783-
const scopingInstanceURN = this.urns.get('roleScopingInstance'); // urn:restorecommerce:acs:names:roleScopingInstance
784-
const hierarchicalRoleScopingURN = this.urns.get('hierarchicalRoleScoping');
776+
// Just check the Role value matches here in subject
785777
const roleURN = this.urns.get('role');
786-
let matches = false;
787-
let scopingEntExists = false;
788-
let ruleRole;
789-
// default if hierarchicalRoleScopingURN is not configured then consider
790-
// to match the HR scopes
791-
let hierarchicalRoleScoping = 'true';
778+
let ruleRole: string;
792779
if (ruleSubAttributes?.length === 0) {
793-
matches = true;
794-
return matches;
780+
return true;
795781
}
796-
for (let ruleSubAttribute of ruleSubAttributes || []) {
797-
if (ruleSubAttribute?.id === scopingEntityURN) {
798-
// match the scoping entity value
799-
scopingEntExists = true;
800-
for (let requestSubAttribute of requestSubAttributes || []) {
801-
if (requestSubAttribute?.value === ruleSubAttribute?.value) {
802-
matches = true;
803-
break;
804-
}
805-
}
806-
} else if (ruleSubAttribute?.id === roleURN) {
807-
ruleRole = ruleSubAttribute.value;
808-
} else if (ruleSubAttribute?.id === hierarchicalRoleScopingURN) {
809-
hierarchicalRoleScoping = ruleSubAttribute.value;
782+
ruleSubAttributes?.forEach((subjectObject) => {
783+
if(subjectObject?.id === roleURN) {
784+
ruleRole = subjectObject?.value;
810785
}
811-
}
786+
});
812787

813-
let context = (request as any)?.context as ContextWithSubResolved;
814-
// check if context subject_id contains HR scope if not make request 'createHierarchicalScopes'
815-
if (context?.subject?.token &&
816-
_.isEmpty(context.subject.hierarchical_scopes)) {
817-
context = await this.createHRScope(context);
788+
// must be a rule subject targetted to specific user
789+
if (!ruleRole && this.attributesMatch(ruleSubAttributes, requestSubAttributes)) {
790+
this.logger.debug('Rule subject targetted to specific user', ruleSubAttributes);
791+
return true;
818792
}
819793

820-
if (scopingEntExists && matches) {
821-
matches = false;
822-
// check the target scoping instance is present in
823-
// the context subject roleassociations and then update matches to true
824-
if (context?.subject?.role_associations) {
825-
let targetScopingInstance;
826-
requestSubAttributes?.find((obj) => {
827-
if (obj?.id === scopingEntityURN && obj?.attributes?.length > 0) {
828-
obj?.attributes?.filter((roleScopeInstObj) => {
829-
if (roleScopeInstObj?.id === scopingInstanceURN) {
830-
targetScopingInstance = roleScopeInstObj?.value;
831-
}
832-
});
833-
}
834-
});
835-
// check in role_associations
836-
const userRoleAssocs = context?.subject?.role_associations;
837-
if (userRoleAssocs?.length > 0) {
838-
for (let role of userRoleAssocs) {
839-
const roleID = role?.role;
840-
for (let obj of role.attributes || []) {
841-
if (obj?.id === scopingEntityURN && obj?.attributes?.length > 0) {
842-
for (let ruleScopInstObj of obj.attributes) {
843-
if (ruleScopInstObj?.id == scopingInstanceURN && ruleScopInstObj?.value == targetScopingInstance) {
844-
if (!ruleRole || (ruleRole && ruleRole === roleID)) {
845-
matches = true;
846-
return matches;
847-
}
848-
}
849-
}
850-
}
851-
}
852-
}
853-
}
854-
if (!matches && hierarchicalRoleScoping && hierarchicalRoleScoping === 'true') {
855-
// check for HR scope
856-
const hrScopes = context?.subject?.hierarchical_scopes;
857-
if (!hrScopes || hrScopes?.length === 0) {
858-
return matches;
859-
}
860-
for (let hrScope of hrScopes || []) {
861-
if (this.checkTargetInstanceExists(hrScope, targetScopingInstance)) {
862-
const userRoleAssocs = context?.subject?.role_associations;
863-
if (!_.isEmpty(userRoleAssocs)) {
864-
for (let role of userRoleAssocs || []) {
865-
const roleID = role.role;
866-
if (!ruleRole || (ruleRole && ruleRole === roleID)) {
867-
matches = true;
868-
return matches;
869-
}
870-
}
871-
}
872-
}
873-
}
874-
}
875-
}
876-
} else if (!scopingEntExists) {
877-
// scoping entity does not exist - check for point 3.
878-
if (context?.subject) {
879-
const userRoleAssocs = context?.subject?.role_associations;
880-
if (userRoleAssocs?.length > 0) {
881-
const ruleSubAttributeObj = ruleSubAttributes?.find((obj) => obj.id === roleURN);
882-
for (let obj of userRoleAssocs) {
883-
if (obj?.role === ruleSubAttributeObj?.value) {
884-
matches = true;
885-
return matches;
886-
}
887-
}
888-
}
889-
}
890-
// must be a rule subject targetted to specific user
891-
if (!matches && this.attributesMatch(ruleSubAttributes, requestSubAttributes)) {
892-
return true;
893-
}
794+
if(!ruleRole) {
795+
this.logger.warn('Invalid Rule as Rule Subject attributes array contains other id, value pairs without role', ruleSubAttributes);
894796
return false;
895797
}
896-
return matches;
798+
const context = (request as any)?.context as ContextWithSubResolved;
799+
return context?.subject?.role_associations?.some((roleObj) => roleObj?.role === ruleRole);
897800
}
898801

899802
private checkTargetInstanceExists(hrScope: HierarchicalScope,

0 commit comments

Comments
 (0)