diff --git a/src/Effector/DefaultEffector.php b/src/Effector/DefaultEffector.php index 4b62ad2..eb3b6e9 100644 --- a/src/Effector/DefaultEffector.php +++ b/src/Effector/DefaultEffector.php @@ -75,9 +75,14 @@ public function mergeEffects(string $expr, array $effects, array $matches, int $ } if ($eft == Effector::ALLOW) { + // set hit rule to first matched allow rule, maybe overridden by the deny part + if ($result == Effector::INDETERMINATE) { + $explainIndex = $i; + } $result = Effector::ALLOW; } elseif ($eft == Effector::DENY) { $result = Effector::DENY; + // set hit rule to the (first) matched deny rule $explainIndex = $i; break; } diff --git a/tests/EnforcerTest.php b/tests/EnforcerTest.php index 57d7cca..8f10d40 100644 --- a/tests/EnforcerTest.php +++ b/tests/EnforcerTest.php @@ -326,9 +326,9 @@ public function testEnforceRbacWithDeny() public function testEnforceExRbacWithDeny() { $e = new Enforcer($this->modelAndPolicyPath . '/rbac_with_deny_model.conf', $this->modelAndPolicyPath . '/rbac_with_deny_policy.csv'); - $this->assertEquals($e->enforceEx('alice', 'data1', 'read'), [true, []]); - $this->assertEquals($e->enforceEx('bob', 'data2', 'write'), [true, []]); - $this->assertEquals($e->enforceEx('alice', 'data2', 'read'), [true, []]); + $this->assertEquals($e->enforceEx('alice', 'data1', 'read'), [true, ['alice', 'data1', 'read', 'allow']]); + $this->assertEquals($e->enforceEx('bob', 'data2', 'write'), [true, ['bob', 'data2', 'write', 'allow']]); + $this->assertEquals($e->enforceEx('alice', 'data2', 'read'), [true, ['data2_admin', 'data2', 'read', 'allow']]); $this->assertEquals($e->enforceEx('alice', 'data2', 'write'), [false, ['alice', 'data2', 'write', 'deny']]); }