From dc8e359bec5f75ead58d6d59fb0d3dfd08bee5f0 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Tue, 1 Jun 2021 19:08:30 +0530 Subject: [PATCH] feat: Added Internal API test and fix: errors with Internal API Signed-off-by: Rushikesh Tote --- Setup-OpenResty.md | 2 +- src/main/Enforcer.lua | 4 +- src/main/InternalEnforcer.lua | 66 ++++++------ src/model/Policy.lua | 8 +- src/persist/file_adapter/FileAdapter.lua | 7 ++ tests/main/internal_api_spec.lua | 128 +++++++++++++++++++++++ tests/model/model_spec.lua | 4 +- 7 files changed, 181 insertions(+), 38 deletions(-) create mode 100644 tests/main/internal_api_spec.lua diff --git a/Setup-OpenResty.md b/Setup-OpenResty.md index 61db00e..70cc847 100644 --- a/Setup-OpenResty.md +++ b/Setup-OpenResty.md @@ -59,7 +59,7 @@ Since the project isn't a LuaRocks/OPM module yet, you need to clone it to use i **NOTE**: You may need to add the `nginx` command to your path by adding `export PATH="/usr/local/openresty/nginx/sbin/:$PATH"` to your `.bashrc` or similar file. You can create a lua module for OpenResty applications as shown [here](https://blog.openresty.com/en/or-lua-module/) or add it to your existing lua module by following these steps: -- In your module, clone the Lua Casbin repo at the top level (`/`) of your application (along with the `conf` director) with `git clone https://github.com/casbin/lua-casbin.git`. +- In your module, clone the Lua Casbin repo at the top level (`/`) of your application (along with the `conf` directory) with `git clone https://github.com/casbin/lua-casbin.git`. - In your module's `conf/nginx.conf` file append the `lua_package_path` with `$prefix/lua-casbin/?.lua;` so that it becomes something like this: `lua_package_path "$prefix/lua/?.lua;$prefix/lua-casbin/?.lua;;";`. - In the file where you want to use Casbin, use `local Enforcer = require("src/main/Enforcer")` inside the `content_by_lua_block`. Here is a sample describing usage for basic model/policy and ABAC model/policy: diff --git a/src/main/Enforcer.lua b/src/main/Enforcer.lua index 362629a..7c54a68 100644 --- a/src/main/Enforcer.lua +++ b/src/main/Enforcer.lua @@ -12,9 +12,9 @@ --See the License for the specific language governing permissions and --limitations under the License. -require("src.main.CoreEnforcer") +require("src.main.InternalEnforcer") Enforcer = {} -setmetatable(Enforcer, CoreEnforcer) +setmetatable(Enforcer, InternalEnforcer) return Enforcer \ No newline at end of file diff --git a/src/main/InternalEnforcer.lua b/src/main/InternalEnforcer.lua index adf89bc..eacd672 100644 --- a/src/main/InternalEnforcer.lua +++ b/src/main/InternalEnforcer.lua @@ -34,8 +34,9 @@ function InternalEnforcer:addPolicy(sec, ptype, rule) if self.adapter and self.autoSave then local status, err = pcall(function () self.adapter:addPolicy(sec, ptype, rule) end) - if status == false then - Util.logPrintf("method not implemented or "..err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end @@ -49,7 +50,7 @@ function InternalEnforcer:addPolicy(sec, ptype, rule) end return true - --TODO: update watcher + --TODO: update watcher, add logger end --[[ @@ -67,8 +68,9 @@ function InternalEnforcer:addPolicies(sec, ptype, rules) self.adapter:addPolicies(sec, ptype, rules) end end) - if status == false then - Util.logPrintf("method not implemented or "..err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end @@ -80,7 +82,7 @@ function InternalEnforcer:addPolicies(sec, ptype, rules) end return true - --TODO: update watcher + --TODO: update watcher, add logger end --[[ @@ -90,7 +92,7 @@ end * @param rules the rules. ]] function InternalEnforcer:buildIncrementalRoleLinks(op, ptype, rules) - self.model:buildIncrementalRoleLinks(self.rm, op, "g", ptype, rules) + self.model:buildIncrementalRoleLinks(self.rmMap[ptype], op, "g", ptype, rules) end --[[ @@ -100,8 +102,9 @@ function InternalEnforcer:removePolicy(sec, ptype, rule) if self.adapter and self.autoSave then local status, err = pcall(function () self.adapter:removePolicy(sec, ptype, rule) end) - if status == false then - Util.logPrintf("method not implemented or "..err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end @@ -119,7 +122,7 @@ function InternalEnforcer:removePolicy(sec, ptype, rule) end return true - -- TODO: update watcher + -- TODO: update watcher, add logger end --[[ @@ -132,12 +135,13 @@ end ]] function InternalEnforcer:updatePolicy(sec, ptype, oldRule, newRule) -- TODO: update dispatcher - + if self.adapter and self.autoSave then local status, err = pcall(function () self.adapter:updatePolicy(sec, ptype, oldRule, newRule) end) - if status == false then - Util.logPrintf("method not implemented or "..err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end @@ -154,8 +158,9 @@ function InternalEnforcer:updatePolicy(sec, ptype, oldRule, newRule) table.insert(oldRules, oldRule) self:buildIncrementalRoleLinks(self.model.PolicyOperations.POLICY_REMOVE, ptype, oldRules) end) - if status == false then - Util.logPrintf(err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end @@ -164,21 +169,22 @@ function InternalEnforcer:updatePolicy(sec, ptype, oldRule, newRule) table.insert(newRules, newRule) self:buildIncrementalRoleLinks(self.model.PolicyOperations.POLICY_ADD, ptype, newRules) end) - if status == false then - Util.logPrintf(err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end return true - -- TODO: update watcher + -- TODO: update watcher, add logger end --[[ * removePolicies removes rules from the current policy. ]] function InternalEnforcer:removePolicies(sec, ptype, rules) - if self.model:hasPolicies(sec, ptype, rules) then + if not self.model:hasPolicies(sec, ptype, rules) then return false end @@ -189,8 +195,9 @@ function InternalEnforcer:removePolicies(sec, ptype, rules) self.adapter:removePolicies(sec, ptype, rules) end end) - if status == false then - Util.logPrintf("method not implemented or "..err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end @@ -206,7 +213,7 @@ function InternalEnforcer:removePolicies(sec, ptype, rules) end return true - -- TODO: update watcher + -- TODO: update watcher, add logger end --[[ @@ -214,30 +221,29 @@ end ]] function InternalEnforcer:removeFilteredPolicy(sec, ptype, fieldIndex, fieldValues) if fieldValues == nil or #fieldValues == 0 then - Util.logPrintf("Invaild fieldValues parameter") return false end if self.adapter and self.autoSave then local status, err = pcall(function () self.adapter:removeFilteredPolicy(sec, ptype, fieldIndex, fieldValues) end) - if status == false then - Util.logPrintf("method not implemented or "..err) + if status == false and string.sub(err, -15) == "not implemented" then + -- log, continue + elseif status == false then return false end end - local effects = self.model:removeFilteredPolicyReturnsEffects(sec, ptype, fieldIndex, fieldValues) - local ruleRemoved = #effects > 0 + local isRuleRemoved, effects = self.model:removeFilteredPolicy(sec, ptype, fieldIndex, fieldValues) - if not ruleRemoved then + if not isRuleRemoved then return false end if sec == "g" then - self:buildIncrementalRoleLinks(self.model.PolicyOperations.POLICY_ADD, ptype, effects) + self:buildIncrementalRoleLinks(self.model.PolicyOperations.POLICY_REMOVE, ptype, effects) end return true - -- TODO: update watcher + -- TODO: update watcher, add logger end diff --git a/src/model/Policy.lua b/src/model/Policy.lua index 6fadb44..a2bc5b4 100644 --- a/src/model/Policy.lua +++ b/src/model/Policy.lua @@ -222,6 +222,7 @@ function Policy:updatePolicy(sec, ptype, oldRule, newRule) if Util.arrayEquals(oldRule, v) then table.remove(self.model[sec][ptype].policy, k) table.insert(self.model[sec][ptype].policy, newRule) + return true end end end @@ -305,10 +306,10 @@ end * means not to match this field. * @return succeeds or not. ]] -function Policy:removeFilteredPolicy(sec, ptype, fieldIndex, ...) +function Policy:removeFilteredPolicy(sec, ptype, fieldIndex, fieldValues) local tmp = {} local res = false - local fieldValues = {...} + local effects = {} if not self.model[sec] then return res end if not self.model[sec][ptype] then return res end @@ -323,6 +324,7 @@ function Policy:removeFilteredPolicy(sec, ptype, fieldIndex, ...) end if matched then + table.insert(effects, rule) res = true else table.insert(tmp, rule) @@ -330,7 +332,7 @@ function Policy:removeFilteredPolicy(sec, ptype, fieldIndex, ...) end self.model[sec][ptype].policy = tmp - return res + return res, effects end --[[ diff --git a/src/persist/file_adapter/FileAdapter.lua b/src/persist/file_adapter/FileAdapter.lua index 3c5d470..d71f8b7 100644 --- a/src/persist/file_adapter/FileAdapter.lua +++ b/src/persist/file_adapter/FileAdapter.lua @@ -97,6 +97,13 @@ function FileAdapter:removePolicy(sec, ptype, rule) error("not implemented") end +--[[ + * updatePolicy updates a policy rule from the storage +]] +function FileAdapter:updatePolicy(sec, ptype, oldRule, newRule) + error("not implemented") +end + --[[ * removeFilteredPolicy removes policy rules that match the filter from the storage. ]] diff --git a/tests/main/internal_api_spec.lua b/tests/main/internal_api_spec.lua new file mode 100644 index 0000000..bed205e --- /dev/null +++ b/tests/main/internal_api_spec.lua @@ -0,0 +1,128 @@ +--Copyright 2021 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. + +local enforcer_module = require("src.main.Enforcer") +local path = os.getenv("PWD") or io.popen("cd"):read() + +describe("Internal API tests", function () + it("Add Policy test", function () + local model = path .. "/examples/rbac_model.conf" + local policy = path .. "/examples/rbac_policy.csv" + + local e = Enforcer:new(model, policy) + + assert.is.False(e:enforce("alice", "data1", "write")) + e:addPolicy("p", "p", {"alice", "data1", "write"}) + assert.is.True(e:enforce("alice", "data1", "write")) + + assert.is.False(e:enforce("bob", "data2", "read")) + e:addPolicy("g", "g", {"bob", "data2_admin"}) + assert.is.True(e:enforce("bob", "data2", "read")) + end) + + it("Remove Policy tests", function () + local model = path .. "/examples/rbac_model.conf" + local policy = path .. "/examples/rbac_policy.csv" + + local e = Enforcer:new(model, policy) + + assert.is.True(e:enforce("alice", "data1", "read")) + e:removePolicy("p", "p", {"alice", "data1", "read"}) + assert.is.False(e:enforce("alice", "data1", "read")) + + assert.is.True(e:enforce("alice", "data2", "read")) + assert.is.True(e:enforce("alice", "data2", "write")) + e:removePolicy("g", "g", {"alice", "data2_admin"}) + assert.is.False(e:enforce("alice", "data2", "read")) + assert.is.False(e:enforce("alice", "data2", "write")) + end) + + it("Update Policy tests", function () + local model = path .. "/examples/rbac_model.conf" + local policy = path .. "/examples/rbac_policy.csv" + + local e = Enforcer:new(model, policy) + + assert.is.True(e:enforce("alice", "data1", "read")) + assert.is.False(e:enforce("alice", "data1", "write")) + e:updatePolicy("p", "p", {"alice", "data1", "read"}, {"alice", "data1", "write"}) + assert.is.False(e:enforce("alice", "data1", "read")) + assert.is.True(e:enforce("alice", "data1", "write")) + + assert.is.True(e:enforce("alice", "data2", "read")) + assert.is.False(e:enforce("bob", "data2", "read")) + e:updatePolicy("g", "g", {"alice", "data2_admin"}, {"bob", "data2_admin"}) + assert.is.False(e:enforce("alice", "data2", "read")) + assert.is.True(e:enforce("bob", "data2", "read")) + end) + + it("Add/Remove Policies test", function () + local model = path .. "/examples/rbac_model.conf" + local policy = path .. "/examples/rbac_policy.csv" + + local e = Enforcer:new(model, policy) + + local rules = { + {"cathy", "data1", "read"}, + {"cathy", "data1", "write"} + } + assert.is.False(e:enforce("cathy", "data1", "read")) + assert.is.False(e:enforce("cathy", "data1", "write")) + e:addPolicies("p", "p", rules) + assert.is.True(e:enforce("cathy", "data1", "read")) + assert.is.True(e:enforce("cathy", "data1", "write")) + + e:removePolicies("p", "p", rules) + assert.is.False(e:enforce("cathy", "data1", "read")) + assert.is.False(e:enforce("cathy", "data1", "write")) + + rules = { + {"cathy", "data2_admin"} + } + + assert.is.False(e:enforce("cathy", "data2", "read")) + assert.is.False(e:enforce("cathy", "data2", "write")) + e:addPolicies("g", "g", rules) + assert.is.True(e:enforce("cathy", "data2", "read")) + assert.is.True(e:enforce("cathy", "data2", "write")) + end) + + it("removeFilteredPolicy test", function () + local model = path .. "/examples/rbac_model.conf" + local policy = path .. "/examples/rbac_policy.csv" + + local e = Enforcer:new(model, policy) + + local rules = { + {"cathy", "data1", "read"}, + {"cathy", "data1", "write"} + } + e:addPolicies("p", "p", rules) + + assert.is.True(e:enforce("cathy", "data1", "read")) + assert.is.True(e:enforce("cathy", "data1", "write")) + + e:removeFilteredPolicy("p", "p", 0, {"cathy"}) + assert.is.False(e:enforce("cathy", "data1", "read")) + assert.is.False(e:enforce("cathy", "data1", "write")) + + assert.is.True(e:enforce("alice", "data2", "read")) + assert.is.True(e:enforce("alice", "data2", "write")) + + e:removeFilteredPolicy("g", "g", 0, {"alice"}) + e.model:printPolicy() + assert.is.False(e:enforce("alice", "data2", "read")) + assert.is.False(e:enforce("alice", "data2", "write")) + end) +end) \ No newline at end of file diff --git a/tests/model/model_spec.lua b/tests/model/model_spec.lua index c8a4519..d5df0a4 100644 --- a/tests/model/model_spec.lua +++ b/tests/model/model_spec.lua @@ -157,10 +157,10 @@ describe("model tests", function() local rule = {'admin', 'domain1', 'data1', 'read'} m:addPolicy("p", "p", rule) - local res = m:removeFilteredPolicy("p", "p", 1, "domain1", "data1") + local res = m:removeFilteredPolicy("p", "p", 1, {"domain1", "data1"}) assert.is.True(res) - local res = m:removeFilteredPolicy("p", "p", 1, "domain1", "data1") + local res = m:removeFilteredPolicy("p", "p", 1, {"domain1", "data1"}) assert.is.False(res) end)