Skip to content

Commit

Permalink
feat: Multiple sections type (#442)
Browse files Browse the repository at this point in the history
(cherry picked from commit 2635601ab1b1dd8d613bbb6b62d52f1cb86400f6)

Signed-off-by: Gabriel-403 <1499015923@qq.com>
Signed-off-by: Zixuan Liu <nodeces@gmail.com>
Co-authored-by: Gabriel-403 <1499015923@qq.com>
  • Loading branch information
nodece and Gabriel-403 authored Mar 26, 2023
1 parent 1d362b6 commit 48b0d8f
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 12 deletions.
2 changes: 2 additions & 0 deletions examples/mulitple_policy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
p2, alice, data1, read
p2, bob, data2, write
42 changes: 33 additions & 9 deletions src/coreEnforcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { DefaultEffector, Effect, Effector } from './effect';
import { FunctionMap, Model, newModelFromFile, PolicyOp } from './model';
import { Adapter, FilteredAdapter, Watcher, BatchAdapter, UpdatableAdapter, WatcherEx } from './persist';
import { DefaultRoleManager, RoleManager } from './rbac';
import { EnforceContext } from './enforceContext';

import {
escapeAssertion,
generateGFunction,
Expand Down Expand Up @@ -47,6 +49,7 @@ export class CoreEnforcer {
protected fm: FunctionMap = FunctionMap.loadFunctionMap();
protected eft: Effector = new DefaultEffector();
private matcherMap: Map<string, Matcher> = new Map();
private defaultEnforceContext: EnforceContext = new EnforceContext('r', 'p', 'e', 'm');

protected adapter: UpdatableAdapter | FilteredAdapter | Adapter | BatchAdapter;
protected watcher: Watcher | null = null;
Expand Down Expand Up @@ -411,7 +414,12 @@ export class CoreEnforcer {
}
}

private *privateEnforce(asyncCompile = true, explain = false, ...rvals: any[]): EnforceResult {
private *privateEnforce(
asyncCompile = true,
explain = false,
enforceContext: EnforceContext = new EnforceContext('r', 'p', 'e', 'm'),
...rvals: any[]
): EnforceResult {
if (!this.enabled) {
return true;
}
Expand All @@ -430,23 +438,23 @@ export class CoreEnforcer {
functions[key] = asyncCompile ? generateGFunction(rm) : generateSyncedGFunction(rm);
});

const expString = this.model.model.get('m')?.get('m')?.value;
const expString = this.model.model.get('m')?.get(enforceContext.mType)?.value;
if (!expString) {
throw new Error('Unable to find matchers in model');
}

const effectExpr = this.model.model.get('e')?.get('e')?.value;
const effectExpr = this.model.model.get('e')?.get(enforceContext.eType)?.value;
if (!effectExpr) {
throw new Error('Unable to find policy_effect in model');
}

const HasEval: boolean = hasEval(expString);
let expression: Matcher | undefined = undefined;

const p = this.model.model.get('p')?.get('p');
const p = this.model.model.get('p')?.get(enforceContext.pType);
const policyLen = p?.policy?.length;

const rTokens = this.model.model.get('r')?.get('r')?.tokens;
const rTokens = this.model.model.get('r')?.get(enforceContext.rType)?.tokens;
const rTokensLen = rTokens?.length;

const effectStream = this.eft.newStream(effectExpr);
Expand Down Expand Up @@ -594,7 +602,11 @@ export class CoreEnforcer {
* @return whether to allow the request.
*/
public enforceSync(...rvals: any[]): boolean {
return generatorRunSync(this.privateEnforce(false, false, ...rvals));
if (rvals[0] instanceof EnforceContext) {
const enforceContext: EnforceContext = rvals.shift();
return generatorRunSync(this.privateEnforce(false, false, enforceContext, ...rvals));
}
return generatorRunSync(this.privateEnforce(false, false, this.defaultEnforceContext, ...rvals));
}

/**
Expand All @@ -608,7 +620,11 @@ export class CoreEnforcer {
* @return whether to allow the request and the reason rule.
*/
public enforceExSync(...rvals: any[]): [boolean, string[]] {
return generatorRunSync(this.privateEnforce(false, true, ...rvals));
if (rvals[0] instanceof EnforceContext) {
const enforceContext: EnforceContext = rvals.shift();
return generatorRunSync(this.privateEnforce(false, true, enforceContext, ...rvals));
}
return generatorRunSync(this.privateEnforce(false, true, this.defaultEnforceContext, ...rvals));
}

/**
Expand All @@ -627,7 +643,11 @@ export class CoreEnforcer {
* @return whether to allow the request.
*/
public async enforce(...rvals: any[]): Promise<boolean> {
return generatorRunAsync(this.privateEnforce(true, false, ...rvals));
if (rvals[0] instanceof EnforceContext) {
const enforceContext: EnforceContext = rvals.shift();
return generatorRunAsync(this.privateEnforce(true, false, enforceContext, ...rvals));
}
return generatorRunAsync(this.privateEnforce(true, false, this.defaultEnforceContext, ...rvals));
}

/**
Expand All @@ -639,7 +659,11 @@ export class CoreEnforcer {
* @return whether to allow the request and the reason rule.
*/
public async enforceEx(...rvals: any[]): Promise<[boolean, string[]]> {
return generatorRunAsync(this.privateEnforce(true, true, ...rvals));
if (rvals[0] instanceof EnforceContext) {
const enforceContext: EnforceContext = rvals.shift();
return generatorRunAsync(this.privateEnforce(true, true, enforceContext, ...rvals));
}
return generatorRunAsync(this.privateEnforce(true, true, this.defaultEnforceContext, ...rvals));
}

/**
Expand Down
31 changes: 31 additions & 0 deletions src/enforceContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2023 The Casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export class EnforceContext {
public pType: string;
public rType: string;
public eType: string;
public mType: string;

constructor(rType: string, pType: string, eType: string, mType: string) {
this.pType = pType;
this.eType = eType;
this.mType = mType;
this.rType = rType;
}
}

export const newEnforceContext = (index: string): EnforceContext => {
return new EnforceContext('r' + index, 'p' + index, 'e' + index, 'm' + index);
};
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export * from './model';
export * from './persist';
export * from './rbac';
export * from './log';
export * from './enforceContext';
export * from './frontend';
export { Util };
9 changes: 7 additions & 2 deletions src/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@

// escapeAssertion escapes the dots in the assertion,
// because the expression evaluation doesn't support such variable names.

import { mustGetDefaultFileSystem } from '../persist';

function escapeAssertion(s: string): string {
s = s.replace(/(?<!\w)r\./g, 'r_');
s = s.replace(/(?<!\w)p\./g, 'p_');
s = s.replace(/(?<!\w)r[0-9]*\./g, (match) => {
return match.replace('.', '_');
});
s = s.replace(/(?<!\w)p[0-9]*\./g, (match) => {
return match.replace('.', '_');
});
return s;
}

Expand Down
70 changes: 69 additions & 1 deletion test/enforcer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import fs, { readFileSync } from 'fs';

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

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 @@ -753,3 +753,71 @@ test('TestEnforcerWithScopeFileSystem', async () => {
await testEnforce(e, 'bob', 'data2', 'write', true);
await testEnforce(e, 'bob', 'data2', 'read', false);
});

test('TestEnforce Multiple policies config', async () => {
const m = newModel();
m.addDef('r', 'r2', 'sub, obj, act');
m.addDef('p', 'p2', 'sub, obj, act');
m.addDef('g', 'g', '_, _');
m.addDef('e', 'e2', 'some(where (p.eft == allow))');
m.addDef('m', 'm2', 'g(r2.sub, p2.sub) && r2.obj == p2.obj && r2.act == p2.act');
const a = new FileAdapter('examples/mulitple_policy.csv');

const e = await newEnforcer(m, a);

//const e = await getEnforcerWithPath(m);
const enforceContext = new EnforceContext('r2', 'p2', 'e2', 'm2');
await expect(e.enforce(enforceContext, 'alice', 'data1', 'read')).resolves.toStrictEqual(true);
await expect(e.enforce(enforceContext, 'bob', 'data2', 'write')).resolves.toStrictEqual(true);
});

test('new EnforceContext config', async () => {
const m = newModel();
m.addDef('r', 'r2', 'sub, obj, act');
m.addDef('p', 'p2', 'sub, obj, act');
m.addDef('g', 'g', '_, _');
m.addDef('e', 'e2', 'some(where (p.eft == allow))');
m.addDef('m', 'm2', 'g(r2.sub, p2.sub) && r2.obj == p2.obj && r2.act == p2.act');
const a = new FileAdapter('examples/mulitple_policy.csv');

const e = await newEnforcer(m, a);

//const e = await getEnforcerWithPath(m);
const enforceContext = newEnforceContext('2');
await expect(e.enforce(enforceContext, 'alice', 'data1', 'read')).resolves.toStrictEqual(true);
await expect(e.enforce(enforceContext, 'bob', 'data2', 'write')).resolves.toStrictEqual(true);
});

test('TestEnforceEX Multiple policies config', async () => {
const m = newModel();
m.addDef('r', 'r2', 'sub, obj, act');
m.addDef('p', 'p2', 'sub, obj, act');
m.addDef('g', 'g', '_, _');
m.addDef('e', 'e2', 'some(where (p.eft == allow))');
m.addDef('m', 'm2', 'g(r2.sub, p2.sub) && r2.obj == p2.obj && r2.act == p2.act');
const a = new FileAdapter('examples/mulitple_policy.csv');

const e = await newEnforcer(m, a);

//const e = await getEnforcerWithPath(m);
const enforceContext = new EnforceContext('r2', 'p2', 'e2', 'm2');
await expect(e.enforceEx(enforceContext, 'alice', 'data1', 'read')).resolves.toStrictEqual([true, ['alice', 'data1', 'read']]);
await expect(e.enforceEx(enforceContext, 'bob', 'data2', 'write')).resolves.toStrictEqual([true, ['bob', 'data2', 'write']]);
});

test('new EnforceContextEX config', async () => {
const m = newModel();
m.addDef('r', 'r2', 'sub, obj, act');
m.addDef('p', 'p2', 'sub, obj, act');
m.addDef('g', 'g', '_, _');
m.addDef('e', 'e2', 'some(where (p.eft == allow))');
m.addDef('m', 'm2', 'g(r2.sub, p2.sub) && r2.obj == p2.obj && r2.act == p2.act');
const a = new FileAdapter('examples/mulitple_policy.csv');

const e = await newEnforcer(m, a);

//const e = await getEnforcerWithPath(m);
const enforceContext = newEnforceContext('2');
await expect(e.enforceEx(enforceContext, 'alice', 'data1', 'read')).resolves.toStrictEqual([true, ['alice', 'data1', 'read']]);
await expect(e.enforceEx(enforceContext, 'bob', 'data2', 'write')).resolves.toStrictEqual([true, ['bob', 'data2', 'write']]);
});

0 comments on commit 48b0d8f

Please sign in to comment.