Skip to content

Commit

Permalink
fix: Added ABAC policy logic to the private enforcer.
Browse files Browse the repository at this point in the history
fix: Added ABAC policy logic to the private enforcer.

fix: Typecasting.

fix: duplicate code.

fix: avoid unknown.
  • Loading branch information
divy9881 committed May 8, 2020
1 parent 4da5291 commit c6fc487
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 13 deletions.
55 changes: 44 additions & 11 deletions src/coreEnforcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import { DefaultEffector, Effect, Effector } from './effect';
import { FunctionMap, Model, newModel } from './model';
import { Adapter, Filter, FilteredAdapter, Watcher } from './persist';
import { DefaultRoleManager, RoleManager } from './rbac';
import { generateGFunction } from './util';
import { generateGFunction, hasEval, getEvalValue, escapeAssertion, replaceEval } from './util';
import { getLogger, logPrint } from './log';

type Matcher = ((context: object) => Promise<any>) | ((context: object) => any);
/**
* CoreEnforcer defines the core functionality of an enforcer.
*/
Expand All @@ -29,7 +30,7 @@ export class CoreEnforcer {
protected model: Model;
protected fm: FunctionMap = FunctionMap.loadFunctionMap();
protected eft: Effector = new DefaultEffector();
private matcherMap: Map<string, ((context: object) => Promise<any>) | ((context: object) => any)> = new Map();
private matcherMap: Map<string, Matcher> = new Map();

protected adapter: FilteredAdapter | Adapter;
protected watcher: Watcher | null = null;
Expand All @@ -40,6 +41,17 @@ export class CoreEnforcer {
protected autoBuildRoleLinks = true;
protected autoNotifyWatcher = true;

private getExpression(asyncCompile: boolean, exp: string): Matcher {
const matcherKey = `${asyncCompile ? 'ASYNC[' : 'SYNC['}${exp}]`;

let expression = this.matcherMap.get(matcherKey);
if (!expression) {
expression = asyncCompile ? compileAsync(exp) : compile(exp);
this.matcherMap.set(matcherKey, expression);
}
return expression;
}

/**
* loadModel reloads the model from the model CONF file.
* Because the policy is attached to a model,
Expand Down Expand Up @@ -279,12 +291,11 @@ export class CoreEnforcer {
throw new Error('Unable to find policy_effect in model');
}

const matcherKey = `${asyncCompile ? 'ASYNC[' : 'SYNC['}${expString}]`;
const HasEval: boolean = hasEval(expString);
let expression;

let expression = this.matcherMap.get(matcherKey);
if (!expression) {
expression = asyncCompile ? compileAsync(expString) : compile(expString);
this.matcherMap.set(matcherKey, expression);
if (!HasEval) {
expression = this.getExpression(asyncCompile, expString);
}

let policyEffects: Effect[];
Expand Down Expand Up @@ -315,8 +326,26 @@ export class CoreEnforcer {
parameters[token] = p?.policy[i][j];
});

const context = { ...parameters, ...functions };
const result = asyncCompile ? await expression(context) : expression(context);
if (HasEval) {
const ruleNames: string[] = getEvalValue(expString);
let expWithRule = expString;
for (const ruleName of ruleNames) {
if (ruleName in parameters) {
const rule = escapeAssertion(parameters[ruleName]);
expWithRule = replaceEval(expWithRule, rule);
} else {
return false;
}

expression = this.getExpression(asyncCompile, expWithRule);
}
}

let result;
if (expression != undefined) {
const context = { ...parameters, ...functions };
result = asyncCompile ? await expression(context) : expression(context);
}

switch (typeof result) {
case 'boolean':
Expand Down Expand Up @@ -368,8 +397,12 @@ export class CoreEnforcer {
parameters[token] = '';
});

const context = { ...parameters, ...functions };
const result = asyncCompile ? await expression(context) : expression(context);
let result = false;

if (expression != undefined) {
const context = { ...parameters, ...functions };
result = asyncCompile ? await expression(context) : expression(context);
}

if (result) {
policyEffects[0] = Effect.Allow;
Expand Down
5 changes: 4 additions & 1 deletion src/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,11 @@ function replaceEval(s: string, rule: string): string {

// getEvalValue returns the parameters of function eval
function getEvalValue(s: string): string[] {
const subMatch: string[] = s.match(evalReg) as string[];
const subMatch = s.match(evalReg);
const rules: string[] = [];
if (!subMatch) {
return [];
}
for (const rule of subMatch) {
const index: number = rule.indexOf('(');
rules.push(rule.slice(index + 1, -1));
Expand Down
33 changes: 32 additions & 1 deletion test/enforcer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { readFileSync } from 'fs';

import { newModel, newEnforcer, Enforcer, FileAdapter, StringAdapter, Util } from '../src';

async function testEnforce(e: Enforcer, sub: string, obj: string, act: string, res: boolean): Promise<void> {
async function testEnforce(e: Enforcer, sub: any, obj: string, act: string, res: boolean): Promise<void> {
await expect(e.enforce(sub, obj, act)).resolves.toBe(res);
}

Expand Down Expand Up @@ -535,3 +535,34 @@ describe('Unimplemented String Adapter methods', () => {
await expect(a.removeFilteredPolicy('', '', 0, '')).rejects.toThrow('not implemented');
});
});

class TestSub {
Name: string;
Age: number;

constructor(name: string, age: number) {
this.Name = name;
this.Age = age;
}
}

test('test ABAC Scaling', async () => {
const e = await newEnforcer('examples/abac_rule_model.conf', 'examples/abac_rule_policy.csv');

const sub1 = new TestSub('alice', 16);
const sub2 = new TestSub('alice', 20);
const sub3 = new TestSub('alice', 65);

await testEnforce(e, sub1, '/data1', 'read', false);
await testEnforce(e, sub1, '/data2', 'read', false);
await testEnforce(e, sub1, '/data1', 'write', false);
await testEnforce(e, sub1, '/data2', 'write', true);
await testEnforce(e, sub2, '/data1', 'read', true);
await testEnforce(e, sub2, '/data2', 'read', false);
await testEnforce(e, sub2, '/data1', 'write', false);
await testEnforce(e, sub2, '/data2', 'write', true);
await testEnforce(e, sub3, '/data1', 'read', true);
await testEnforce(e, sub3, '/data2', 'read', false);
await testEnforce(e, sub3, '/data1', 'write', false);
await testEnforce(e, sub3, '/data2', 'write', false);
});

0 comments on commit c6fc487

Please sign in to comment.