Skip to content

Commit

Permalink
If effective role is present in token, check it in Authorizator along…
Browse files Browse the repository at this point in the history
…side with user role and scopes
  • Loading branch information
Neloop authored and Martin Kruliš committed Sep 7, 2019
1 parent 8fc544f commit db1cdd2
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 12 deletions.
5 changes: 3 additions & 2 deletions app/V1Module/security/Authorizator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ abstract class Authorizator implements IAuthorizator {
/** @var Roles */
protected $roles;

private $initialized = false;

public function __construct(PolicyRegistry $policy, Roles $roles) {
$this->policy = $policy;
Expand All @@ -34,8 +33,10 @@ public function isAllowed(Identity $identity, string $resource, string $privileg
$this->queriedContext = $context;

$scopeRoles = $identity->getScopeRoles();
$effectiveRole = $identity->getEffectiveRole();
return $this->checkPermissionsForRoleList($identity->getRoles(), $resource, $privilege)
&& ($scopeRoles === [] || $this->checkPermissionsForRoleList($scopeRoles, $resource, $privilege));
&& ($scopeRoles === [] || $this->checkPermissionsForRoleList($scopeRoles, $resource, $privilege))
&& ($effectiveRole === null || $this->checkPermissions($effectiveRole, $resource, $privilege));
}

protected function checkPermissionsForRoleList($roleList, $resource, $privilege): bool {
Expand Down
12 changes: 12 additions & 0 deletions app/V1Module/security/Identity.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ function getScopeRoles()
return array_map(function (string $role) { return "scope-" . $role; }, $this->token->getScopes());
}

/**
* Return effective role that user uses in current session.
* @return string|null
*/
public function getEffectiveRole(): ?string {
if (!$this->token) {
return null;
}

return $this->token->getEffectiveRole();
}

function getUserData()
{
return $this->user;
Expand Down
88 changes: 88 additions & 0 deletions tests/Authorizator/AuthorizatorWithEffectiveRole.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
include __DIR__ . "/../bootstrap.php";

use App\Security\Authorizator;
use App\Security\Loader;
use App\Security\PolicyRegistry;
use App\Security\Roles;
use App\Security\UserStorage;
use Tester\Assert;

class Resource1 { }

interface ITestResource1Permissions {
function canAction1(Resource1 $resource): bool;
function canAction2(Resource1 $resource): bool;
}

/**
* @testCase
*/
class TestAuthorizatorWithEffectiveRole extends Tester\TestCase
{
use MockeryTrait;

/** @var PolicyRegistry */
private $policies;

/** @var Roles */
private $roles;

/** @var Authorizator */
private $authorizator;

/** @var Loader */
private $loader;

public function __construct()
{
$this->loader = new Loader(TEMP_DIR . '/security', __DIR__ . '/config/with_effective_role.neon', [
'resource1' => ITestResource1Permissions::class
], Mockery::mock(UserStorage::class));
}

public function setUp()
{
$this->policies = new PolicyRegistry();
$this->roles = $this->loader->loadRoles();
$this->authorizator = $this->loader->loadAuthorizator($this->policies, $this->roles);
}

public function testNoEffectiveRoles()
{
Assert::true($this->authorizator->isAllowed(
new MockIdentity([ 'normal_role' ]),
'resource1',
'action1',
[
'resource1' => new Resource1(),
]
));
}

public function testRestrictedEffectiveRole()
{
Assert::false($this->authorizator->isAllowed(
new MockIdentity([ 'normal_role' ], [], 'effective_role_2'),
'resource1',
'action1',
[
'resource1' => new Resource1(),
]
));
}

public function testAgreeingRoles()
{
Assert::true($this->authorizator->isAllowed(
new MockIdentity([ 'normal_role' ], [], 'effective_role_1'),
'resource1',
'action1',
[
'resource1' => new Resource1(),
]
));
}
}

(new TestAuthorizatorWithEffectiveRole())->run();
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ITestResource1Permissions {
/**
* @testCase
*/
class TestAuthorizatorWithEffectiveRoles extends Tester\TestCase
class TestAuthorizatorWithScopeRoles extends Tester\TestCase
{
use MockeryTrait;

Expand All @@ -35,7 +35,7 @@ class TestAuthorizatorWithEffectiveRoles extends Tester\TestCase

public function __construct()
{
$this->loader = new Loader(TEMP_DIR . '/security', __DIR__ . '/config/with_effective_roles.neon', [
$this->loader = new Loader(TEMP_DIR . '/security', __DIR__ . '/config/with_scope_roles.neon', [
'resource1' => ITestResource1Permissions::class
], Mockery::mock(\App\Security\UserStorage::class));
}
Expand All @@ -47,7 +47,7 @@ class TestAuthorizatorWithEffectiveRoles extends Tester\TestCase
$this->authorizator = $this->loader->loadAuthorizator($this->policies, $this->roles);
}

public function testNoEffectiveRoles()
public function testNoScopeRoles()
{
Assert::true($this->authorizator->isAllowed(
new MockIdentity([ 'normal_role' ]),
Expand All @@ -59,7 +59,7 @@ class TestAuthorizatorWithEffectiveRoles extends Tester\TestCase
));
}

public function testRestrictedEffectiveRole()
public function testRestrictedScopeRole()
{
Assert::false($this->authorizator->isAllowed(
new MockIdentity([ 'normal_role' ], [ 'effective_role_2' ]),
Expand Down Expand Up @@ -95,7 +95,7 @@ class TestAuthorizatorWithEffectiveRoles extends Tester\TestCase
));
}

public function testBothEffectiveRoles()
public function testBothScopeRoles()
{
Assert::true($this->authorizator->isAllowed(
new MockIdentity([ 'normal_role' ], [ 'effective_role_2', 'effective_role_1' ]),
Expand All @@ -108,4 +108,4 @@ class TestAuthorizatorWithEffectiveRoles extends Tester\TestCase
}
}

(new TestAuthorizatorWithEffectiveRoles())->run();
(new TestAuthorizatorWithScopeRoles())->run();
15 changes: 11 additions & 4 deletions tests/Authorizator/MockIdentity.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
class MockIdentity extends App\Security\Identity
{
private $roles;
private $effectiveRoles;
private $scopeRoles;
private $effectiveRole;

public function __construct(array $roles, array $effectiveRoles = [])
public function __construct(array $roles, array $scopeRoles = [], string $effectiveRole = null)
{
parent::__construct(null, null);
$this->roles = $roles;
$this->effectiveRoles = $effectiveRoles;
$this->scopeRoles = $scopeRoles;
$this->effectiveRole = $effectiveRole;
}

public function getRoles()
Expand All @@ -19,6 +21,11 @@ public function getRoles()

function getScopeRoles()
{
return $this->effectiveRoles;
return $this->scopeRoles;
}

function getEffectiveRole(): ?string
{
return $this->effectiveRole;
}
}
22 changes: 22 additions & 0 deletions tests/Authorizator/config/with_effective_role.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
roles:
- name: normal_role
- name: effective_role_1
- name: effective_role_2

permissions:
- allow: true
role: normal_role
resource: resource1
actions:
- action1
- action2
- allow: true
role: effective_role_1
resource: resource1
actions:
- action1
- allow: true
role: effective_role_2
resource: resource1
actions:
- action2

0 comments on commit db1cdd2

Please sign in to comment.