Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Policies: treat true as allow, and false as deny #2534

Merged
merged 5 commits into from Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/User/Access/AbstractPolicy.php
Expand Up @@ -43,13 +43,13 @@ protected function forceDeny()
* @param User $user
* @param string $ability
* @param $instance
* @return bool|void
* @return string|void
*/
public function checkAbility(User $actor, string $ability, $instance)
{ // If a specific method for this ability is defined,
// call that and return any non-null results
if (method_exists($this, $ability)) {
$result = call_user_func_array([$this, $ability], [$actor, $instance]);
$result = $this->sanitizeResult(call_user_func_array([$this, $ability], [$actor, $instance]));

if (! is_null($result)) {
return $result;
Expand All @@ -58,7 +58,22 @@ public function checkAbility(User $actor, string $ability, $instance)

// If a "total access" method is defined, try that.
if (method_exists($this, 'can')) {
return call_user_func_array([$this, 'can'], [$actor, $ability, $instance]);
return $this->sanitizeResult(call_user_func_array([$this, 'can'], [$actor, $ability, $instance]));
}
}

/**
* @param mixed $result
* @return string|void
*/
public function sanitizeResult($result)
{
if ($result === true) {
$result = $this->allow();
askvortsov1 marked this conversation as resolved.
Show resolved Hide resolved
} elseif ($result === false) {
$result = $this->deny();
}

return $result;
}
}
57 changes: 42 additions & 15 deletions tests/unit/User/AbstractPolicyTest.php
Expand Up @@ -9,42 +9,59 @@

namespace Flarum\Tests\unit\User;

use Flarum\Event\GetPermission;
use Flarum\Tests\unit\TestCase;
use Flarum\User\AbstractPolicy;
use Flarum\User\Access\AbstractPolicy;
use Flarum\User\User;
use Illuminate\Events\Dispatcher;
use Mockery as m;

class AbstractPolicyTest extends TestCase
{
private $policy;
private $dispatcher;

/**
* @inheritDoc
*/
protected function setUp(): void
{
$this->policy = m::mock(CustomUserPolicy::class)->makePartial();
$this->dispatcher = new Dispatcher();
$this->dispatcher->subscribe($this->policy);
User::setEventDispatcher($this->dispatcher);
User::setEventDispatcher(new Dispatcher());
}

public function test_policy_can_be_called_with_object()
/**
* @inheritDoc
*/
protected function tearDown(): void
{
$this->policy->shouldReceive('edit')->andReturn(true);
m::close();
}

$allowed = $this->dispatcher->until(new GetPermission(new User(), 'edit', new User()));
public function test_policy_can_be_called_with_object()
{
$allowed = $this->policy->checkAbility(new User(), 'create', new User());

$this->assertTrue($allowed);
$this->assertEquals(AbstractPolicy::ALLOW, $allowed);
}

public function test_policy_can_be_called_with_class()
{
$this->policy->shouldReceive('create')->andReturn(true);
$allowed = $this->policy->checkAbility(new User(), 'edit', User::class);

$this->assertEquals(AbstractPolicy::DENY, $allowed);
}

public function test_policy_converts_true_to_ALLOW()
{
$allowed = $this->policy->checkAbility(new User(), 'somethingRandom', User::class);

$this->assertEquals(AbstractPolicy::ALLOW, $allowed);
}

$allowed = $this->dispatcher->until(new GetPermission(new User(), 'create', User::class));
public function test_policy_converts_false_to_DENY()
{
$allowed = $this->policy->checkAbility(new User(), 'somethingElseRandom', User::class);

$this->assertTrue($allowed);
$this->assertEquals(AbstractPolicy::DENY, $allowed);
}
}

Expand All @@ -54,11 +71,21 @@ class CustomUserPolicy extends AbstractPolicy

public function create(User $actor)
{
return true;
return $this->allow();
}

public function edit(User $actor, User $user)
public function edit(User $actor, $target)
{
return $this->deny();
}

public function somethingRandom(User $actor, $target)
{
return true;
}

public function somethingElseRandom(User $actor, $target)
{
return false;
}
}