Skip to content

Commit ad9df14

Browse files
committed
feat: add getImplicitUsersForPermission
1 parent 50b7b9f commit ad9df14

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

src/enforcer.ts

+27
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ManagementEnforcer } from './managementEnforcer';
1616
import { Model, newModel } from './model';
1717
import { Adapter, FileAdapter, StringAdapter } from './persist';
1818
import { getLogger } from './log';
19+
import { arrayRemoveDuplicates } from './util';
1920

2021
/**
2122
* Enforcer = ManagementEnforcer + RBAC API.
@@ -320,6 +321,32 @@ export class Enforcer extends ManagementEnforcer {
320321

321322
return res;
322323
}
324+
325+
/**
326+
* getImplicitUsersForPermission gets implicit users for a permission.
327+
* For example:
328+
* p, admin, data1, read
329+
* p, bob, data1, read
330+
* g, alice, admin
331+
*
332+
* getImplicitUsersForPermission("data1", "read") will get: ["alice", "bob"].
333+
* Note: only users will be returned, roles (2nd arg in "g") will be excluded.
334+
*/
335+
public async getImplicitUsersForPermission(...permission: string[]): Promise<string[]> {
336+
const res: string[] = [];
337+
const policySubjects = await this.getAllSubjects();
338+
const subjects = arrayRemoveDuplicates([...policySubjects, ...this.model.getValuesForFieldInPolicyAllTypes('g', 0)]);
339+
const inherits = this.model.getValuesForFieldInPolicyAllTypes('g', 1);
340+
341+
for (const user of subjects) {
342+
const allowed = await this.enforce(user, ...permission);
343+
if (allowed) {
344+
res.push(user);
345+
}
346+
}
347+
348+
return res.filter(n => !inherits.some(m => n === m));
349+
}
323350
}
324351

325352
export async function newEnforcerWithClass<T extends Enforcer>(enforcer: new () => T, ...params: any[]): Promise<T> {

src/model/model.ts

+16
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,22 @@ export class Model {
332332
return util.arrayRemoveDuplicates(ast.policy.map((n: string[]) => n[fieldIndex]));
333333
}
334334

335+
// getValuesForFieldInPolicyAllTypes gets all values for a field for all rules in a policy of all ptypes, duplicated values are removed.
336+
public getValuesForFieldInPolicyAllTypes(sec: string, fieldIndex: number): string[] {
337+
const values: string[] = [];
338+
339+
const ast = this.model.get(sec);
340+
if (!ast) {
341+
return values;
342+
}
343+
344+
for (const ptype of ast.keys()) {
345+
values.push(...this.getValuesForFieldInPolicy(sec, ptype, fieldIndex));
346+
}
347+
348+
return util.arrayRemoveDuplicates(values);
349+
}
350+
335351
// printPolicy prints the policy to log.
336352
public printPolicy(): void {
337353
logPrint('Policy:');

test/rbacAPI.test.ts

+16
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,19 @@ test('test deleteUser', async () => {
158158
expect(await e.getImplicitPermissionsForUser('alice')).toEqual([]);
159159
expect(await e.getImplicitPermissionsForUser('bob')).toEqual([]);
160160
});
161+
162+
test('test getImplicitPermissionsForUser', async () => {
163+
const e = await newEnforcer('examples/rbac_model.conf', 'examples/rbac_with_hierarchy_policy.csv');
164+
expect(await e.getImplicitUsersForPermission('data1', 'read')).toEqual(['alice']);
165+
expect(await e.getImplicitUsersForPermission('data1', 'write')).toEqual(['alice']);
166+
expect(await e.getImplicitUsersForPermission('data2', 'read')).toEqual(['alice']);
167+
expect(await e.getImplicitUsersForPermission('data2', 'write')).toEqual(['alice', 'bob']);
168+
169+
e.clearPolicy();
170+
171+
await e.addPolicy('admin', 'data1', 'read');
172+
await e.addPolicy('bob', 'data1', 'read');
173+
await e.addGroupingPolicy('alice', 'admin');
174+
175+
expect(await e.getImplicitUsersForPermission('data1', 'read')).toEqual(['bob', 'alice']);
176+
});

0 commit comments

Comments
 (0)