Skip to content

Commit e42f3da

Browse files
authored
feat: add field_index_map and constant (#314)
* feat: add constants * feat: add field_index_map
1 parent f0c1786 commit e42f3da

9 files changed

Lines changed: 107 additions & 12 deletions

File tree

casbin/async_internal_enforcer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
# limitations under the License.
1414
import copy
1515

16+
from casbin.core_enforcer import CoreEnforcer
1617
from casbin.model import Model, FunctionMap
1718
from casbin.persist import Adapter
18-
from casbin.core_enforcer import CoreEnforcer
1919
from casbin.persist.adapters.async_file_adapter import AsyncFileAdapter
2020

2121

@@ -160,7 +160,6 @@ async def _update_policy(self, sec, ptype, old_rule, new_rule):
160160
return rule_updated
161161

162162
if self.adapter and self.auto_save:
163-
164163
result = await self.adapter.update_policy(sec, ptype, old_rule, new_rule)
165164
if result is False:
166165
return False
@@ -289,3 +288,12 @@ async def _remove_filtered_policy_returns_effects(self, sec, ptype, field_index,
289288
self.watcher.update()
290289

291290
return rule_removed
291+
292+
async def get_field_index(self, ptype, field):
293+
"""gets the index of the field name."""
294+
return self.model.get_field_index(ptype, field)
295+
296+
async def set_field_index(self, ptype, field, index):
297+
"""sets the index of the field name."""
298+
assertion = self.model["p"][ptype]
299+
assertion.field_index_map[field] = index

casbin/constant/__init__.py

Whitespace-only changes.

casbin/constant/constants.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2023 The casbin Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Index constants
16+
DOMAIN_INDEX = "dom"
17+
SUBJECT_INDEX = "sub"
18+
OBJECT_INDEX = "obj"
19+
PRIORITY_INDEX = "priority"
20+
21+
# Effect constants
22+
ALLOW_OVERRIDE_EFFECT = "some(where (p_eft == allow))"
23+
DENY_OVERRIDE_EFFECT = "!some(where (p_eft == deny))"
24+
ALLOW_AND_DENY_EFFECT = "some(where (p_eft == allow)) && !some(where (p_eft == deny))"
25+
PRIORITY_EFFECT = "priority(p_eft) || deny"
26+
SUBJECT_PRIORITY_EFFECT = "subjectPriority(p_eft) || deny"

casbin/effect/__init__.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,25 @@
1919
PriorityEffector,
2020
)
2121
from .effector import Effector
22+
from ..constant.constants import (
23+
ALLOW_OVERRIDE_EFFECT,
24+
SUBJECT_PRIORITY_EFFECT,
25+
PRIORITY_EFFECT,
26+
DENY_OVERRIDE_EFFECT,
27+
ALLOW_AND_DENY_EFFECT,
28+
)
2229

2330

2431
def get_effector(expr):
2532
"""creates an effector based on the current policy effect expression"""
2633

27-
if expr == "some(where (p_eft == allow))":
34+
if expr == ALLOW_OVERRIDE_EFFECT:
2835
return AllowOverrideEffector()
29-
elif expr == "!some(where (p_eft == deny))":
36+
elif expr == DENY_OVERRIDE_EFFECT:
3037
return DenyOverrideEffector()
31-
elif expr == "some(where (p_eft == allow)) && !some(where (p_eft == deny))":
38+
elif expr == ALLOW_AND_DENY_EFFECT:
3239
return AllowAndDenyEffector()
33-
elif expr == "priority(p_eft) || deny" or expr == "subjectPriority(p_eft) || deny":
40+
elif expr == PRIORITY_EFFECT or expr == SUBJECT_PRIORITY_EFFECT:
3441
return PriorityEffector()
3542
else:
3643
raise RuntimeError("unsupported effect")

casbin/internal_enforcer.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ def _update_policy(self, sec, ptype, old_rule, new_rule):
6767
return rule_updated
6868

6969
if self.adapter and self.auto_save:
70-
7170
if self.adapter.update_policy(sec, ptype, old_rule, new_rule) is False:
7271
return False
7372

@@ -84,7 +83,6 @@ def _update_policies(self, sec, ptype, old_rules, new_rules):
8483
return rules_updated
8584

8685
if self.adapter and self.auto_save:
87-
8886
if self.adapter.update_policies(sec, ptype, old_rules, new_rules) is False:
8987
return False
9088

@@ -189,3 +187,12 @@ def _remove_filtered_policy_returns_effects(self, sec, ptype, field_index, *fiel
189187
self.watcher.update()
190188

191189
return rule_removed
190+
191+
def get_field_index(self, ptype, field):
192+
"""gets the index of the field name."""
193+
return self.model.get_field_index(ptype, field)
194+
195+
def set_field_index(self, ptype, field, index):
196+
"""sets the index of the field name."""
197+
assertion = self.model["p"][ptype]
198+
assertion.field_index_map[field] = index

casbin/model/assertion.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import logging
16+
1617
from casbin.model.policy_op import PolicyOp
1718

1819

@@ -26,6 +27,7 @@ def __init__(self):
2627
self.rm = None
2728
self.priority_index: int = -1
2829
self.policy_map: dict = {}
30+
self.field_index_map: dict = {}
2931

3032
def build_role_links(self, rm):
3133
self.rm = rm

casbin/model/model.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from . import Assertion
1615
from casbin import util, config
16+
from . import Assertion
1717
from .policy import Policy
1818

1919
DEFAULT_DOMAIN = ""
2020
DEFAULT_SEPARATOR = "::"
2121

2222

2323
class Model(Policy):
24-
2524
section_name_map = {
2625
"r": "request_definition",
2726
"p": "policy_definition",
@@ -207,3 +206,23 @@ def write_string(sec):
207206
s[-1] = s[-1].strip()
208207

209208
return "".join(s)
209+
210+
def get_field_index(self, ptype, field):
211+
"""get_field_index gets the index of the field for a ptype in a policy,
212+
return -1 if the field does not exist."""
213+
assertion = self["p"][ptype]
214+
if field in assertion.field_index_map:
215+
return assertion.field_index_map[field]
216+
217+
pattern = f"{ptype}_{field}"
218+
index = -1
219+
for i, token in enumerate(assertion.tokens):
220+
if token == pattern:
221+
index = i
222+
break
223+
224+
if index == -1:
225+
return index
226+
227+
assertion.field_index_map[field] = index
228+
return index

casbin/synced_enforcer.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,3 +628,12 @@ def build_incremental_role_links(self, op, ptype, rules):
628628

629629
def new_enforce_context(self, suffix: str) -> "EnforceContext":
630630
return self._e.new_enforce_context(suffix)
631+
632+
def get_field_index(self, ptype, field):
633+
"""gets the index of the field name."""
634+
return self._e.model.get_field_index(ptype, field)
635+
636+
def set_field_index(self, ptype, field, index):
637+
"""sets the index of the field name."""
638+
assertion = self._e.model["p"][ptype]
639+
assertion.field_index_map[field] = index

tests/test_rbac_api.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from unittest import IsolatedAsyncioTestCase
1515

1616
import casbin
17+
from casbin.constant.constants import DOMAIN_INDEX
1718
from tests.test_enforcer import get_examples, TestCaseBase
1819

1920

@@ -254,7 +255,6 @@ def test_enforce_implicit_permissions_api_with_domain(self):
254255
self.assertEqual(e.get_implicit_permissions_for_user("bob", "domain1"), [])
255256

256257
def test_enforce_implicit_permissions_api_with_domain_matching_function(self):
257-
258258
e = self.get_enforcer(
259259
get_examples("rbac_with_domain_and_policy_pattern_model.conf"),
260260
get_examples("rbac_with_domain_and_policy_pattern_policy.csv"),
@@ -405,6 +405,15 @@ def test_domain_match_model(self):
405405
self.assertTrue(e.enforce("bob", "domain2", "data2", "read"))
406406
self.assertTrue(e.enforce("bob", "domain2", "data2", "write"))
407407

408+
def test_set_field_index(self):
409+
e = self.get_enforcer(
410+
get_examples("rbac_with_domains_model.conf"),
411+
get_examples("rbac_with_domains_policy.csv"),
412+
)
413+
self.assertEqual(e.get_field_index("p", DOMAIN_INDEX), 1)
414+
e.set_field_index("p", DOMAIN_INDEX, 2)
415+
self.assertEqual(e.get_field_index("p", DOMAIN_INDEX), 2)
416+
408417

409418
class TestRbacApiSynced(TestRbacApi):
410419
def get_enforcer(self, model=None, adapter=None):
@@ -686,7 +695,6 @@ async def test_enforce_implicit_permissions_api_with_domain(self):
686695
self.assertEqual(await e.get_implicit_permissions_for_user("bob", "domain1"), [])
687696

688697
async def test_enforce_implicit_permissions_api_with_domain_matching_function(self):
689-
690698
e = self.get_enforcer(
691699
get_examples("rbac_with_domain_and_policy_pattern_model.conf"),
692700
get_examples("rbac_with_domain_and_policy_pattern_policy.csv"),
@@ -847,3 +855,12 @@ async def test_domain_match_model(self):
847855
self.assertFalse(e.enforce("bob", "domain2", "data1", "write"))
848856
self.assertTrue(e.enforce("bob", "domain2", "data2", "read"))
849857
self.assertTrue(e.enforce("bob", "domain2", "data2", "write"))
858+
859+
async def test_set_field_index(self):
860+
e = self.get_enforcer(
861+
get_examples("rbac_with_domains_model.conf"),
862+
get_examples("rbac_with_domains_policy.csv"),
863+
)
864+
self.assertEqual(await e.get_field_index("p", DOMAIN_INDEX), 1)
865+
await e.set_field_index("p", DOMAIN_INDEX, 2)
866+
self.assertEqual(await e.get_field_index("p", DOMAIN_INDEX), 2)

0 commit comments

Comments
 (0)