Skip to content

Commit 9e7edf6

Browse files
Merge pull request #2 from dicoding-dev/fix/issue-check-with-inverted-whole-action-rule
[Bugfix] Comparison issue when facing with inverted (negated) rule that have whole field with specific action
2 parents e09b991 + 0443fe3 commit 9e7edf6

5 files changed

Lines changed: 60 additions & 2 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "A core package for managing the authorization through CanCanCan style. With supports of granularity based on Attributes Based Access Control.",
44
"type": "library",
55
"license": "MIT",
6-
"version": "0.6.0-stable",
6+
"version": "0.6.1-stable",
77
"scripts": {
88
"test": "./vendor/bin/pest"
99
},

src/Abilities/Core/Comparator/AbilityCheckerImpl.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ public function can(string $action, string $resource, string $scope, mixed $fiel
2424
$starActionRules = [];
2525
foreach ($unspecifiedActionRules as $unspecifiedActionRule) {
2626
/** 1. Checking on specific inverted rules */
27-
if ($unspecifiedActionRule->isInverted() && $unspecifiedActionRule->getResource()->matchField($field)) {
27+
if ($unspecifiedActionRule->isInverted() &&
28+
$unspecifiedActionRule->getResource()->matchField($field) &&
29+
$unspecifiedActionRule->getAction()->match($action)
30+
) {
2831
return false; // as the correspondent user is prohibited access resource
2932
} elseif ($unspecifiedActionRule->getAction()->wholeAction()) {
3033
$starActionRules[] = $unspecifiedActionRule;

src/Abilities/Core/Objects/Action.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,13 @@ public function __toString(): string
3737
{
3838
return $this->get();
3939
}
40+
41+
public function match(string $action): bool
42+
{
43+
if ($this->wholeAction()) {
44+
return true;
45+
}
46+
47+
return $this->get() === $action;
48+
}
4049
}

tests/Feature/Core/AbilityCheckerImplTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,33 @@
157157
expect($abilityChecker->can('update', 'resource1', 'scope1', (object) ['author' => 666]))
158158
->toBeFalse();
159159
});
160+
161+
it('must return as expected when has inverted specific action and whole field rule compared with rule that has specific field with whole action', function () {
162+
$compiledRules = new CompiledRules([
163+
(object) [
164+
'id' => 2,
165+
'rule' => '!scope1:resource1/*:review'
166+
],
167+
(object) [
168+
'id' => 3,
169+
'rule' => 'scope1:resource1/{"author": 667}:*'
170+
]
171+
]);
172+
173+
$abilityChecker = new AbilityCheckerImpl($compiledRules);
174+
expect($abilityChecker->can('update', 'resource1', 'scope1', (object) ['author' => 667]))
175+
->toBeTrue();
176+
expect($abilityChecker->can('update', 'resource1', 'scope1'))
177+
->toBeFalse();
178+
expect($abilityChecker->can('*', 'resource1', 'scope1'))
179+
->toBeFalse();
180+
expect($abilityChecker->can('review', 'resource1', 'scope1', (object) ['author' => 667]))
181+
->toBeFalse();
182+
expect($abilityChecker->can('review', 'resource1', 'scope1'))
183+
->toBeFalse();
184+
expect($abilityChecker->can('review', 'resource1', 'scope1', (object) ['author' => 666]))
185+
->toBeFalse();
186+
});
160187
});
161188

162189
describe('cannot() feature function test', function () {

tests/Unit/Core/Objects/ActionTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,23 @@
3434
it('can know if the action is whole action (star)', function () {
3535
expect((new Action('*'))->wholeAction())->toBeTrue();
3636

37+
});
38+
39+
describe('match() function test', function () {
40+
it('must return true when the current action is whole action', function () {
41+
$currentAction = new Action();
42+
43+
expect($currentAction->match('create'))->toBeTrue();
44+
expect($currentAction->match('*'))->toBeTrue();
45+
});
46+
47+
it ('must return true when the match with specific action', function () {
48+
$currentAction = new Action('create');
49+
expect($currentAction->match('create'))->toBeTrue();
50+
});
51+
52+
it('must return false when not match with specific action', function () {
53+
$currentAction = new Action('create');
54+
expect($currentAction->match('update'))->toBeFalse();
55+
});
3756
});

0 commit comments

Comments
 (0)