From 784a46f8f403cf18572c22c8779dc1e3dca315ca Mon Sep 17 00:00:00 2001 From: BustDot Date: Mon, 10 Jul 2023 10:38:26 +0800 Subject: [PATCH] feat: add string adapter (#304) --- casbin/persist/adapters/string_adapter.py | 67 ++++++++++++++++++ tests/persist/__init__.py | 0 tests/persist/test_string_adapter.py | 83 +++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 casbin/persist/adapters/string_adapter.py create mode 100644 tests/persist/__init__.py create mode 100644 tests/persist/test_string_adapter.py diff --git a/casbin/persist/adapters/string_adapter.py b/casbin/persist/adapters/string_adapter.py new file mode 100644 index 00000000..0076caee --- /dev/null +++ b/casbin/persist/adapters/string_adapter.py @@ -0,0 +1,67 @@ +# 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. + +from casbin import persist, load_policy_line +import os + +from casbin.util import util + + +class StringAdapter(persist.Adapter): + """the string adapter for Casbin. + It can load policy from string or save policy to string. + """ + + _file_path = "" + + def __init__(self, line): + self.line = line + + def load_policy(self, model): + """loads all policy rules from the storage.""" + if self.line == "": + raise RuntimeError("invalid line, line cannot be empty") + + strs = self.line.split("\n") + for s in strs: + if s == "": + continue + load_policy_line(s, model) + + def save_policy(self, model): + """saves all policy rules to the storage.""" + tmp = [] + for ptype, ast in model["p"].items(): + for rule in ast.policy: + tmp.append(ptype + ", " + util.array_to_string(rule) + "\n") + + for ptype, ast in model["g"].items(): + for rule in ast.policy: + tmp.append(ptype + ", " + util.array_to_string(rule) + "\n") + + self.line = "".join(tmp).rstrip("\n") + + def add_policy(self, sec, ptype, rule): + """adds a policy rule to the storage.""" + raise RuntimeError("not implemented") + + def remove_policy(self, sec, ptype, rule): + """removes a policy rule from the storage.""" + raise RuntimeError("not implemented") + + def remove_filtered_policy(self, sec, ptype, field_index, *field_values): + """removes policy rules that match the filter from the storage. + This is part of the Auto-Save feature. + """ + raise RuntimeError("not implemented") diff --git a/tests/persist/__init__.py b/tests/persist/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/persist/test_string_adapter.py b/tests/persist/test_string_adapter.py new file mode 100644 index 00000000..b0a4b8e9 --- /dev/null +++ b/tests/persist/test_string_adapter.py @@ -0,0 +1,83 @@ +# 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. +from casbin import Model +from casbin.persist.adapters.string_adapter import StringAdapter +from tests import TestCaseBase + + +class TestStringAdapter(TestCaseBase): + def test_key_match_rbac(self): + conf = """ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _ , _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act) +""" + line = """ +p, alice, /alice_data/*, (GET)|(POST) +p, alice, /alice_data/resource1, POST +p, data_group_admin, /admin/*, POST +p, data_group_admin, /bob_data/*, POST +g, alice, data_group_admin +""" + adapter = StringAdapter(line) + model = Model() + model.load_model_from_text(conf) + e = self.get_enforcer(model, adapter) + sub = "alice" + obj = "/alice_data/login" + act = "POST" + self.assertTrue(e.enforce(sub, obj, act)) + + def test_string_rbac(self): + conf = """ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _ , _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act +""" + line = """ +p, alice, data1, read +p, data_group_admin, data3, read +p, data_group_admin, data3, write +g, alice, data_group_admin +""" + adapter = StringAdapter(line) + model = Model() + model.load_model_from_text(conf) + e = self.get_enforcer(model, adapter) + sub = "alice" + obj = "data1" + act = "read" + self.assertTrue(e.enforce(sub, obj, act))