Skip to content

Commit

Permalink
feat: add getImplicitUsersForPermission
Browse files Browse the repository at this point in the history
  • Loading branch information
nodece committed May 3, 2020
1 parent 50b7b9f commit ad9df14
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/enforcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ManagementEnforcer } from './managementEnforcer';
import { Model, newModel } from './model';
import { Adapter, FileAdapter, StringAdapter } from './persist';
import { getLogger } from './log';
import { arrayRemoveDuplicates } from './util';

/**
* Enforcer = ManagementEnforcer + RBAC API.
Expand Down Expand Up @@ -320,6 +321,32 @@ export class Enforcer extends ManagementEnforcer {

return res;
}

/**
* getImplicitUsersForPermission gets implicit users for a permission.
* For example:
* p, admin, data1, read
* p, bob, data1, read
* g, alice, admin
*
* getImplicitUsersForPermission("data1", "read") will get: ["alice", "bob"].
* Note: only users will be returned, roles (2nd arg in "g") will be excluded.
*/
public async getImplicitUsersForPermission(...permission: string[]): Promise<string[]> {
const res: string[] = [];
const policySubjects = await this.getAllSubjects();
const subjects = arrayRemoveDuplicates([...policySubjects, ...this.model.getValuesForFieldInPolicyAllTypes('g', 0)]);
const inherits = this.model.getValuesForFieldInPolicyAllTypes('g', 1);

for (const user of subjects) {
const allowed = await this.enforce(user, ...permission);
if (allowed) {
res.push(user);
}
}

return res.filter(n => !inherits.some(m => n === m));
}
}

export async function newEnforcerWithClass<T extends Enforcer>(enforcer: new () => T, ...params: any[]): Promise<T> {
Expand Down
16 changes: 16 additions & 0 deletions src/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,22 @@ export class Model {
return util.arrayRemoveDuplicates(ast.policy.map((n: string[]) => n[fieldIndex]));
}

// getValuesForFieldInPolicyAllTypes gets all values for a field for all rules in a policy of all ptypes, duplicated values are removed.
public getValuesForFieldInPolicyAllTypes(sec: string, fieldIndex: number): string[] {
const values: string[] = [];

const ast = this.model.get(sec);
if (!ast) {
return values;
}

for (const ptype of ast.keys()) {
values.push(...this.getValuesForFieldInPolicy(sec, ptype, fieldIndex));
}

return util.arrayRemoveDuplicates(values);
}

// printPolicy prints the policy to log.
public printPolicy(): void {
logPrint('Policy:');
Expand Down
16 changes: 16 additions & 0 deletions test/rbacAPI.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,19 @@ test('test deleteUser', async () => {
expect(await e.getImplicitPermissionsForUser('alice')).toEqual([]);
expect(await e.getImplicitPermissionsForUser('bob')).toEqual([]);
});

test('test getImplicitPermissionsForUser', async () => {
const e = await newEnforcer('examples/rbac_model.conf', 'examples/rbac_with_hierarchy_policy.csv');
expect(await e.getImplicitUsersForPermission('data1', 'read')).toEqual(['alice']);
expect(await e.getImplicitUsersForPermission('data1', 'write')).toEqual(['alice']);
expect(await e.getImplicitUsersForPermission('data2', 'read')).toEqual(['alice']);
expect(await e.getImplicitUsersForPermission('data2', 'write')).toEqual(['alice', 'bob']);

e.clearPolicy();

await e.addPolicy('admin', 'data1', 'read');
await e.addPolicy('bob', 'data1', 'read');
await e.addGroupingPolicy('alice', 'admin');

expect(await e.getImplicitUsersForPermission('data1', 'read')).toEqual(['bob', 'alice']);
});

0 comments on commit ad9df14

Please sign in to comment.