Skip to content

Commit 9445086

Browse files
authored
feat: add explicit priority support (#190)
* feat: added explicit priority support Signed-off-by: ffyuanda <46557895+ffyuanda@users.noreply.github.com> * feat: updated load_policy to match casbin Signed-off-by: ffyuanda <shaoxuan.yuan02@gmail.com>
1 parent 357be23 commit 9445086

File tree

7 files changed

+112
-13
lines changed

7 files changed

+112
-13
lines changed

casbin/core_enforcer.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import logging
1+
import logging, copy
22

33
from casbin.effect import Effector, get_effector, effect_to_bool
44
from casbin.model import Model, FunctionMap
@@ -177,14 +177,36 @@ def init_rm_map(self):
177177

178178
def load_policy(self):
179179
"""reloads the policy from file/database."""
180+
need_to_rebuild = False
181+
new_model = copy.copy(self.model)
182+
new_model.clear_policy()
180183

181-
self.model.clear_policy()
182-
self.adapter.load_policy(self.model)
184+
try:
183185

184-
self.init_rm_map()
185-
self.model.print_policy()
186-
if self.auto_build_role_links:
187-
self.build_role_links()
186+
self.adapter.load_policy(new_model)
187+
188+
new_model.sort_policies_by_priority()
189+
190+
self.init_rm_map()
191+
self.model.print_policy()
192+
193+
if self.auto_build_role_links:
194+
195+
need_to_rebuild = True
196+
for rm in self.rm_map.values():
197+
rm.clear()
198+
199+
new_model.build_role_links(self.rm_map)
200+
self.build_role_links()
201+
202+
self.model = new_model
203+
204+
except Exception as e:
205+
206+
if self.auto_build_role_links and need_to_rebuild:
207+
self.build_role_links()
208+
209+
raise e
188210

189211
def load_filtered_policy(self, filter):
190212
"""reloads a filtered policy from file/database."""
@@ -194,6 +216,9 @@ def load_filtered_policy(self, filter):
194216
raise ValueError("filtered policies are not supported by this adapter")
195217

196218
self.adapter.load_filtered_policy(self.model, filter)
219+
220+
self.model.sort_policies_by_priority()
221+
197222
self.init_rm_map()
198223
self.model.print_policy()
199224
if self.auto_build_role_links:

casbin/effect/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_effector(expr):
1616
return DenyOverrideEffector()
1717
elif expr == "some(where (p_eft == allow)) && !some(where (p_eft == deny))":
1818
return AllowAndDenyEffector()
19-
elif expr == "priority(p_eft) || deny":
19+
elif expr == "priority(p_eft) || deny" or expr == "subjectPriority(p_eft) || deny":
2020
return PriorityEffector()
2121
else:
2222
raise RuntimeError("unsupported effect")

casbin/model/assertion.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ def __init__(self):
1010
self.tokens = []
1111
self.policy = []
1212
self.rm = None
13+
self.priority_index: int = -1
14+
self.policy_map: dict = {}
1315

1416
def build_role_links(self, rm):
1517
self.rm = rm

casbin/model/model.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,22 @@ def print_model(self):
7979
for k, v in self.items():
8080
for i, j in v.items():
8181
self.logger.info("%s.%s: %s", k, i, j.value)
82+
83+
def sort_policies_by_priority(self):
84+
for ptype, assertion in self["p"].items():
85+
for index, token in enumerate(assertion.tokens):
86+
if token == f"{ptype}_priority":
87+
assertion.priority_index = index
88+
break
89+
90+
if assertion.priority_index == -1:
91+
continue
92+
93+
assertion.policy = sorted(
94+
assertion.policy, key=lambda x: x[assertion.priority_index]
95+
)
96+
97+
for i, policy in enumerate(assertion.policy):
98+
assertion.policy_map[",".join(policy)] = i
99+
100+
return None

casbin/model/policy.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import logging
22

3+
DEFAULT_SEP = ","
4+
35

46
class Policy:
57
def __init__(self):
@@ -83,12 +85,37 @@ def has_policy(self, sec, ptype, rule):
8385

8486
def add_policy(self, sec, ptype, rule):
8587
"""adds a policy rule to the model."""
86-
88+
assertion = self[sec][ptype]
8789
if not self.has_policy(sec, ptype, rule):
88-
self[sec][ptype].policy.append(rule)
89-
return True
90+
assertion.policy.append(rule)
91+
else:
92+
return False
93+
94+
if sec == "p" and assertion.priority_index >= 0:
95+
try:
96+
idx_insert = int(rule[assertion.priority_index])
9097

91-
return False
98+
i = len(assertion.policy) - 1
99+
for i in range(i, 0, -1):
100+
101+
try:
102+
idx = int(assertion.policy[i - 1][assertion.priority_index])
103+
except Exception as e:
104+
print(e)
105+
106+
if idx > idx_insert:
107+
assertion.policy[i] = assertion.policy[i - 1]
108+
else:
109+
break
110+
111+
assertion.policy[i] = rule
112+
assertion.policy_map[DEFAULT_SEP.join(rule)] = i
113+
114+
except Exception as e:
115+
print(e)
116+
117+
assertion.policy_map[DEFAULT_SEP.join(rule)] = len(assertion.policy) - 1
118+
return True
92119

93120
def add_policies(self, sec, ptype, rules):
94121
"""adds policy rules to the model."""

examples/priority_model_explicit.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ g = _, _
1111
e = priority(p.eft) || deny
1212

1313
[matchers]
14-
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
14+
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

tests/test_enforcer.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,32 @@ def test_enforce_priority(self):
141141
self.assertTrue(e.enforce("bob", "data2", "read"))
142142
self.assertFalse(e.enforce("bob", "data2", "write"))
143143

144+
def test_enforce_priority_explicit(self):
145+
e = self.get_enforcer(
146+
get_examples("priority_model_explicit.conf"),
147+
get_examples("priority_policy_explicit.csv"),
148+
)
149+
150+
self.assertTrue(e.enforce("alice", "data1", "write"))
151+
self.assertTrue(e.enforce("alice", "data1", "read"))
152+
self.assertFalse(e.enforce("bob", "data2", "read"))
153+
self.assertTrue(e.enforce("bob", "data2", "write"))
154+
self.assertFalse(e.enforce("data1_deny_group", "data1", "read"))
155+
self.assertFalse(e.enforce("data1_deny_group", "data1", "write"))
156+
self.assertTrue(e.enforce("data2_allow_group", "data2", "read"))
157+
self.assertTrue(e.enforce("data2_allow_group", "data2", "write"))
158+
159+
e.add_policy("1", "bob", "data2", "write", "deny")
160+
161+
self.assertTrue(e.enforce("alice", "data1", "write"))
162+
self.assertTrue(e.enforce("alice", "data1", "read"))
163+
self.assertFalse(e.enforce("bob", "data2", "read"))
164+
self.assertFalse(e.enforce("bob", "data2", "write"))
165+
self.assertFalse(e.enforce("data1_deny_group", "data1", "read"))
166+
self.assertFalse(e.enforce("data1_deny_group", "data1", "write"))
167+
self.assertTrue(e.enforce("data2_allow_group", "data2", "read"))
168+
self.assertTrue(e.enforce("data2_allow_group", "data2", "write"))
169+
144170
def test_enforce_priority_indeterminate(self):
145171
e = self.get_enforcer(
146172
get_examples("priority_model.conf"),

0 commit comments

Comments
 (0)