Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions docs/en/3-0-migration-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ The following interfaces now have appropriate parameter and return types added:
- ``RequestPolicyInterface.php``
- ``ResolverInterface``

Multiple optional arguments for ``applyScope``
----------------------------------------------

``IdentityInterface::applyScope`` as well as ``AuthorizationServiceInterface::applyScope``
allow multiple optional arguments to be added.
Multiple optional arguments for ``applyScope``, ``can`` and ``canResult``
-------------------------------------------------------------------------

The following interface methods have been adjusted to pass on multiple optional arguments.
- ``IdentityInterface::applyScope``
- ``AuthorizationServiceInterface::applyScope``
- ``AuthorizationServiceInterface::can``
- ``AuthorizationServiceInterface::canResult``

Removed methods
---------------
Expand Down
19 changes: 12 additions & 7 deletions src/AuthorizationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,19 @@ public function __construct(ResolverInterface $resolver)
/**
* @inheritDoc
*/
public function can(?IdentityInterface $user, string $action, $resource): bool
public function can(?IdentityInterface $user, string $action, $resource, ...$optionalArgs): bool
{
$result = $this->performCheck($user, $action, $resource);
$result = $this->performCheck($user, $action, $resource, ...$optionalArgs);

return is_bool($result) ? $result : $result->getStatus();
}

/**
* @inheritDoc
*/
public function canResult(?IdentityInterface $user, string $action, $resource): ResultInterface
public function canResult(?IdentityInterface $user, string $action, $resource, ...$optionalArgs): ResultInterface
{
$result = $this->performCheck($user, $action, $resource);
$result = $this->performCheck($user, $action, $resource, ...$optionalArgs);

return is_bool($result) ? new Result($result) : $result;
}
Expand All @@ -74,10 +74,15 @@ public function canResult(?IdentityInterface $user, string $action, $resource):
* @param \Authorization\IdentityInterface|null $user The user to check permissions for.
* @param string $action The action/operation being performed.
* @param mixed $resource The resource being operated on.
* @param mixed $optionalArgs Multiple additional arguments which are passed on
* @return \Authorization\Policy\ResultInterface|bool
*/
protected function performCheck(?IdentityInterface $user, string $action, mixed $resource): bool|ResultInterface
{
protected function performCheck(
?IdentityInterface $user,
string $action,
mixed $resource,
mixed ...$optionalArgs
): bool|ResultInterface {
$this->authorizationChecked = true;
$policy = $this->resolver->getPolicy($resource);

Expand All @@ -90,7 +95,7 @@ protected function performCheck(?IdentityInterface $user, string $action, mixed
}

$handler = $this->getCanHandler($policy, $action);
$result = $handler($user, $resource);
$result = $handler($user, $resource, ...$optionalArgs);

assert(
is_bool($result) || $result instanceof ResultInterface,
Expand Down
11 changes: 9 additions & 2 deletions src/AuthorizationServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ interface AuthorizationServiceInterface
* @param \Authorization\IdentityInterface|null $user The user to check permissions for.
* @param string $action The action/operation being performed.
* @param mixed $resource The resource being operated on.
* @param mixed $optionalArgs Multiple additional arguments which are passed to the scope
* @return bool
*/
public function can(?IdentityInterface $user, string $action, mixed $resource): bool;
public function can(?IdentityInterface $user, string $action, mixed $resource, mixed ...$optionalArgs): bool;

/**
* Check whether the provided user can perform an action on a resource.
Expand All @@ -45,9 +46,15 @@ public function can(?IdentityInterface $user, string $action, mixed $resource):
* @param \Authorization\IdentityInterface|null $user The user to check permissions for.
* @param string $action The action/operation being performed.
* @param mixed $resource The resource being operated on.
* @param mixed $optionalArgs Multiple additional arguments which are passed to the scope
* @return \Authorization\Policy\ResultInterface
*/
public function canResult(?IdentityInterface $user, string $action, mixed $resource): ResultInterface;
public function canResult(
?IdentityInterface $user,
string $action,
mixed $resource,
mixed ...$optionalArgs
): ResultInterface;

/**
* Apply authorization scope conditions/restrictions.
Expand Down
90 changes: 89 additions & 1 deletion tests/TestCase/AuthorizationServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,50 @@ public function testCan()
$this->assertTrue($result);
}

public function testCanWithAdditionalParams()
{
$resolver = new MapResolver([
Article::class => ArticlePolicy::class,
]);

$service = new AuthorizationService($resolver);

$user = new IdentityDecorator($service, [
'role' => 'admin',
]);

$innerService = function () {
return true;
};

$result = $service->can($user, 'withService', new Article(), $innerService);
$this->assertTrue($result);
}

public function testCanWithAdditionalNamedParams()
{
$resolver = new MapResolver([
Article::class => ArticlePolicy::class,
]);

$service = new AuthorizationService($resolver);

$user = new IdentityDecorator($service, [
'role' => 'admin',
]);

$innerService1 = function () {
return true;
};

$innerService2 = function () {
return false;
};

$result = $service->can(user: $user, action: 'withMultipleServices', resource: new Article(), service2: $innerService2, service1: $innerService1);
$this->assertFalse($result);
}

public function testCanWithResult()
{
$resolver = new MapResolver([
Expand All @@ -82,6 +126,50 @@ public function testCanWithResult()
$this->assertInstanceOf(ResultInterface::class, $result);
}

public function testCanWithResultAndAdditionalParams()
{
$resolver = new MapResolver([
Article::class => ArticlePolicy::class,
]);

$service = new AuthorizationService($resolver);

$user = new IdentityDecorator($service, [
'role' => 'admin',
]);

$innerService = function () {
return true;
};

$result = $service->canResult($user, 'withService', new Article(), $innerService);
$this->assertInstanceOf(ResultInterface::class, $result);
}

public function testCanWithResultAndAdditionalNamedParams()
{
$resolver = new MapResolver([
Article::class => ArticlePolicy::class,
]);

$service = new AuthorizationService($resolver);

$user = new IdentityDecorator($service, [
'role' => 'admin',
]);

$innerService1 = function () {
return true;
};

$innerService2 = function () {
return false;
};

$result = $service->canResult(user: $user, action: 'withMultipleServices', resource: new Article(), service2: $innerService2, service1: $innerService1);
$this->assertInstanceOf(ResultInterface::class, $result);
}

public function testAuthorizationCheckedWithCan()
{
$resolver = new MapResolver([
Expand Down Expand Up @@ -173,7 +261,7 @@ public function testApplyScopeMethodMissing()
]);

$article = new Article();
$result = $service->applyScope($user, 'nope', $article);
$service->applyScope($user, 'nope', $article);
}

public function testApplyScopeAdditionalArguments()
Expand Down
2 changes: 1 addition & 1 deletion tests/TestCase/Policy/OrmResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,6 @@ public function testGetPolicyUnknownTable()

$articles = $this->createMock('Cake\Datasource\RepositoryInterface');
$resolver = new OrmResolver('TestApp');
$policy = $resolver->getPolicy($articles);
$resolver->getPolicy($articles);
}
}
3 changes: 2 additions & 1 deletion tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

use Authorization\AuthorizationPlugin;
use Cake\Core\Configure;
use Cake\Core\Plugin;
use Cake\Datasource\ConnectionManager;
use Cake\TestSuite\Fixture\SchemaLoader;
use function Cake\Core\env;

$findRoot = function ($root) {
do {
Expand All @@ -33,7 +35,6 @@
unset($findRoot);
chdir($root);

require_once 'vendor/cakephp/cakephp/src/basics.php';
require_once 'vendor/autoload.php';

define('ROOT', $root . DS . 'tests' . DS . 'test_app' . DS);
Expand Down
11 changes: 11 additions & 0 deletions tests/test_app/TestApp/Policy/ArticlePolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace TestApp\Policy;

use Authorization\Policy\Result;
use Closure;
use TestApp\Model\Entity\Article;

class ArticlePolicy
Expand Down Expand Up @@ -116,4 +117,14 @@ public function canPublish($user, Article $article)

return new Result($article->get('user_id') === $user['id']);
}

public function canWithService($user, Article $article, Closure $service)
{
return $service();
}

public function canWithMultipleServices($user, Article $article, Closure $service1, Closure $service2)
{
return $service1() && $service2();
}
}