diff --git a/examples/mulitple_policy.csv b/examples/mulitple_policy.csv new file mode 100644 index 0000000..f896c69 --- /dev/null +++ b/examples/mulitple_policy.csv @@ -0,0 +1,2 @@ +p2, alice, data1, read +p2, bob, data2, write \ No newline at end of file diff --git a/src/coreEnforcer.ts b/src/coreEnforcer.ts index 489e341..c58e97d 100644 --- a/src/coreEnforcer.ts +++ b/src/coreEnforcer.ts @@ -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, @@ -47,6 +49,7 @@ export class CoreEnforcer { protected fm: FunctionMap = FunctionMap.loadFunctionMap(); protected eft: Effector = new DefaultEffector(); private matcherMap: Map = new Map(); + private defaultEnforceContext: EnforceContext = new EnforceContext('r', 'p', 'e', 'm'); protected adapter: UpdatableAdapter | FilteredAdapter | Adapter | BatchAdapter; protected watcher: Watcher | null = null; @@ -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; } @@ -430,12 +438,12 @@ 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'); } @@ -443,10 +451,10 @@ export class CoreEnforcer { 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); @@ -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)); } /** @@ -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)); } /** @@ -627,7 +643,11 @@ export class CoreEnforcer { * @return whether to allow the request. */ public async enforce(...rvals: any[]): Promise { - 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)); } /** @@ -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)); } /** diff --git a/src/enforceContext.ts b/src/enforceContext.ts new file mode 100644 index 0000000..eb9bcc5 --- /dev/null +++ b/src/enforceContext.ts @@ -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); +}; diff --git a/src/index.ts b/src/index.ts index 6658ac2..a6500aa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,5 +24,6 @@ export * from './model'; export * from './persist'; export * from './rbac'; export * from './log'; +export * from './enforceContext'; export * from './frontend'; export { Util }; diff --git a/src/util/util.ts b/src/util/util.ts index 6b18c7b..56e6719 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -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(/(? { + return match.replace('.', '_'); + }); + s = s.replace(/(? { + return match.replace('.', '_'); + }); return s; } diff --git a/test/enforcer.test.ts b/test/enforcer.test.ts index 75aa0ff..a98cc20 100644 --- a/test/enforcer.test.ts +++ b/test/enforcer.test.ts @@ -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 { await expect(e.enforce(sub, obj, act)).resolves.toBe(res); @@ -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']]); +});