From a44c6a99ed36634a67e7888472e8f6d324b257f4 Mon Sep 17 00:00:00 2001 From: Zxilly Date: Sun, 13 Jun 2021 16:57:58 +0800 Subject: [PATCH] feat: add support for `in` operator Signed-off-by: Zxilly --- examples/in_operator_model.conf | 11 +++++++++++ package.json | 2 +- src/coreEnforcer.ts | 8 +++++++- test/frontend.test.ts | 5 +++-- test/model.test.ts | 30 ++++++++++++++++++++++++++++++ yarn.lock | 8 ++++---- 6 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 examples/in_operator_model.conf diff --git a/examples/in_operator_model.conf b/examples/in_operator_model.conf new file mode 100644 index 0000000..452325c --- /dev/null +++ b/examples/in_operator_model.conf @@ -0,0 +1,11 @@ +[request_definition] +r = sub, obj + +[policy_definition] +p = sub, obj, act + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = r.sub.Owner == r.obj.Owner && r.sub.Doc in(r.obj.Docs) diff --git a/package.json b/package.json index 647cdb1..e3aad06 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "dependencies": { "await-lock": "^2.0.1", "csv-parse": "^4.15.3", - "expression-eval": "^2.0.0", + "expression-eval": "^4.0.0", "picomatch": "^2.2.3" }, "files": [ diff --git a/src/coreEnforcer.ts b/src/coreEnforcer.ts index f4ec298..19e2d21 100644 --- a/src/coreEnforcer.ts +++ b/src/coreEnforcer.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { compile, compileAsync } from 'expression-eval'; +import { compile, compileAsync, addBinaryOp } from 'expression-eval'; import { DefaultEffector, Effect, Effector } from './effect'; import { FunctionMap, Model, newModel, PolicyOp } from './model'; @@ -48,6 +48,12 @@ export class CoreEnforcer { private getExpression(asyncCompile: boolean, exp: string): Matcher { const matcherKey = `${asyncCompile ? 'ASYNC[' : 'SYNC['}${exp}]`; + addBinaryOp('in', 1, (a, b) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return (a in b) as number; + }); + let expression = this.matcherMap.get(matcherKey); if (!expression) { expression = asyncCompile ? compileAsync(exp) : compile(exp); diff --git a/test/frontend.test.ts b/test/frontend.test.ts index 3d2bc9a..24a8a1c 100644 --- a/test/frontend.test.ts +++ b/test/frontend.test.ts @@ -13,8 +13,8 @@ // limitations under the License. import { readFileSync } from 'fs'; -import { newEnforcer } from '../src/index'; -import { casbinJsGetPermissionForUser } from '../src/frontend'; +import { newEnforcer } from '../src'; +import { casbinJsGetPermissionForUser } from '../src'; test('TestCasbinJsGetPermissionForUser', async () => { const e = await newEnforcer('examples/rbac_model.conf', 'examples/rbac_with_hierarchy_policy.csv'); @@ -25,6 +25,7 @@ test('TestCasbinJsGetPermissionForUser', async () => { } const received = JSON.parse(await casbinJsGetPermissionForUser(e, 'alice')); const expectedModelStr = readFileSync('examples/rbac_model.conf').toString(); + // If you enable CR_LF auto transfer on Windows platform, this can lead to some unexpected behavior. expect(received['m']).toBe(expectedModelStr.replace(/\n\n/g, '\n')); const expectedPoliciesStr = readFileSync('examples/rbac_with_hierarchy_policy.csv').toString(); const expectedPolicyItem = expectedPoliciesStr.split(RegExp(',|\n')); diff --git a/test/model.test.ts b/test/model.test.ts index 60af91a..433f5f2 100644 --- a/test/model.test.ts +++ b/test/model.test.ts @@ -11,6 +11,7 @@ // 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. +// noinspection JSMismatchedCollectionQueryUpdate import * as _ from 'lodash'; import { DefaultRoleManager, Enforcer, newEnforcer, newModel } from '../src'; @@ -418,3 +419,32 @@ test('TestAllMatchModel', async () => { await testDomainEnforce(e, 'alice', 'domain2', '/book/1', 'read', false); await testDomainEnforce(e, 'alice', 'domain2', '/book/1', 'write', true); }); + +test('ABACModelWithInOperator', async () => { + const e = await newEnforcer('examples/in_operator_model.conf'); + + class TestRule1 { + public Owner: string; + public Doc: number; + + constructor(Owner: string, Doc: number) { + this.Owner = Owner; + this.Doc = Doc; + } + } + + class TestRule2 { + public Owner: string; + public Docs: Array; + + constructor(Owner: string, Doc: Array) { + this.Owner = Owner; + this.Docs = Doc; + } + } + + const rule1 = new TestRule1('alice', 1); + const rule2 = new TestRule2('alice', [1, 2]); + + await expect(e.enforce(rule1, rule2)).resolves.toBe(true); +}); diff --git a/yarn.lock b/yarn.lock index babcaa9..f9dce0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2828,10 +2828,10 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" -expression-eval@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/expression-eval/-/expression-eval-2.1.0.tgz#422915caa46140a7c5b5f248650dea8bf8236e62" - integrity sha512-FUJO/Akvl/JOWkvlqZaqbkhsEWlCJWDeZG4tzX96UH68D9FeRgYgtb55C2qtqbORC0Q6x5419EDjWu4IT9kQfg== +expression-eval@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/expression-eval/-/expression-eval-4.0.0.tgz#d6a07c93e8b33e635710419d4a595d9208b9cc5e" + integrity sha512-YHSnLTyIb9IKaho2IdQbvlei/pElxnGm48UgaXJ1Fe5au95Ck0R9ftm6rHJQuKw3FguZZ4eXVllJFFFc7LX0WQ== dependencies: jsep "^0.3.0"