diff --git a/src/enforcer.ts b/src/enforcer.ts index 2e1903b..fd0f2c3 100644 --- a/src/enforcer.ts +++ b/src/enforcer.ts @@ -348,6 +348,44 @@ export class Enforcer extends ManagementEnforcer { return res; } + /** + * getImplicitResourcesForUser returns all policies that user obtaining in domain. + */ + public async getImplicitResourcesForUser(user: string, ...domain: string[]): Promise { + const permissions = await this.getImplicitPermissionsForUser(user, ...domain); + const res: string[][] = []; + for (const permission of permissions) { + if (permission[0] === user) { + res.push(permission); + continue; + } + let resLocal: string[][] = [[user]]; + const tokensLength: number = permission.length; + const t: string[][] = []; + for (const token of permission) { + if (token === permission[0]) { + continue; + } + const tokens: string[] = await this.getImplicitUsersForRole(token, ...domain); + tokens.push(token); + t.push(tokens); + } + for (let i = 0; i < tokensLength - 1; i++) { + const n: string[][] = []; + for (const tokens of t[i]) { + for (const policy of resLocal) { + const t: string[] = [...policy]; + t.push(tokens); + n.push(t); + } + } + resLocal = n; + } + res.push(...resLocal); + } + return res; + } + /** * getImplicitUsersForRole gets implicit users that a role has. * Compared to getUsersForRole(), this function retrieves indirect users besides direct users. diff --git a/src/managementEnforcer.ts b/src/managementEnforcer.ts index c1d7cf4..1393c0d 100644 --- a/src/managementEnforcer.ts +++ b/src/managementEnforcer.ts @@ -508,6 +508,29 @@ export class ManagementEnforcer extends InternalEnforcer { return this.removeFilteredPolicyInternal('g', ptype, fieldIndex, fieldValues, true); } + /** + * UpdateGroupingPolicy updates an rule to the current named policy. + * + * @param oldRule the old rule. + * @param newRule the new rule. + * @return succeeds or not. + */ + public async updateGroupingPolicy(oldRule: string[], newRule: string[]): Promise { + return this.updateNamedGroupingPolicy('g', oldRule, newRule); + } + + /** + * updateNamedGroupingPolicy updates an rule to the current named policy. + * + * @param ptype the policy type, can be "g", "g2", "g3", .. + * @param oldRule the old rule. + * @param newRule the new rule. + * @return succeeds or not. + */ + public async updateNamedGroupingPolicy(ptype: string, oldRule: string[], newRule: string[]): Promise { + return this.updatePolicyInternal('g', ptype, oldRule, newRule, true); + } + /** * addFunction adds a customized function. * @param name custom function name diff --git a/src/syncedEnforcer.ts b/src/syncedEnforcer.ts index c4e6b99..bbc1146 100644 --- a/src/syncedEnforcer.ts +++ b/src/syncedEnforcer.ts @@ -479,6 +479,29 @@ export class SyncedEnforcer extends Enforcer { return super.removeFilteredNamedGroupingPolicy(ptype, fieldIndex, ...fieldValues).finally(() => this.lock.release()); } + /** + * UpdateGroupingPolicy updates an rule to the current named policy. + * + * @param oldRule the old rule. + * @param newRule the new rule. + * @return succeeds or not. + */ + public async updateGroupingPolicy(oldRule: string[], newRule: string[]): Promise { + return super.updateGroupingPolicy(oldRule, newRule); + } + + /** + * updateNamedGroupingPolicy updates an rule to the current named policy. + * + * @param ptype the policy type, can be "g", "g2", "g3", .. + * @param oldRule the old rule. + * @param newRule the new rule. + * @return succeeds or not. + */ + public async updateNamedGroupingPolicy(ptype: string, oldRule: string[], newRule: string[]): Promise { + return super.updateNamedGroupingPolicy(ptype, oldRule, newRule); + } + /** * add matching function to RoleManager by ptype * @param ptype g diff --git a/test/managementAPI.test.ts b/test/managementAPI.test.ts index fde73c6..2afc92e 100644 --- a/test/managementAPI.test.ts +++ b/test/managementAPI.test.ts @@ -353,3 +353,27 @@ test('removeNamedGroupingPolicies', async () => { const removed = await e.removeNamedGroupingPolicies('g', groupingRules); expect(removed).toBe(true); }); + +test('updateGroupingPolicy', async () => { + const a = new FileAdapter('examples/rbac_policy.csv'); + e.setAdapter(a); + + let groupingPolicy = await e.getGroupingPolicy(); + testArray2DEquals(groupingPolicy, [['alice', 'data2_admin']]); + + const updated = e.updateGroupingPolicy(['alice', 'data2_admin'], ['alice', 'update_test']); + groupingPolicy = await e.getGroupingPolicy(); + testArray2DEquals(groupingPolicy, [['alice', 'update_test']]); +}); + +test('updateNamedGroupingPolicy', async () => { + const a = new FileAdapter('examples/rbac_policy.csv'); + e.setAdapter(a); + + let groupingPolicy = await e.getGroupingPolicy(); + testArray2DEquals(groupingPolicy, [['alice', 'data2_admin']]); + + const updated = e.updateNamedGroupingPolicy('g', ['alice', 'data2_admin'], ['alice', 'update_test']); + groupingPolicy = await e.getGroupingPolicy(); + testArray2DEquals(groupingPolicy, [['alice', 'update_test']]); +}); diff --git a/test/rbacAPI.test.ts b/test/rbacAPI.test.ts index 98dc40b..32b45a0 100644 --- a/test/rbacAPI.test.ts +++ b/test/rbacAPI.test.ts @@ -75,6 +75,28 @@ test('test getImplicitPermissionsForUser', async () => { ]); }); +test('test getImplicitResourcesForUser', async () => { + const e = await newEnforcer('examples/rbac_with_pattern_model.conf', 'examples/rbac_with_pattern_policy.csv'); + expect(await e.getImplicitResourcesForUser('alice')).toEqual([ + ['alice', '/pen/1', 'GET'], + ['alice', '/pen2/1', 'GET'], + ['alice', '/book/*', 'GET'], + ['alice', '/book/:id', 'GET'], + ['alice', '/book2/{id}', 'GET'], + ['alice', 'book_group', 'GET'], + ]); + expect(await e.getImplicitResourcesForUser('bob')).toEqual([ + ['bob', '/pen/:id', 'GET'], + ['bob', '/pen2/{id}', 'GET'], + ['bob', 'pen_group', 'GET'], + ]); + expect(await e.getImplicitResourcesForUser('cathy')).toEqual([ + ['cathy', '/pen/:id', 'GET'], + ['cathy', '/pen2/{id}', 'GET'], + ['cathy', 'pen_group', 'GET'], + ]); +}); + test('test deleteRolesForUser', async () => { const e = await newEnforcer('examples/rbac_model.conf', 'examples/rbac_with_hierarchy_policy.csv'); expect(await e.hasPermissionForUser('bob', 'data2', 'write')).toEqual(true);