From 4d2b3f2a6175ad2c84b519e2410b9fb07fd9bb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 22 Jun 2015 23:47:01 +0200 Subject: [PATCH] add report voter + tests --- Resources/config/services.yml | 9 +- Security/Authorization/ReportVoter.php | 66 ++++++ .../Authorization/ReportVoterTest.php | 193 ++++++++++++++++++ 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 Security/Authorization/ReportVoter.php create mode 100644 Tests/Security/Authorization/ReportVoterTest.php diff --git a/Resources/config/services.yml b/Resources/config/services.yml index f5305da04..774d6e677 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -18,4 +18,11 @@ services: arguments: - '@doctrine.orm.entity_manager' tags: - - { name: chill.timeline, context: 'person' } \ No newline at end of file + - { name: chill.timeline, context: 'person' } + + chill.report.security.authorization.report_voter: + class: Chill\ReportBundle\Security\Authorization\ReportVoter + arguments: + - "@chill.main.security.authorization.helper" + tags: + - { name: security.voter } \ No newline at end of file diff --git a/Security/Authorization/ReportVoter.php b/Security/Authorization/ReportVoter.php new file mode 100644 index 000000000..e363923df --- /dev/null +++ b/Security/Authorization/ReportVoter.php @@ -0,0 +1,66 @@ + + * + * 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 . + */ + +namespace Chill\ReportBundle\Security\Authorization; + +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; + +/** + * + * + * @author Julien Fastré + */ +class ReportVoter extends AbstractChillVoter +{ + const CREATE = 'CHILL_REPORT_CREATE'; + const SEE = 'CHILL_REPORT_SEE'; + const UPDATE = 'CHILL_REPORT_UPDATE'; + + /** + * + * @var AuthorizationHelper + */ + protected $helper; + + public function __construct(AuthorizationHelper $helper) + { + $this->helper = $helper; + } + + protected function getSupportedAttributes() + { + return array(self::CREATE, self::SEE, self::UPDATE); + } + + protected function getSupportedClasses() + { + return array('Chill\ReportBundle\Entity\Report'); + } + + protected function isGranted($attribute, $report, $user = null) + { + if (! $user instanceof \Chill\MainBundle\Entity\User){ + + return false; + } + + return $this->helper->userHasAccess($user, $report, $attribute); + } +} diff --git a/Tests/Security/Authorization/ReportVoterTest.php b/Tests/Security/Authorization/ReportVoterTest.php new file mode 100644 index 000000000..8fa450fb0 --- /dev/null +++ b/Tests/Security/Authorization/ReportVoterTest.php @@ -0,0 +1,193 @@ + + * + * 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 . + */ + +namespace Chill\ReportBundle\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\ReportBundle\Entity\Report; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Entity\Center; +use Chill\PersonBundle\Entity\Person; + +/** + * + * + * @author Julien Fastré + */ +class ReportVoterTest extends KernelTestCase +{ + + use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait; + + /** + * + * @var \Chill\ReportBundle\Security\Authorization\ReportVoter + */ + protected $voter; + + /** + * + * @var \Prophecy\Prophet + */ + protected $prophet; + + public static function setUpBeforeClass() + { + + } + + public function setUp() + { + static::bootKernel(); + $this->voter = static::$kernel->getContainer() + ->get('chill.report.security.authorization.report_voter'); + $this->prophet = new \Prophecy\Prophet(); + } + + /** + * @dataProvider dataProvider + * @param type $expectedResult + * @param Report $report + * @param User $user + * @param type $action + * @param type $message + */ + public function testAccess($expectedResult, Report $report, $action, + $message, User $user = null) + { + $token = $this->prepareToken($user); + $result = $this->voter->vote($token, $report, [$action]); + $this->assertEquals($expectedResult, $result, $message); + } + + /** + * prepare a person + * + * The only properties set is the center, others properties are ignored. + * + * @param Center $center + * @return Person + */ + protected function preparePerson(Center $center) + { + return (new Person()) + ->setCenter($center) + ; + } + + /** + * prepare a token interface with correct rights + * + * if $permissions = null, user will be null (no user associated with token + * + * @param User $user + * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface + */ + protected function prepareToken(User $user = null) + { + $token = $this->prophet->prophesize(); + $token + ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + if ($user === NULL) { + $token->getUser()->willReturn(null); + } else { + $token->getUser()->willReturn($user); + } + + return $token->reveal(); + } + + public function dataProvider() + { + $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_REPORT_SEE'], + ['scope' => $scopeA, 'role' => 'CHILL_REPORT_UPDATE'] + ) + ), + array( + 'center' => $centerB, + 'permissionsGroup' => array( + ['scope' => $scopeA, 'role' => 'CHILL_REPORT_SEE'], + ) + ) + + )); + + $reportA = (new Report) + ->setScope($scopeA) + ->setPerson($this->preparePerson($centerA)) + ; + $reportB = (new Report()) + ->setScope($scopeB) + ->setPerson($this->preparePerson($centerA)) + ; + $reportC = (new Report()) + ->setScope($scopeC) + ->setPerson($this->preparePerson($centerB)) + ; + + + return array( + array( + VoterInterface::ACCESS_DENIED, + $reportA, + 'CHILL_REPORT_SEE', + "assert is denied to a null user", + null + ), + array( + VoterInterface::ACCESS_GRANTED, + $reportA, + 'CHILL_REPORT_SEE', + "assert access is granted to a user with inheritance UPDATE > SEE", + $userA + ), + array( + VoterInterface::ACCESS_GRANTED, + $reportB, + 'CHILL_REPORT_SEE', + "assert access is granted to a user without inheritance", + $userA + ), + array( + VoterInterface::ACCESS_DENIED, + $reportC, + 'CHILL_REPORT_SEE', + 'assert access is denied to a report', + $userA + ) + ); + + } + + +}