123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- <?php
- /**
- *
- * Cube Framework $Id$ +ZjSTmVALawSGSDsJRY8yHBeEWJfviBwiv8jozAo7sA=
- *
- * @link http://codecu.be/framework
- * @copyright Copyright (c) 2015 CodeCube SRL
- * @license http://codecu.be/framework/license Commercial License
- *
- * @version 1.4
- */
- namespace Cube\Permissions;
- /**
- * access control list management class
- *
- * Class Acl
- *
- * @package Cube\Permissions
- */
- class Acl
- {
- /**
- * rule type = allow
- */
- const TYPE_ALLOW = 'ALLOW';
- /**
- * rule type = deny
- */
- const TYPE_DENY = 'DENY';
- /**
- * rule operation = add
- */
- const OPERATION_ADD = 'ADD';
- /**
- * rule operation = remove
- */
- const OPERATION_REMOVE = 'REMOVE';
- /**
- *
- * array of roles
- *
- * @var array
- */
- protected $_roles = array();
- /**
- *
- * array of resources
- *
- * @var array
- */
- protected $_resources = array();
- /**
- *
- * array of rules
- *
- * array format:
- *
- * array($resourceId => array(
- * $roleId = array(
- * array(
- * 'name' => $privilegeName|null (all privileges)
- * 'type' => ALLOW|DENY
- * )
- * )
- * )
- *
- * @var array
- */
- protected $_rules = array();
- /**
- *
- * add a role to the roles array
- *
- * @param \Cube\Permissions\RoleInterface $role
- * @param mixed $parents
- *
- * @throws \RuntimeException
- * @throws \InvalidArgumentException
- * @throws \DomainException
- * @return $this
- */
- public function addRole(RoleInterface $role, $parents = null)
- {
- $roleId = $role->getId();
- $roleParents = array();
- if ($this->hasRole($role)) {
- throw new \InvalidArgumentException(
- sprintf("The role with the id '%s' already exists.", $roleId));
- }
- if ($parents !== null) {
- if (!is_array($parents)) {
- $parents = array($parents);
- }
- foreach ((array)$parents as $parent) {
- if (!$parent instanceof RoleInterface) {
- throw new \RuntimeException("All role parents must be of type \Cube\Permissions\RoleInterface");
- }
- $roleParentId = $parent->getId();
- if ($roleId === $roleParentId) {
- throw new \DomainException(
- sprintf("Cannot set a parent role as itself, role id '%s'.", $roleId));
- }
- $roleParents[$roleParentId] = $parent;
- $this->_roles[$roleParentId]['children'][$roleId] = $role;
- }
- }
- $this->_roles[$roleId] = array(
- 'instance' => $role,
- 'parents' => $roleParents,
- 'children' => array()
- );
- return $this;
- }
- /**
- *
- * check if a role exists in the acl
- *
- * @param string|\Cube\Permissions\RoleInterface $role
- *
- * @return bool
- */
- public function hasRole($role)
- {
- if ($role instanceof RoleInterface) {
- $roleId = $role->getId();
- }
- else {
- $roleId = (string)$role;
- }
- return isset($this->_roles[$roleId]);
- }
- /**
- *
- * return the role instance
- *
- * @param string|\Cube\Permissions\RoleInterface $role
- *
- * @return \Cube\Permissions\RoleInterface
- * @throws \InvalidArgumentException
- */
- public function getRole($role)
- {
- if ($role instanceof RoleInterface) {
- $roleId = $role->getId();
- }
- else {
- $roleId = (string)$role;
- }
- if ($this->hasRole($role) === false) {
- throw new \InvalidArgumentException(
- sprintf("The role '%s' was not found.", $roleId));
- }
- return $this->_roles[$roleId]['instance'];
- }
- /**
- *
- * remove a role from the roles array, including parent and child dependencies
- *
- * @param string|\Cube\Permissions\RoleInterface $role
- *
- * @return $this
- */
- public function removeRole($role)
- {
- $roleId = $this->getRole($role)->getId();
- foreach ($this->_roles[$roleId]['children'] as $childId => $child) {
- unset($this->_roles[$childId]['parents'][$roleId]);
- }
- foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) {
- unset($this->_roles[$parentId]['children'][$roleId]);
- }
- unset($this->_roles[$roleId]);
- return $this;
- }
- /**
- *
- * reset roles array
- *
- * @return $this
- */
- public function removeAllRoles()
- {
- $this->_roles = array();
- foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) {
- unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]);
- }
- foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) {
- foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) {
- unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]);
- }
- }
- return $this;
- }
- /**
- *
- * get all roles from the acl
- *
- * @return array
- */
- public function getRoles()
- {
- return $this->_roles;
- }
- /**
- *
- * get the parents of a role
- *
- * @param string|\Cube\Permissions\RoleInterface $role
- *
- * @return array
- */
- public function getRoleParents($role)
- {
- $roleId = $this->getRole($role)->getId();
- return $this->_roles[$roleId]['parents'];
- }
- /**
- *
- * add resource to acl
- *
- * @param \Cube\Permissions\ResourceInterface $resource
- * @param mixed $parent
- *
- * @return $this
- * @throws \InvalidArgumentException
- */
- public function addResource(ResourceInterface $resource, $parent = null)
- {
- $resourceId = $resource->getId();
- if ($this->hasResource($resource)) {
- throw new \InvalidArgumentException(
- sprintf("The resource with the id '%s' already exists.", $resourceId));
- }
- $resourceParent = null;
- if ($parent !== null) {
- if ($parent instanceof ResourceInterface) {
- $resourceParentId = $parent->getId();
- }
- else {
- $resourceParentId = $parent;
- }
- $resourceParent = $this->getResource($resourceParentId);
- $this->_resources[$resourceParentId]['children'][$resourceId] = $resource;
- }
- $this->_resources[$resourceId] = array(
- 'instance' => $resource,
- 'parent' => $resourceParent,
- 'children' => array()
- );
- return $this;
- }
- /**
- *
- * check if a resource exists in the acl
- *
- * @param string|\Cube\Permissions\ResourceInterface $resource
- *
- * @return bool
- */
- public function hasResource($resource)
- {
- if ($resource instanceof ResourceInterface) {
- $resourceId = $resource->getId();
- }
- else {
- $resourceId = (string)$resource;
- }
- return isset($this->_resources[$resourceId]);
- }
- /**
- *
- * get a resource instance
- *
- * @param string|\Cube\Permissions\ResourceInterface $resource
- *
- * @return \Cube\Permissions\ResourceInterface
- * @throws \InvalidArgumentException
- */
- public function getResource($resource)
- {
- if ($resource instanceof ResourceInterface) {
- $resourceId = $resource->getId();
- }
- else {
- $resourceId = (string)$resource;
- }
- if ($this->hasResource($resource) === false) {
- throw new \InvalidArgumentException(
- sprintf("The resource '%s' was not found.", $resourceId));
- }
- return $this->_resources[$resourceId]['instance'];
- }
- /**
- *
- * remove a resource from the resources array, including parent and child dependencies
- *
- * @param string|\Cube\Permissions\ResourceInterface $resource
- *
- * @return $this
- */
- public function removeResource($resource)
- {
- $resourceId = $this->getResource($resource)->getId();
- $resourcesRemoved = array($resourceId);
- if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) {
- unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]);
- }
- foreach ($this->_resources[$resourceId]['children'] as $childId => $child) {
- $this->removeResource($childId);
- $resourcesRemoved[] = $childId;
- }
- unset($this->_roles[$resourceId]);
- unset($this->_resources[$resourceId]);
- return $this;
- }
- /**
- *
- * reset resources array
- *
- * @return $this
- */
- public function removeAllResources()
- {
- $this->_rules = array();
- $this->_resources = array();
- return $this;
- }
- /**
- *
- * set acl rule
- *
- * @param string $operation
- * @param string $type
- * @param string|array|\Cube\Permissions\RoleInterface $roles
- * @param string|array|\Cube\Permissions\ResourceInterface $resources
- * @param string|array $privileges
- * @param \Cube\Permissions\AssertInterface $assert
- *
- * @return $this
- */
- protected function _setRule($operation, $type, $roles, $resources, $privileges = null, AssertInterface $assert = null)
- {
- if (!is_array($roles)) {
- $roles = array($roles);
- }
- $rolesTmp = $roles;
- $roles = array();
- foreach ($rolesTmp as $role) {
- $roles[] = $this->getRole($role)->getId();
- }
- unset($rolesTmp);
- if (!is_array($resources)) {
- $resources = array($resources);
- }
- $resourcesTmp = $resources;
- $resources = array();
- foreach ($resourcesTmp as $resource) {
- $resources[] = $this->getResource($resource)->getId();
- }
- if (!is_array($privileges)) {
- $privileges = array($privileges);
- }
- switch ($operation) {
- case self::OPERATION_ADD:
- foreach ($resources as $resource) {
- foreach ($roles as $role) {
- foreach ($privileges as $privilege) {
- $this->_rules[$resource][$role][(string)$privilege] = array(
- 'type' => $type,
- 'assert' => $assert,
- );
- }
- }
- }
- break;
- case self::OPERATION_REMOVE:
- foreach ($resources as $resource) {
- foreach ($roles as $role) {
- if ($privileges !== null) {
- foreach ($privileges as $privilege) {
- unset($this->_rules[$resource][$role][(string)$privilege]);
- }
- }
- else {
- unset($this->_rules[$resource][$role]);
- }
- if (empty($this->_rules[$resource][$role])) {
- unset($this->_rules[$resource][$role]);
- }
- }
- if (empty($this->_rules[$resource])) {
- unset($this->_rules[$resource]);
- }
- }
- break;
- }
- return $this;
- }
- /**
- *
- * set a rule of type allow
- *
- * @param string|array|\Cube\Permissions\RoleInterface $roles
- * @param string|array|\Cube\Permissions\ResourceInterface $resources
- * @param string|array $privileges
- * @param \Cube\Permissions\AssertInterface $assert
- *
- * @return $this
- */
- public function allow($roles = null, $resources = null, $privileges = null, AssertInterface $assert = null)
- {
- return $this->_setRule(self::OPERATION_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
- }
- /**
- *
- * set a rule of type deny
- *
- * @param string|array|\Cube\Permissions\RoleInterface $roles
- * @param string|array|\Cube\Permissions\ResourceInterface $resources
- * @param string|array $privileges
- * @param \Cube\Permissions\AssertInterface $assert
- *
- * @return $this
- */
- public function deny($roles = null, $resources = null, $privileges = null, AssertInterface $assert = null)
- {
- return $this->_setRule(self::OPERATION_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
- }
- /**
- *
- * remove a rule of type allow
- *
- * @param string|array|\Cube\Permissions\RoleInterface $roles
- * @param string|array|\Cube\Permissions\ResourceInterface $resources
- * @param string|array $privileges
- * @param \Cube\Permissions\AssertInterface $assert
- *
- * @return $this
- */
- public function removeAllow($roles = null, $resources = null, $privileges = null, AssertInterface $assert = null)
- {
- return $this->_setRule(self::OPERATION_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert);
- }
- /**
- *
- * remove a rule of type deny
- *
- * @param string|array|\Cube\Permissions\RoleInterface $roles
- * @param string|array|\Cube\Permissions\ResourceInterface $resources
- * @param string|array $privileges
- * @param \Cube\Permissions\AssertInterface $assert
- *
- * @return $this
- */
- public function removeDeny($roles = null, $resources = null, $privileges = null, AssertInterface $assert = null)
- {
- return $this->_setRule(self::OPERATION_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges, $assert);
- }
- /**
- *
- * check if one or more roles are allowed for a certain resource
- * for allowed to be true, at least one role needs to be allowed
- *
- * @param array|string|\Cube\Permissions\RoleInterface $roles
- * @param string|\Cube\Permissions\ResourceInterface $resource
- * @param string $privilege
- *
- * @return bool
- */
- public function isAllowed($roles, $resource, $privilege = null)
- {
- if (!is_array($roles)) {
- $roles = array($roles);
- }
- $allowed = false;
- foreach ($roles as $role) {
- $allowed = ($this->_isAllowed($role, $resource, $privilege) === true) ? true : $allowed;
- }
- return $allowed;
- }
- /**
- *
- * check if a role is allowed to access a certain resource
- *
- * if the rule is defined by a parent, then if one parent allows the resource,
- * then return true
- * only return false if either specified by a rule of the role or if all parents
- * assert to false
- *
- * TODO: CUSTOM ASSERTIONS
- * RULE WITH NO PARENTS AND NO ACTION DOESNT SEEM TO WORK
- *
- * @param array|string|\Cube\Permissions\RoleInterface $role
- * @param string|\Cube\Permissions\ResourceInterface $resource
- * @param string $privilege
- *
- * @return bool
- */
- protected function _isAllowed($role, $resource, $privilege = null)
- {
- $roleId = $this->getRole($role)->getId();
- $resourceId = $this->getResource($resource)->getId();
- $privilege = (string)$privilege;
- $rule = null;
- $allowed = false;
- if (isset($this->_rules[$resourceId][$roleId][$privilege])) {
- // applies to a single action
- $rule = $this->_rules[$resourceId][$roleId][$privilege];
- }
- else if (isset($this->_rules[$resourceId][$roleId][''])) {
- // the rule applies to all actions
- $rule = $this->_rules[$resourceId][$roleId][''];
- }
- if ($rule !== null) {
- if ($rule['assert'] !== null) {
- $allowed = $rule['assert']->assert($this, $role, $resource, $privilege);
- }
- else if ($rule['type'] === self::TYPE_ALLOW) {
- $allowed = true;
- }
- else if ($rule['type'] === self::TYPE_DENY) {
- $allowed = false;
- }
- }
- else {
- $parents = $this->getRoleParents($role);
- foreach ($parents as $parent) {
- if ($this->isAllowed($parent, $resource, $privilege) === true) {
- return true;
- }
- }
- }
- return $allowed;
- }
- }
|