This repository has been archived by the owner on Jul 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 111
Add route permissions guard and controller permissions guard #238
Merged
bakura10
merged 20 commits into
ZF-Commons:master
from
jmleroux:route-permissions-guard
Jun 19, 2014
Merged
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
5f5e1e7
Add route permissions guard
jmleroux b3dda6d
Moved to src + Docblock
jmleroux 78f8e66
route permissions guard factory test
jmleroux 8e75f52
typo
jmleroux 9539831
change permissions guard priority to 10
jmleroux ec8321e
Add route permissions guard tests
jmleroux 7e25038
Update documentation 04.Guards
jmleroux f20b7fa
Code format
jmleroux 8f78325
Update documentation 04.Guards
jmleroux 26ff936
docblock, comments and variable names
jmleroux d9fa14d
guard plugin manager for RoutePermissionsGuard
jmleroux 07c16ba
Permission config is an AND condition
jmleroux 7a834b2
documentation 04.guards
jmleroux 255d622
documentation 04.guards
jmleroux 7ecd164
tests : change permissions names in data provider
jmleroux 2bb5a83
tests
jmleroux ea027cf
RoutePermissionsGuard priority
jmleroux 6984b01
revert rule_type
jmleroux 7926465
ControllerPermissionsGuard
jmleroux f26b666
Documentation for ControllerPermissionsGuard
jmleroux File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfcRbac\Factory; | ||
|
||
use Zend\ServiceManager\FactoryInterface; | ||
use Zend\ServiceManager\MutableCreationOptionsInterface; | ||
use Zend\ServiceManager\ServiceLocatorInterface; | ||
use ZfcRbac\Guard\ControllerPermissionsGuard; | ||
use ZfcRbac\Guard\RouteGuard; | ||
|
||
/** | ||
* Create a controller guard for checking permissions | ||
* | ||
* @author JM Lerouxw <[email protected]> | ||
* @licence MIT | ||
*/ | ||
class ControllerPermissionsGuardFactory implements FactoryInterface, MutableCreationOptionsInterface | ||
{ | ||
/** | ||
* @var array | ||
*/ | ||
protected $options = []; | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function setCreationOptions(array $options) | ||
{ | ||
$this->options = $options; | ||
} | ||
|
||
/** | ||
* @param \Zend\ServiceManager\AbstractPluginManager|ServiceLocatorInterface $serviceLocator | ||
* @return RouteGuard | ||
*/ | ||
public function createService(ServiceLocatorInterface $serviceLocator) | ||
{ | ||
$parentLocator = $serviceLocator->getServiceLocator(); | ||
|
||
/* @var \ZfcRbac\Options\ModuleOptions $moduleOptions */ | ||
$moduleOptions = $parentLocator->get('ZfcRbac\Options\ModuleOptions'); | ||
|
||
/* @var \ZfcRbac\Service\AuthorizationService $authorizationService */ | ||
$authorizationService = $parentLocator->get('ZfcRbac\Service\AuthorizationService'); | ||
|
||
$guard = new ControllerPermissionsGuard($authorizationService, $this->options); | ||
$guard->setProtectionPolicy($moduleOptions->getProtectionPolicy()); | ||
|
||
return $guard; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfcRbac\Factory; | ||
|
||
use Zend\ServiceManager\FactoryInterface; | ||
use Zend\ServiceManager\MutableCreationOptionsInterface; | ||
use Zend\ServiceManager\ServiceLocatorInterface; | ||
use ZfcRbac\Guard\RouteGuard; | ||
use ZfcRbac\Guard\RoutePermissionsGuard; | ||
|
||
/** | ||
* Create a route guard for checking permissions | ||
* | ||
* @author Michaël Gallego <[email protected]> | ||
* @author JM Lerouxw <[email protected]> | ||
* @licence MIT | ||
*/ | ||
class RoutePermissionsGuardFactory implements FactoryInterface, MutableCreationOptionsInterface | ||
{ | ||
/** | ||
* @var array | ||
*/ | ||
protected $options = []; | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function setCreationOptions(array $options) | ||
{ | ||
$this->options = $options; | ||
} | ||
|
||
/** | ||
* @param \Zend\ServiceManager\AbstractPluginManager|ServiceLocatorInterface $serviceLocator | ||
* @return RouteGuard | ||
*/ | ||
public function createService(ServiceLocatorInterface $serviceLocator) | ||
{ | ||
$parentLocator = $serviceLocator->getServiceLocator(); | ||
|
||
/* @var \ZfcRbac\Options\ModuleOptions $moduleOptions */ | ||
$moduleOptions = $parentLocator->get('ZfcRbac\Options\ModuleOptions'); | ||
|
||
/* @var \ZfcRbac\Service\AuthorizationService $authorizationService */ | ||
$authorizationService = $parentLocator->get('ZfcRbac\Service\AuthorizationService'); | ||
|
||
$routeGuard = new RoutePermissionsGuard($authorizationService, $this->options); | ||
$routeGuard->setProtectionPolicy($moduleOptions->getProtectionPolicy()); | ||
|
||
return $routeGuard; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
<?php | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is the whole file marked as changed? Very hard to know what has changed :/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'cause it's a new one 😉 ControllerPermissionsGuard |
||
/* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* This software consists of voluntary contributions made by many individuals | ||
* and is licensed under the MIT license. | ||
*/ | ||
|
||
namespace ZfcRbac\Guard; | ||
|
||
use Zend\Mvc\MvcEvent; | ||
use ZfcRbac\Service\AuthorizationServiceInterface; | ||
|
||
/** | ||
* A controller guard can protect a controller and a set of actions | ||
* | ||
* @author Michaël Gallego <[email protected]> | ||
* @author JM Leroux <[email protected]> | ||
* @licence MIT | ||
*/ | ||
class ControllerPermissionsGuard extends AbstractGuard | ||
{ | ||
use ProtectionPolicyTrait; | ||
|
||
/** | ||
* Event priority | ||
*/ | ||
const EVENT_PRIORITY = -15; | ||
|
||
/** | ||
* @var AuthorizationServiceInterface | ||
*/ | ||
protected $authorizationService; | ||
|
||
/** | ||
* Controller guard rules | ||
* | ||
* @var array | ||
*/ | ||
protected $rules = []; | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param AuthorizationServiceInterface $authorizationService | ||
* @param array $rules | ||
*/ | ||
public function __construct(AuthorizationServiceInterface $authorizationService, array $rules = []) | ||
{ | ||
$this->authorizationService = $authorizationService; | ||
$this->setRules($rules); | ||
} | ||
|
||
/** | ||
* Set the rules | ||
* | ||
* A controller rule is made the following way: | ||
* | ||
* [ | ||
* 'controller' => 'ControllerName', | ||
* 'actions' => []/string | ||
* 'roles' => []/string | ||
* ] | ||
* | ||
* @param array $rules | ||
* @return void | ||
*/ | ||
public function setRules(array $rules) | ||
{ | ||
$this->rules = []; | ||
|
||
foreach ($rules as $rule) { | ||
$controller = strtolower($rule['controller']); | ||
$actions = isset($rule['actions']) ? (array) $rule['actions'] : []; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix alignment of "=" |
||
$permissions = (array) $rule['permissions']; | ||
|
||
if (empty($actions)) { | ||
$this->rules[$controller][0] = $permissions; | ||
continue; | ||
} | ||
|
||
foreach ($actions as $action) { | ||
$this->rules[$controller][strtolower($action)] = $permissions; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function isGranted(MvcEvent $event) | ||
{ | ||
$routeMatch = $event->getRouteMatch(); | ||
$controller = strtolower($routeMatch->getParam('controller')); | ||
$action = strtolower($routeMatch->getParam('action')); | ||
|
||
// If no rules apply, it is considered as granted or not based on the protection policy | ||
if (!isset($this->rules[$controller])) { | ||
return $this->protectionPolicy === self::POLICY_ALLOW; | ||
} | ||
|
||
// Algorithm is as follow: we first check if there is an exact match (controller + action), if not | ||
// we check if there are rules set globally for the whole controllers (see the index "0"), and finally | ||
// if nothing is matched, we fallback to the protection policy logic | ||
|
||
if (isset($this->rules[$controller][$action])) { | ||
$allowedPermissions = $this->rules[$controller][$action]; | ||
} elseif (isset($this->rules[$controller][0])) { | ||
$allowedPermissions = $this->rules[$controller][0]; | ||
} else { | ||
return $this->protectionPolicy === self::POLICY_ALLOW; | ||
} | ||
|
||
// If no rules apply, it is considered as granted or not based on the protection policy | ||
if (empty($allowedPermissions)) { | ||
return $this->protectionPolicy === self::POLICY_ALLOW; | ||
} | ||
|
||
if (in_array('*', $allowedPermissions)) { | ||
return true; | ||
} | ||
|
||
foreach ($allowedPermissions as $permission) { | ||
if (!$this->authorizationService->isGranted($permission)) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I honestly find it confusing. "admin" is typically not a "permission", it's just a role. Typical permissions that admin may have is something like "post.delete_others". We already had this discussion and we came to the conclusion that this is the cleanest way to solve this problem. Then the admin have both "post.delete" and "post.delete_others" permissions while normal users only have "post.delete".