chill-bundles/Tests/Security/Authorization/AuthorizationHelperTest.php
Julien Fastré 8ac41a15b6 Merge branch add_acl ref #263
Squashed commit of the following:

commit e1236655e1514fd207818aeb57789eca0d949453
Merge: c0b349b fb15bd3
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Tue Jun 30 09:51:35 2015 +0200

    Merge remote-tracking branch 'origin/master' into add_acl

    In order to prepare merging of add_acl to master

    Conflicts:
    	composer.json

commit c0b349bb5f31fe79c84f82d4dd6658c9e90ef728
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Tue Jun 30 00:40:13 2015 +0200

    fix infos in composer.json

    [ci skip]

commit 106bbf56a5060efd2a89232f278692eeb57e3092
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Mon Jun 29 22:58:48 2015 +0200

    add username and password to client auth options

    [ci skip]

commit c4990972711850616aa1426394884223d63b504f
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Mon Jun 29 22:22:20 2015 +0200

    fix quoting in timelinebuilder

commit 1db7cbea5a0fb0e8d396f8c9d8dc01240b47e96f
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Thu Jun 25 22:43:46 2015 +0200

    remove data_class to allow edit form

commit 7c999279310b5e2b9ecef8a9b5001c71910a822d
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Wed Jun 24 22:33:42 2015 +0200

    fix doc for AppendScopeChoiceTypeTrait

commit 839d4c43bf6f463e705b47d5dbc0cdf7853db0b6
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Wed Jun 24 22:30:13 2015 +0200

    refactor: move scope field to a trait

    Example usage :

      ```
      class AbcType extends Symfony\Component\Form\AbstractType
      {
          use AppendScopeChoiceTypeTrait;
          protected $authorizationHelper;
          protected $translatableStringHelper;
          protected $user;

          public function __construct(AuthorizationHelper $helper,
            TokenStorageInterface $tokenStorage,
            TranslatableStringHelper $translatableStringHelper)
          {
              $this->authorizationHelper = $helper;
              $this->user = $tokenStorage->getToken()->getUser();
              $this->translatableStringHelper = $translatableStringHelper;
          }

          public function buildForm(FormBuilder $builder, array $options)
          {
                // ... add your form there

              // append the scope using FormEvents: PRE_SET_DATA
              $this->appendScopeChoices($builder, $options['role'],
                   $options['center'], $this->user,
                   $this->authorizationHelper,
                   $this->translatableStringHelper);
           }

           public function configureOptions(OptionsResolver $resolver)
           {
                   // ... add your options

              // add an option 'role' and 'center' to your form (optional)
              $this->appendScopeChoicesOptions($resolver);
           }

       }
      ```

    [ci skip]

commit a1ac530f343146eee12b5982e4e6fceb6dc1da66
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Wed Jun 24 00:24:30 2015 +0200

    remove unused statements

commit 74f0a4ce5dfdfa4f8fc39ce1cfe726d945e9bdec
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Wed Jun 24 00:09:47 2015 +0200

    add missing unused statement

commit b3a49f2de8758b51c57af6ff0437f30b2fdef72e
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Tue Jun 23 23:58:57 2015 +0200

    remove ScopeType strategy and fix autorization helper

commit aaa70b5eeae76b0950110f51b8274e08bef10576
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Tue Jun 23 21:35:06 2015 +0200

    create scope type

commit 8f5b2b23c9448b8c8e752e46bdd7f9f721054a98
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 19 18:13:54 2015 +0200

    add getREachableCenter method + test on Autho.Helper

commit ab2ccb8c287f9aef12912ea9b7f5dc4998209d77
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 19 17:27:22 2015 +0200

    remove debug information [ci skip]

commit 9d481c07966a5d769d1418bb366bd6b1ea9d4f76
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 19 17:24:57 2015 +0200

    fix role hierarchy

    Now we test effectively that a user has access, not that a role may grant access

commit f4b17d0ae398fd6c26d4907377761e9f15d36a90
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Thu Jun 18 02:08:55 2015 +0200

    fix trait conflicts

    traits does not share the same instance of prophet any more

commit baac8ce97ba0acd4c4fe6f03278f7a0d30da28ad
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Thu Jun 18 01:56:39 2015 +0200

    try to fix trait error in zend strict mode (used by travis)

commit 7b9fa4b14bde72c7036a29c03a0c6cca3c7e6c74
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Thu Jun 18 01:24:09 2015 +0200

    fix error on trait hierarchy (should be)

commit f8b3451089f7017653bf8d280b640356df6a1841
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Thu Jun 18 01:03:04 2015 +0200

    add userHasAccess method to AuthorizationHelper

    This method may be used in voter to check access.

    It supports both hasCenterInterface and HasScopeInterface and check all
    required permission.

commit 9ad9f624a0aa73ca2e639fd68fe4d5559da2bbd7
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Thu Jun 18 01:01:16 2015 +0200

    add utilities to generate prophesized entities

    entities
    - User (with permissions)
    - Center
    - Scope
    may be  generated by trait/methods

    This ease test writing about acl

commit 16008b9e64bb7f551319abea494db1c1c5a12b82
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 12 22:42:46 2015 +0200

    add test to CenterType

commit 55e2c64aba9714caf09df8dbc9595980826b296a
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 12 20:50:05 2015 +0200

    first implementation of test on CenterType

    [TRANSFER][ci skip]

commit 548fb24927cc470794a51d81f1ba6af52237363f
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Wed Jun 10 21:15:52 2015 +0200

    add center type

    the center type is hidden if the current user can reach only one center,
    and is `entity` type if the user can reach multiple centers

commit 024e3ef8d969d25560406864d86768a260ef4402
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Mon Jun 8 00:28:51 2015 +0200

    add first impl of Access Model

    - first classes and interfaces
    - authorizationHelper + test
    - rewrite loadUser to have multi-center

commit bc5ae70c83c39a0a738e78313e33020fc284f456
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Sun Jun 7 22:11:13 2015 +0200

    make deprecations message not fail tests

commit ab9308ed62e45171e9d355ec033b0862b9274e07
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Sat Jun 6 10:19:19 2015 +0200

    introducting phpunit-bridge to handle deprecation warnings

commit 5b7a43c4d058af58578c30120670c5be5b11cfd8
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 5 12:49:23 2015 +0200

    fix options resolver deprecation

commit a5b4e5743f790c16dfd04e5068c5ecca9c2b1583
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 5 12:36:17 2015 +0200

    remove warning about deprecation in phpunit

commit 56621767936df1ea1293c49ae06380d7735c8d6c
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 5 11:59:50 2015 +0200

    fix pattern deprecation in routing/test

    pattern=> path

commit 17d40fc5294b245d7377572a8c918abab2484985
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 5 11:40:59 2015 +0200

    fix deprecation of pattern in routing

    pattern => path in routing

commit 6a33752c6439bd9dbc707df010ce1d8765eeb5fe
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 5 11:21:18 2015 +0200

    fix twig.form.resources deprecation

    the new key is twig.form_themes

commit adf03eb819f2d443f87d7b744f59a5adf51d2b31
Author: Julien Fastré <julien.fastre@champs-libres.coop>
Date:   Fri Jun 5 10:56:51 2015 +0200

    switch to symfony 2.7 [ci-skip]
2015-06-30 14:38:08 +02:00

449 lines
16 KiB
PHP

<?php
/*
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Tests\Security\Authorization;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Chill\MainBundle\Test\PrepareUserTrait;
use Chill\MainBundle\Test\PrepareCenterTrait;
use Chill\MainBundle\Test\PrepareScopeTrait;
use Chill\MainBundle\Test\ProphecyTrait;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Role\Role;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\Center;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class AuthorizationHelperTest extends KernelTestCase
{
use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait, ProphecyTrait;
public function setUp()
{
static::bootKernel();
}
/**
*
* @return \Chill\MainBundle\Security\Authorization\AuthorizationHelper
*/
private function getAuthorizationHelper()
{
return static::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
;
}
/**
* Test function userCanReach of helper.
*
* A user can reach center => the function should return true.
*/
public function testUserCanReachCenter_UserShouldReach()
{
$center = $this->prepareCenter(1, 'center');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'ANY_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$this->assertTrue($helper->userCanReachCenter($user, $center));
}
/**
* Test function userCanReach of helper
*
* A user can not reachcenter =>W the function should return false
*/
public function testUserCanReachCenter_UserShouldNotReach()
{
$centerA = $this->prepareCenter(1, 'center');
$centerB = $this->prepareCenter(2, 'centerB');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $centerA, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'ANY_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$this->assertFalse($helper->userCanReachCenter($user, $centerB));
}
public function testUserHasAccess_shouldHaveAccess_EntityWithoutScope()
{
$center = $this->prepareCenter(1, 'center');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'CHILL_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->getCenter()->willReturn($center);
$this->assertTrue($helper->userHasAccess($user, $entity->reveal(),
'CHILL_ROLE'));
}
public function testUserHasAccess_ShouldHaveAccessWithInheritance_EntityWithoutScope()
{
$center = $this->prepareCenter(1, 'center');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'CHILL_MASTER_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->getCenter()->willReturn($center);
$this->assertTrue($helper->userHasAccess($user, $entity->reveal(),
'CHILL_INHERITED_ROLE_1'));
}
public function testuserHasAccess_UserHasNoRole_EntityWithoutScope()
{
$center = $this->prepareCenter(1, 'center');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'ANY_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->getCenter()->willReturn($center);
$this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE'));
}
/**
* test that a user has no access on a entity, but is granted on the same role
* on another center
*/
public function testUserHasAccess_userHasNoRole_UserHasRoleOnAnotherCenter_EntityWithoutScope()
{
$centerA = $this->prepareCenter(1, 'center');
$centerB = $this->prepareCenter(2, 'centerB');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $centerA, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'ANY_ROLE']
),
array(
'centerB' => $centerB, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'ANY_ROLE'],
['scope' => $scope, 'role' => 'CHILL_ROLE']
)
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->getCenter()->willReturn($centerA);
$this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE'));
}
public function testtestUserHasAccess_UserShouldHaveAccess_EntityWithScope()
{
$center = $this->prepareCenter(1, 'center');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'CHILL_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface');
$entity->getCenter()->willReturn($center);
$entity->getScope()->willReturn($scope);
$this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE'));
}
public function testUserHasAccess_UserHasNoRole_EntityWithScope()
{
$center = $this->prepareCenter(1, 'center');
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'CHILL_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface');
$entity->getCenter()->willReturn($center);
$entity->getScope()->willReturn($scope);
$this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'ANOTHER_ROLE'));
}
public function testUserHasAccess_UserHasNoCenter_EntityWithScope()
{
$centerA = $this->prepareCenter(1, 'center'); //the user will have this center
$centerB = $this->prepareCenter(2, 'centerB'); //the entity will have another center
$scope = $this->prepareScope(1, 'default');
$user = $this->prepareUser(array(
array(
'center' => $centerA, 'permissionsGroup' => array(
['scope' => $scope, 'role' => 'CHILL_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface');
$entity->getCenter()->willReturn($centerB);
$entity->getScope()->willReturn($scope);
$this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE'));
}
public function testUserHasAccess_UserHasNoScope_EntityWithScope()
{
$center = $this->prepareCenter(1, 'center');
$scopeA = $this->prepareScope(1, 'default'); //the entity will have this scope
$scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope
$user = $this->prepareUser(array(
array(
'center' => $center, 'permissionsGroup' => array(
['scope' => $scopeB, 'role' => 'CHILL_ROLE']
)
)
));
$helper = $this->getAuthorizationHelper();
$entity = $this->getProphet()->prophesize();
$entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface');
$entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface');
$entity->getCenter()->willReturn($center);
$entity->getScope()->willReturn($scopeA);
$this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE'));
}
/**
*
* @dataProvider dataProvider_getReachableCenters
* @param Center $shouldHaveCenter
* @param User $user
* @param Role $role
* @param Scope $scope
*/
public function testGetReachableCenters($test, $result, $msg)
{
$this->assertEquals($test, $result, $msg);
}
public function dataProvider_getReachableCenters()
{
$this->setUp();
$centerA = $this->prepareCenter(1, 'center A');
$centerB = $this->prepareCenter(2, 'center B');
$scopeA = $this->prepareScope(1, 'scope default');
$scopeB = $this->prepareScope(2, 'scope B');
$scopeC = $this->prepareScope(3, 'scope C');
$userA = $this->prepareUser(array(
array(
'center' => $centerA,
'permissionsGroup' => array(
['scope' => $scopeB, 'role' => 'CHILL_ROLE_1'],
['scope' => $scopeA, 'role' => 'CHILL_ROLE_2']
)
),
array(
'center' => $centerB,
'permissionsGroup' => array(
['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'],
['scope' => $scopeC, 'role' => 'CHILL_ROLE_2']
)
)
));
$ah = $this->getAuthorizationHelper();
return array(
// without scopes
array(
true,
in_array($centerA, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_1'), null)),
'center A should be available for userA, with role 1 '
),
array(
true,
in_array($centerA, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_2'), null)),
'center A should be available for userA, with role 2 '
),
array(
true,
in_array($centerB, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_2'), null)),
'center A should be available for userA, with role 2 '
),
array(
false,
in_array($centerB, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_1'), null)),
'center B should NOT be available for userA, with role 1 '
),
// with scope
array(
true,
in_array($centerA, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_1'), $scopeB)),
'center A should be available for userA, with role 1, scopeC '
),
array(
false,
in_array($centerA, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_2'), $scopeC)),
'center A should NOT be available for userA, with role 2, scopeA '
),
array(
true,
in_array($centerB, $ah->getReachableCenters($userA,
new Role('CHILL_ROLE_2'), $scopeA)),
'center B should be available for userA, with role 2, scopeA '
),
);
}
/**
*
* @dataProvider dataProvider_getReachableScopes
* @param boolean $expectedResult
* @param Scope $testedScope
* @param User $user
* @param Role $role
* @param Center $center
* @param string $message
*/
public function testGetReachableScopes($expectedResult, Scope $testedScope,
User $user, Role $role, Center $center, $message)
{
$reachableScopes = $this->getAuthorizationHelper()
->getReachableScopes($user, $role, $center);
$this->assertEquals($expectedResult, in_array($testedScope, $reachableScopes),
$message);
}
public function dataProvider_getReachableScopes()
{
$centerA = $this->prepareCenter(1, 'center A');
$centerB = $this->prepareCenter(2, 'center B');
$scopeA = $this->prepareScope(1, 'scope default');
$scopeB = $this->prepareScope(2, 'scope B');
$scopeC = $this->prepareScope(3, 'scope C');
$userA = $this->prepareUser(array(
array(
'center' => $centerA,
'permissionsGroup' => array(
['scope' => $scopeB, 'role' => 'CHILL_ROLE_1'],
['scope' => $scopeA, 'role' => 'CHILL_ROLE_2']
)
),
array(
'center' => $centerB,
'permissionsGroup' => array(
['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'],
['scope' => $scopeC, 'role' => 'CHILL_ROLE_2'],
['scope' => $scopeB, 'role' => 'CHILL_ROLE_2']
)
)
));
return array(
array(
true,
$scopeA,
$userA,
new Role('CHILL_ROLE_2'),
$centerA,
"Assert that a scope is found within accessible scopes"
),
array(
false,
$scopeB,
$userA,
new Role('CHILL_ROLE_2'),
$centerA,
"Assert that a scope not reachable is NOT found within accessible scopes"
),
array(
false,
$scopeB,
$userA,
new Role('CHILL_ROLE_1'),
$centerB,
"Assert that a scope not reachable is not found within accessible scopes."
. " Trying on filter centering"
)
);
}
}