Skip to content

Commit

Permalink
feat: add priority support
Browse files Browse the repository at this point in the history
  • Loading branch information
basakest committed Sep 11, 2021
1 parent 132167b commit bcc0153
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 5 deletions.
14 changes: 14 additions & 0 deletions examples/priority_model_explicit.conf
@@ -0,0 +1,14 @@
[request_definition]
r = sub, obj, act

[policy_definition]
p = priority, sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = priority(p.eft) || deny

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
12 changes: 12 additions & 0 deletions examples/priority_policy_explicit.csv
@@ -0,0 +1,12 @@
p, 10, data1_deny_group, data1, read, deny
p, 10, data1_deny_group, data1, write, deny
p, 10, data2_allow_group, data2, read, allow
p, 10, data2_allow_group, data2, write, allow


p, 1, alice, data1, write, allow
p, 1, alice, data1, read, allow
p, 1, bob, data2, read, deny

g, bob, data2_allow_group
g, alice, data1_deny_group
2 changes: 2 additions & 0 deletions src/CoreEnforcer.php
Expand Up @@ -363,6 +363,7 @@ public function loadPolicy(): void
}

$this->model->printPolicy();
$this->model->sortPoliciesByPriority();
if ($this->autoBuildRoleLinks) {
$this->buildRoleLinks();
}
Expand All @@ -386,6 +387,7 @@ public function loadFilteredPolicy($filter): void
throw new CasbinException('filtered policies are not supported by this adapter');
}

$this->model->sortPoliciesByPriority();
$this->initRmMap();
$this->model->printPolicy();
if ($this->autoBuildRoleLinks) {
Expand Down
19 changes: 19 additions & 0 deletions src/Model/Model.php
Expand Up @@ -216,4 +216,23 @@ public static function loadFunctionMap(): FunctionMap
{
return FunctionMap::loadFunctionMap();
}

public function sortPoliciesByPriority(): void
{
foreach ($this->items['p'] as $ptype => $assertion) {
if ($assertion->tokens[0] != sprintf("%s_priority", $ptype)) {
continue;
}
$policies = &$assertion->policy;
usort($policies, function ($i, $j): int {
if ($i[0] == $j[0]) {
return 0;
}
return ($i[0] < $j[0]) ? -1 : 1;
});
foreach ($assertion->policy as $i => $policy) {
$assertion->policyMap[implode(',', $policy)] = $i;
}
}
}
}
24 changes: 19 additions & 5 deletions src/Model/Policy.php
Expand Up @@ -193,8 +193,24 @@ public function hasPolicies(string $sec, string $ptype, array $rules): bool
*/
public function addPolicy(string $sec, string $ptype, array $rule): void
{
$this->items[$sec][$ptype]->policy[] = $rule;
$this->items[$sec][$ptype]->policyMap[implode(self::DEFAULT_SEP, $rule)] = count($this->items[$sec][$ptype]->policy) - 1;
$assertion = &$this->items[$sec][$ptype];
$assertion->policy[] = $rule;
$idxInsert = $rule[0];

if (isset($assertion->tokens[0]) &&$assertion->tokens[0] == sprintf("%s_priority", $ptype)) {
for ($i = count($assertion->policy) - 1; $i > 0; $i--) {
$idx = $assertion->policy[$i-1][0];
if ($idx > $idxInsert) {
$assertion->policy[$i] = $assertion->policy[$i-1];
} else {
break;
}
}
$assertion->policy[$i] = $rule;
$assertion->policyMap[implode(self::DEFAULT_SEP, $rule)] = $i;
} else {
$assertion->policyMap[implode(self::DEFAULT_SEP, $rule)] = count($this->items[$sec][$ptype]->policy) - 1;
}
}

/**
Expand All @@ -211,9 +227,7 @@ public function addPolicies(string $sec, string $ptype, array $rules): void
if (isset($this->items[$sec][$ptype]->policyMap[$hashKey])) {
continue;
}

$this->items[$sec][$ptype]->policy[] = $rule;
$this->items[$sec][$ptype]->policyMap[$hashKey] = count($this->items[$sec][$ptype]->policy) - 1;
$this->addPolicy($sec, $ptype, $rule);
}
}

Expand Down
24 changes: 24 additions & 0 deletions tests/Unit/CoreEnforcerTest.php
Expand Up @@ -236,4 +236,28 @@ public function testEnableEnforce()
$this->assertFalse($e->enforce('bob', 'data2', 'read'));
$this->assertTrue($e->enforce('bob', 'data2', 'write'));
}

public function testPriorityExplicit()
{
$e = new Enforcer($this->modelAndPolicyPath . '/priority_model_explicit.conf', $this->modelAndPolicyPath . '/priority_policy_explicit.csv');
$this->assertTrue($e->enforce('alice', 'data1', 'write'));
$this->assertTrue($e->enforce('alice', 'data1', 'read'));
$this->assertFalse($e->enforce('bob', 'data2', 'read'));
$this->assertTrue($e->enforce('bob', 'data2', 'write'));
$this->assertFalse($e->enforce('data1_deny_group', 'data1', 'read'));
$this->assertFalse($e->enforce('data1_deny_group', 'data1', 'write'));
$this->assertTrue($e->enforce('data2_allow_group', 'data2', 'read'));
$this->assertTrue($e->enforce('data2_allow_group', 'data2', 'write'));

$e->addPolicy('1', 'bob', 'data2', 'write', 'deny');

$this->assertTrue($e->enforce('alice', 'data1', 'write'));
$this->assertTrue($e->enforce('alice', 'data1', 'read'));
$this->assertFalse($e->enforce('bob', 'data2', 'read'));
$this->assertFalse($e->enforce('bob', 'data2', 'write'));
$this->assertFalse($e->enforce('data1_deny_group', 'data1', 'read'));
$this->assertFalse($e->enforce('data1_deny_group', 'data1', 'write'));
$this->assertTrue($e->enforce('data2_allow_group', 'data2', 'read'));
$this->assertTrue($e->enforce('data2_allow_group', 'data2', 'write'));
}
}

0 comments on commit bcc0153

Please sign in to comment.