first commit
diff --git a/casbin_sqlobject_adapter/__init__.py b/casbin_sqlobject_adapter/__init__.py new file mode 100644 index 0000000..78b6b09 --- /dev/null +++ b/casbin_sqlobject_adapter/__init__.py
@@ -0,0 +1 @@ +from .adapter import CasbinRule, Adapter
diff --git a/casbin_sqlobject_adapter/adapter.py b/casbin_sqlobject_adapter/adapter.py new file mode 100644 index 0000000..1001474 --- /dev/null +++ b/casbin_sqlobject_adapter/adapter.py
@@ -0,0 +1,82 @@ +from casbin import persist +from sqlobject import * + + +class CasbinRule(SQLObject): + + class sqlmeta: + + table = 'casbin_rule' + + ptype = StringCol(length=255) + v0 = StringCol(length=255, default=None) + v1 = StringCol(length=255, default=None) + v2 = StringCol(length=255, default=None) + v3 = StringCol(length=255, default=None) + v4 = StringCol(length=255, default=None) + v5 = StringCol(length=255, default=None) + + def __str__(self): + arr = [self.ptype] + for v in (self.v0, self.v1, self.v2, self.v3, self.v4, self.v5): + if v is None: + break + arr.append(v) + return ', '.join(arr) + + def __repr__(self): + return '<CasbinRule {}: "{}">'.format(self.id, str(self)) + + + + + +class Adapter(persist.Adapter): + """the interface for Casbin adapters.""" + + def __init__(self, connection_string): + self._conhandler = connectionForURI(connection_string) + sqlhub.processConnection = self._conhandler + + + def load_policy(self, model): + """loads all policy rules from the storage.""" + count = CasbinRule.select().count() + for i in range(1,1+count): + line = CasbinRule.get(i) + persist.load_policy_line(str(line), model) + + def _save_policy_line(self, ptype, rule): + line = CasbinRule.selectBy(ptype=ptype) + for i, v in enumerate(rule): + setattr(line, 'v{}'.format(i), v) + + + def save_policy(self, model): + """saves all policy rules to the storage.""" + for sec in ["p", "g"]: + if sec not in model.model.keys(): + continue + for ptype, ast in model.model[sec].items(): + for rule in ast.policy: + self._save_policy_line(ptype, rule) + + return True + + def add_policy(self, sec, ptype, rule): + """adds a policy rule to the storage.""" + self._save_policy_line(ptype, rule) + + + def remove_policy(self, sec, ptype, rule): + """removes a policy rule from the storage.""" + pass + + 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. + """ + pass + + +
diff --git a/tests/rbac_model.conf b/tests/rbac_model.conf new file mode 100644 index 0000000..71159e3 --- /dev/null +++ b/tests/rbac_model.conf
@@ -0,0 +1,14 @@ +[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 \ No newline at end of file
diff --git a/tests/rbac_policy.csv b/tests/rbac_policy.csv new file mode 100644 index 0000000..9bbfa7c --- /dev/null +++ b/tests/rbac_policy.csv
@@ -0,0 +1,6 @@ +p, alice, data1, read +p, bob, data2, write +p, data2_admin, data2, read +p, data2_admin, data2, write + +g, alice, data2_admin \ No newline at end of file
diff --git a/tests/test_adapter.py b/tests/test_adapter.py new file mode 100644 index 0000000..70538bb --- /dev/null +++ b/tests/test_adapter.py
@@ -0,0 +1,72 @@ +import os +import unittest + +import casbin + +from casbin_sqlobject_adapter import Adapter +from casbin_sqlobject_adapter import CasbinRule + + +def get_fixture(path): + dir_path = os.path.split(os.path.realpath(__file__))[0] + "/" + return os.path.abspath(dir_path + path) + + +def get_enforcer(): + con_string = 'sqlite:/:memory:' + adapter = Adapter(con_string) + + CasbinRule.createTable(ifNotExists=True) + CasbinRule(ptype='p', v0='alice', v1='data1', v2='read') + CasbinRule(ptype='p', v0='bob', v1='data2', v2='write') + CasbinRule(ptype='p', v0='data2_admin', v1='data2', v2='read') + CasbinRule(ptype='p', v0='data2_admin', v1='data2', v2='write') + CasbinRule(ptype='g', v0='alice', v1='data2_admin') + + return casbin.Enforcer(get_fixture('rbac_model.conf'), adapter) + + +class TestConfig(unittest.TestCase): + + def test_enforcer_basic(self): + e = get_enforcer() + + self.assertTrue(e.enforce('alice', 'data1', 'read')) + self.assertFalse(e.enforce('bob', 'data1', 'read')) + self.assertTrue(e.enforce('bob', 'data2', 'write')) + self.assertTrue(e.enforce('alice', 'data2', 'read')) + self.assertTrue(e.enforce('alice', 'data2', 'write')) + + def test_add_policy(self): + e = get_enforcer() + + self.assertFalse(e.enforce('eve', 'data3', 'read')) + res = e.add_permission_for_user('eve', 'data3', 'read') + self.assertTrue(res) + self.assertTrue(e.enforce('eve', 'data3', 'read')) + + def test_save_policy(self): + e = get_enforcer() + self.assertFalse(e.enforce('alice', 'data4', 'read')) + + model = e.get_model() + model.clear_policy() + + model.add_policy('p', 'p', ['alice', 'data4', 'read']) + + adapter = e.get_adapter() + adapter.save_policy(model) + self.assertTrue(e.enforce('alice', 'data4', 'read')) + + def test_str(self): + rule = CasbinRule(ptype='p', v0='alice', v1='data1', v2='read') + self.assertEqual(str(rule), 'p, alice, data1, read') + + + def test_repr(self): + rule = CasbinRule(ptype='p', v0='alice', v1='data1', v2='read') + self.assertRegex(repr(rule), r'<CasbinRule \d+: "p, alice, data1, read">') + +if(__name__=='__main__'): + unittest.main() +