diff --git a/phalcon/Acl/Adapter/Memory.zep b/phalcon/Acl/Adapter/Memory.zep index c1e16ac9095..36f0ed738f3 100644 --- a/phalcon/Acl/Adapter/Memory.zep +++ b/phalcon/Acl/Adapter/Memory.zep @@ -592,18 +592,19 @@ class Memory extends Adapter */ public function isAllowed(var roleName, var componentName, string access, array parameters = null) -> bool { - var eventsManager, accessList, accessKey, haveAccess = null, rolesNames, - funcAccess = null, componentObject = null, roleObject = null, - funcList, reflectionFunction, reflectionParameters, parameterNumber, - parametersForFunction, numberOfRequiredParameters, - userParametersSizeShouldBe, reflectionClass, parameterToCheck, - reflectionParameter; - bool hasRole = false, hasComponent = false; + var accessKey, accessList, componentObject = null, haveAccess = null, + eventsManager, funcAccess = null, funcList, numberOfRequiredParameters, + reflectionFunction, reflectionParameters, parameterNumber, + parameterToCheck, parametersForFunction, reflectionClass, + reflectionParameter, rolesNames, roleObject = null, + userParametersSizeShouldBe; + + bool hasComponent = false, hasRole = false; if typeof roleName == "object" { if roleName instanceof RoleAware { - let roleObject = roleName; - let roleName = roleObject->getRoleName(); + let roleObject = roleName, + roleName = roleObject->getRoleName(); } elseif roleName instanceof RoleInterface { let roleName = roleName->getName(); } else { @@ -615,8 +616,8 @@ class Memory extends Adapter if typeof componentName == "object" { if componentName instanceof ComponentAware { - let componentObject = componentName; - let componentName = componentObject->getComponentName(); + let componentObject = componentName, + componentName = componentObject->getComponentName(); } elseif componentName instanceof ComponentInterface { let componentName = componentName->getName(); } else { @@ -626,16 +627,17 @@ class Memory extends Adapter } } - let this->activeRole = roleName; - let this->activeComponent = componentName; - let this->activeAccess = access; - let this->activeKey = null; - let this->activeFunction = null; - let this->activeFunctionCustomArgumentsCount = 0; + let this->activeRole = roleName, + this->activeComponent = componentName, + this->activeAccess = access, + this->activeKey = null, + this->activeKey = null, + this->activeFunction = null, + accessList = this->access, + eventsManager = this->eventsManager, + funcList = this->func; - let accessList = this->access; - let eventsManager = this->eventsManager; - let funcList = this->func; + let this->activeFunctionCustomArgumentsCount = 0; if typeof eventsManager == "object" { if eventsManager->fire("acl:beforeCheckAccess", this) === false { @@ -672,8 +674,8 @@ class Memory extends Adapter eventsManager->fire("acl:afterCheckAccess", this); } - let this->activeKey = accessKey; - let this->activeFunction = funcAccess; + let this->activeKey = accessKey, + this->activeFunction = funcAccess; if haveAccess == null { /** @@ -689,9 +691,9 @@ class Memory extends Adapter * If we have funcAccess then do all the checks for it */ if is_callable(funcAccess) { - let reflectionFunction = new \ReflectionFunction(funcAccess); - let reflectionParameters = reflectionFunction->getParameters(); - let parameterNumber = count(reflectionParameters); + let reflectionFunction = new \ReflectionFunction(funcAccess), + reflectionParameters = reflectionFunction->getParameters(), + parameterNumber = count(reflectionParameters); /** * No parameters, just return haveAccess and call function without @@ -701,19 +703,19 @@ class Memory extends Adapter return haveAccess == Acl::ALLOW && call_user_func(funcAccess); } - let parametersForFunction = []; - let numberOfRequiredParameters = reflectionFunction->getNumberOfRequiredParameters(); - let userParametersSizeShouldBe = parameterNumber; + let parametersForFunction = [], + numberOfRequiredParameters = reflectionFunction->getNumberOfRequiredParameters(), + userParametersSizeShouldBe = parameterNumber; for reflectionParameter in reflectionParameters { - let reflectionClass = reflectionParameter->getClass(); - let parameterToCheck = reflectionParameter->getName(); + let reflectionClass = reflectionParameter->getClass(), + parameterToCheck = reflectionParameter->getName(); if reflectionClass !== null { // roleObject is this class if roleObject !== null && reflectionClass->isInstance(roleObject) && !hasRole { - let hasRole = true; - let parametersForFunction[] = roleObject; + let hasRole = true, + parametersForFunction[] = roleObject; let userParametersSizeShouldBe--; continue; @@ -721,8 +723,8 @@ class Memory extends Adapter // componentObject is this class if componentObject !== null && reflectionClass->isInstance(componentObject) && !hasComponent { - let hasComponent = true; - let parametersForFunction[] = componentObject; + let hasComponent = true, + parametersForFunction[] = componentObject; let userParametersSizeShouldBe--; continue; diff --git a/phalcon/Firewall/Adapter.zep b/phalcon/Firewall/Adapter.zep new file mode 100644 index 00000000000..62f571c0b71 --- /dev/null +++ b/phalcon/Firewall/Adapter.zep @@ -0,0 +1,248 @@ + +/** + * This file is part of the Phalcon Framework. + * + * (c) Phalcon Team + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Phalcon\Firewall; + +use Phalcon\Acl; +use Phalcon\Acl\RoleAware; +use Phalcon\Cache\Adapter\AdapterInterface as CacheAdapterInterface; +use Phalcon\DiInterface; +use Phalcon\Events\EventsAwareInterface; +use Phalcon\Events\ManagerInterface; +use Phalcon\Mvc\Dispatcher; + +/** + * Phalcon\Firewall\Adapter + * + * Adapter for Phalcon\Firewall adapters + */ +abstract class Adapter implements AdapterInterface, EventsAwareInterface +{ + /** + * Storing active identity object implementing Phalcon/Acl/RoleAware + */ + protected activeIdentity { get }; + + /** + * Storing active user role + */ + protected activeRole { get }; + + /** + * Should role always be resolved using role callback or just once? + * @var bool + */ + protected alwaysResolvingRole = false { set }; + + /** + * Cache for caching access + * @var + */ + protected cache; + + /** + * Default access + * @var int + */ + protected defaultAccess = Acl::DENY { get, set }; + + /** + * Events manager + * @var mixed + */ + protected eventsManager; + + /** + * Internal cache for caching access during request time + * @var mixed + */ + protected internalCache; + + /** + * Anonymous function for getting user identity - this function must + * return string, array or object implementing Phalcon\Acl\RoleAware + * @var mixed + */ + protected roleCallback; + + /** + * Returns the internal event manager + */ + public function getEventsManager() -> + { + return this->eventsManager; + } + + /** + * Gets role callback to fetch role name + */ + public function getRoleCallback() -> <\Closure> + { + return this->roleCallback; + } + + /** + * Gets always resolving role option + */ + public function isAlwaysResolvingRole() -> bool + { + return this->alwaysResolvingRole; + } + + /** + * Sets the events manager + */ + public function setEventsManager( eventsManager) -> + { + let this->eventsManager = eventsManager; + + return this; + } + + /** + * Sets role callback to fetch role name + */ + public function setRoleCallback(var callback) -> + { + if !is_callable(callback){ + throw new Exception("Role callback must be function."); + } + let this->roleCallback = callback; + + return this; + } + + protected function callRoleCallback( container) -> void + { + var roleCallback, identity; + + let roleCallback = this->roleCallback, + identity = {roleCallback}(container); + + if empty identity { + throw new Exception("Function defined as roleCallback must return something."); + } + + if typeof identity == "object" { + if !(identity instanceof RoleAware) { + throw new Exception("Role passed as object must implement 'Phalcon\\Acl\\RoleAware'"); + } + let this->activeIdentity = identity, + this->activeRole = identity->getRoleName(); + } else { + let this->activeRole = identity; + } + } + + /** + * Gets access from cache + */ + protected function getAccessFromCache( + string! key, + array originalValues = null, + string roleCacheKey = null + ) -> bool | null + { + var access; + + fetch access, this->internalCache[key]; + + return access; + } + + /** + * Handles a user exception + */ + protected function handleException(<\Exception> exception) + { + var eventsManager; + let eventsManager = this->eventsManager; + if typeof eventsManager == "object" { + if eventsManager->fire("firewall:beforeException", this, exception) === false { + return false; + } + } + } + + /** + * Fires event or throwing exception + */ + protected function fireEventOrThrowException( + var role, + string actionName, + string controllerName, + bool access + ) + { + var eventsManager, roleName; + + let eventsManager = this->eventsManager; + if access { + if typeof eventsManager == "object" { + eventsManager->fire("firewall:afterCheck",this); + } + } else { + if typeof role == "array" { + let roleName = implode(", ",role); + } else { + let roleName = role; + } + + return this->throwFirewallException( + "Role name " . roleName . " doesn't have access to action " . + actionName . " in controller " . controllerName, + 403 + ); + } + } + + /** + * Saves access in cache and internal cache + */ + protected function saveAccessInCache(string! key, bool access) -> void + { + var cache; + + let this->internalCache[key] = access; + + let cache = this->cache; + + if cache != null { + cache->save("_PHF_", this->internalCache); + } + } + + public function setCache( cache) -> + { + let this->cache = cache; + + if this->internalCache === null { + let this->internalCache = cache->get("_PHF_"); + } + + return this; + } + + /** + * Throws an internal exception + */ + protected function throwFirewallException(string message, int exceptionCode = 0) + { + var exception; + + let exception = new Exception(message, exceptionCode); + + if this->handleException(exception) === false { + return false; + } + + throw exception; + } +} diff --git a/phalcon/firewall/adapter/acl.zep b/phalcon/Firewall/Adapter/Acl.zep similarity index 50% rename from phalcon/firewall/adapter/acl.zep rename to phalcon/Firewall/Adapter/Acl.zep index e23d6e62166..01a484711ae 100644 --- a/phalcon/firewall/adapter/acl.zep +++ b/phalcon/Firewall/Adapter/Acl.zep @@ -1,33 +1,22 @@ -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (http://www.phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - | Wojciech Ślawski | - +------------------------------------------------------------------------+ +/** + * This file is part of the Phalcon Framework. + * + * (c) Phalcon Team + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. */ - namespace Phalcon\Firewall\Adapter; +use Phalcon\Di; +use Phalcon\Cache\Adapter\AdapterInterface; +use Phalcon\Events\Event; +use Phalcon\Events\ManagerInterface; use Phalcon\Firewall\Adapter; use Phalcon\Firewall\Exception; -use Phalcon\Events\Event; use Phalcon\Mvc\DispatcherInterface; -use Phalcon\Di; -use Phalcon\Events\ManagerInterface; -use Phalcon\Cache\BackendInterface; /** * Phalcon\Mvc\Dispatcher\Firewall\Adapter\Acl @@ -40,42 +29,43 @@ class Acl extends Adapter * Acl service name * @var string */ - protected _aclServiceName { get, set }; + protected aclServiceName { get, set }; /** - * Parameter for using with multi module application - * @var boolean + * Bound models + * @var array */ - protected _multiModuleConfiguration = false; + protected boundModels; /** - * Separator between module name and controller prefix - * @var string + * Property used for setting different key names in associated acl function than got from Binder */ - protected _moduleSeparator = ":" { get, set }; + protected boundModelsKeyMap { get, set }; /** - * Function returning string for role cache key + * Dispatcher * @var mixed */ - protected _roleCacheCallback { get, set }; + protected dispatcher; /** - * Bound models - * @var array + * Parameter for using with multi module application + * @var bool */ - protected _boundModels; + protected multiModuleConfiguration = false; /** - * Property used for setting different key names in associated acl function than got from Binder + * Separator between module name and controller prefix + * @var string */ - protected _boundModelsKeyMap { get, set }; + protected moduleSeparator = ":" { get, set }; /** - * Dispatcher + * Function returning string for role cache key * @var mixed */ - protected _dispatcher; + protected roleCacheCallback { get, set }; + /** * Phalcon\Firewall\Adapter\Acl constructor @@ -85,8 +75,23 @@ class Acl extends Adapter */ public function __construct(string aclServiceName, array boundModelsKeyMap = null) { - let this->_aclServiceName = aclServiceName; - let this->_boundModelsKeyMap = boundModelsKeyMap; + let this->aclServiceName = aclServiceName, + this->boundModelsKeyMap = boundModelsKeyMap; + } + + public function afterBinding( event, dispatcher, var data) + { + let this->boundModels = dispatcher->getBoundModels(), + this->dispatcher = dispatcher; + + return this->handleDispatcher(dispatcher); + } + + public function beforeExecuteRoute( event, dispatcher, var data) + { + let this->dispatcher = dispatcher; + + return this->handleDispatcher(dispatcher); } /** @@ -94,106 +99,185 @@ class Acl extends Adapter */ public function getDispatcher() -> { - return this->_dispatcher; + return this->dispatcher; } /** * Returns multiModuleConfiguration - * @return boolean + * @return bool */ - public function isMultiModuleConfiguration() -> boolean + public function isMultiModuleConfiguration() -> bool { - return this->_multiModuleConfiguration; + return this->multiModuleConfiguration; } /** * Sets multiModuleConfiguration */ - public function useMultiModuleConfiguration(boolean multiModuleConfiguration) + public function useMultiModuleConfiguration(bool multiModuleConfiguration) { - let this->_multiModuleConfiguration = multiModuleConfiguration; + let this->multiModuleConfiguration = multiModuleConfiguration; return this; } - public function afterBinding( event, dispatcher, var data) + protected function getAccessFromCache( + string! key, + array originalValues = null, + string roleCacheKey = null + ) -> bool | null { - let this->_boundModels = dispatcher->getBoundModels(); - let this->_dispatcher = dispatcher; + var explodedKey, access, keyWithValues, originalKeysJoin; - return this->handleDispatcher(dispatcher); - } + if roleCacheKey != null { + let roleCacheKey = "!".roleCacheKey; + } - public function beforeExecuteRoute( event, dispatcher, var data) - { - let this->_dispatcher = dispatcher; - return this->handleDispatcher(dispatcher); + let explodedKey = explode("!", key); + + /** + * If this is inherited role we change it to our active role to keep things simpler + */ + if explodedKey[0] != this->activeRole { + let explodedKey[0] = this->activeRole; + let key = join("!", explodedKey); + } + + /** + * If there is original values from binding then use it first + */ + if !empty originalValues { + let originalKeysJoin = join("!", originalValues), + keyWithValues = key."!".originalKeysJoin.roleCacheKey, + access = parent::getAccessFromCache(keyWithValues); + + if access !== null { + return null; + } + + /** + * Try role-resource-* + */ + + let access = parent::getAccessFromCache( + explodedKey[0] . "!" . explodedKey[1] . "!*!" . originalKeysJoin . roleCacheKey + ); + + if access !== null { + return access; + } + + /** + * Try role-*-* + */ + + let access = parent::getAccessFromCache( + explodedKey[0] . "!*!*!" . originalKeysJoin . roleCacheKey + ); + + if access !== null { + return access; + } + } + + let access = parent::getAccessFromCache(key.roleCacheKey); + + if access !== null { + return null; + } + + /** + * Try role-resource-* + */ + let access = parent::getAccessFromCache( + explodedKey[0] . "!" . explodedKey[1] . "!*" . roleCacheKey + ); + + if access !== null { + return access; + } + + /** + * Try role-*-* + */ + + let access = parent::getAccessFromCache(explodedKey[0]."!*!*".roleCacheKey); + + return access; } protected function handleDispatcher( dispatcher) { - var role, actionName, acl, aclServiceName, aclRole, aclAccess, defaultAccess, - parameters, value, dependencyInjector, controllerName, moduleName, moduleSeparator, - boundModel, boundModelKey, boundModels, boundModelsKeyMap, boundModelKeyMap, cacheKey, originalValues, - roleCacheKey, roleCacheCallback, modelBinder; + var acl, aclAccess, aclRole, aclServiceName, actionName, boundModel, + boundModelKey, boundModelKeyMap, boundModels, boundModelsKeyMap, + cacheKey, container, controllerName, defaultAccess, modelBinder, + moduleName, moduleSeparator, originalValues, parameters, + roleCacheKey, roleCacheCallback, role,value; string resourceName; // there were some seg fault when result from ucfirst was assigned to var - let dependencyInjector = dispatcher->getDI(); - if typeof dependencyInjector != "object" { - throw new Exception("A dependency injector container is required to obtain ACL service"); + let container = dispatcher->getDI(); + if typeof container != "object" { + throw new Exception(Exception::containerServiceNotFound("the ACL service")); } - let defaultAccess = (bool)this->_defaultAccess; - let parameters = []; - let controllerName = get_class(dispatcher->getActiveController()); - let boundModels = this->_boundModels; - let boundModelsKeyMap = this->_boundModelsKeyMap; + let defaultAccess = (bool) this->defaultAccess, + parameters = [], + controllerName = get_class(dispatcher->getActiveController()), + boundModels = this->boundModels, + boundModelsKeyMap = this->boundModelsKeyMap; - if !this->_multiModuleConfiguration { + if !this->multiModuleConfiguration { let resourceName = ucfirst(dispatcher->getControllerName()); } else { - let moduleSeparator = this->_moduleSeparator; - let moduleName = dispatcher->getModuleName(); - let resourceName = moduleName.moduleSeparator.ucfirst(dispatcher->getControllerName()); + let moduleSeparator = this->moduleSeparator, + moduleName = dispatcher->getModuleName(), + resourceName = moduleName.moduleSeparator.ucfirst(dispatcher->getControllerName()); } let actionName = dispatcher->getActionName(); - if this->_activeRole == null || this->_alwaysResolvingRole { - let this->_activeRole = null; - let this->_activeIdentity = null; - this->callRoleCallback(dependencyInjector); + if this->activeRole == null || this->alwaysResolvingRole { + let this->activeRole = null, + this->activeIdentity = null; + + this->callRoleCallback(container); } - let aclRole = this->_activeRole; + let aclRole = this->activeRole; // handle role as object - if typeof this->_activeIdentity == "object" { - let role = this->_activeIdentity; + if typeof this->activeIdentity == "object" { + let role = this->activeIdentity; } else { let role = aclRole; } if typeof aclRole != "string" { - throw new Exception("When using ACL service as firewall configuration you can pass role only as string or object implementing 'Phalcon\\Acl\\RoleAware'."); + throw new Exception( + "When using ACL service as firewall configuration you can " . + "pass role only as string or object implementing 'Phalcon\\Acl\\RoleAware'." + ); } - let cacheKey = aclRole."!".resourceName."!".actionName; - let modelBinder = dispatcher->getModelBinder(); + let cacheKey = aclRole . "!" . resourceName . "!" . actionName, + modelBinder = dispatcher->getModelBinder(); if modelBinder != null { let originalValues = modelBinder->getOriginalValues(); } - let roleCacheCallback = this->_roleCacheCallback; + let roleCacheCallback = this->roleCacheCallback; if typeof role == "object" && roleCacheCallback != null { let roleCacheKey = {roleCacheCallback}(role); } let aclAccess = this->getAccessFromCache(cacheKey, originalValues, roleCacheKey); if aclAccess === null { - let aclServiceName = this->_aclServiceName; - let acl = dependencyInjector->get(aclServiceName); + let aclServiceName = this->aclServiceName, + acl = container->get(aclServiceName); if typeof acl != "object" || !(acl instanceof \Phalcon\Acl\AdapterInterface) { - throw new Exception("You need to add acl service to dependency injector container which is implementing 'Phalcon\\Acl\\AdapterInterface'"); + throw new Exception( + "You need to add acl service to dependency injector " . + "container which is implementing 'Phalcon\\Acl\\AdapterInterface'" + ); } // check if role exist @@ -203,7 +287,12 @@ class Acl extends Adapter // if resource doesn't exist check against firewall defaultAccess if !acl->isResource(resourceName) { - let value = this->fireEventOrThrowException(aclRole, actionName, controllerName, defaultAccess); + let value = this->fireEventOrThrowException( + aclRole, + actionName, + controllerName, + defaultAccess + ); if roleCacheKey != null { this->saveAccessInCache(cacheKey."!".roleCacheKey, defaultAccess); } else { @@ -251,97 +340,21 @@ class Acl extends Adapter } } - protected function saveAccessInCache(string! key, boolean access) -> void + protected function saveAccessInCache(string! key, bool access) -> void { var explodedKey, activeRole; - let explodedKey = explode("!", key); - let activeRole = this->_activeRole; + let explodedKey = explode("!", key), + activeRole = this->activeRole; /** * We are not saving info about inherited role, if access was got from inherited role, save it as an actual role to keep things simple */ if explodedKey[0] != activeRole { - let explodedKey[0] = activeRole; - let key = join("!", explodedKey); + let explodedKey[0] = activeRole, + key = join("!", explodedKey); } parent::saveAccessInCache(key, access); } - - protected function getAccessFromCache(string! key, array originalValues = null, string roleCacheKey = null) -> boolean|null - { - var explodedKey, access, keyWithValues, originalKeysJoin; - - if roleCacheKey != null { - let roleCacheKey = "!".roleCacheKey; - } - - - let explodedKey = explode("!", key); - - /** - * If this is inherited role we change it to our active role to keep things simpler - */ - if explodedKey[0] != this->_activeRole { - let explodedKey[0] = this->_activeRole; - let key = join("!", explodedKey); - } - - /** - * If there is original values from binding then use it first - */ - if !empty originalValues { - let originalKeysJoin = join("!", originalValues); - let keyWithValues = key."!".originalKeysJoin.roleCacheKey; - let access = parent::getAccessFromCache(keyWithValues); - - if access !== null { - return null; - } - - /** - * Try role-resource-* - */ - - let access = parent::getAccessFromCache(explodedKey[0]."!".explodedKey[1]."!*!".originalKeysJoin.roleCacheKey); - - if access !== null { - return access; - } - - /** - * Try role-*-* - */ - - let access = parent::getAccessFromCache(explodedKey[0]."!*!*!".originalKeysJoin.roleCacheKey); - - if access !== null { - return access; - } - } - - let access = parent::getAccessFromCache(key.roleCacheKey); - - if access !== null { - return null; - } - - /** - * Try role-resource-* - */ - let access = parent::getAccessFromCache(explodedKey[0]."!".explodedKey[1]."!*".roleCacheKey); - - if access !== null { - return access; - } - - /** - * Try role-*-* - */ - - let access = parent::getAccessFromCache(explodedKey[0]."!*!*".roleCacheKey); - - return access; - } } diff --git a/phalcon/firewall/adapter/annotations.zep b/phalcon/Firewall/Adapter/Annotations.zep similarity index 52% rename from phalcon/firewall/adapter/annotations.zep rename to phalcon/Firewall/Adapter/Annotations.zep index e0808f909cc..c189e94968d 100644 --- a/phalcon/firewall/adapter/annotations.zep +++ b/phalcon/Firewall/Adapter/Annotations.zep @@ -1,34 +1,23 @@ -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (http://www.phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - | Wojciech Ślawski | - +------------------------------------------------------------------------+ +/** + * This file is part of the Phalcon Framework. + * + * (c) Phalcon Team + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. */ - namespace Phalcon\Firewall\Adapter; +use Phalcon\Annotations\AdapterInterface; +use Phalcon\Cache\Adapter\AdapterInterface; +use Phalcon\Events\Event; +use Phalcon\Events\ManagerInterface; use Phalcon\Firewall\Adapter; use Phalcon\Firewall\Exception; -use Phalcon\Events\Event; use Phalcon\Mvc\DispatcherInterface; use ReflectionClass; -use Phalcon\Annotations\AdapterInterface; -use Phalcon\Events\ManagerInterface; -use Phalcon\Cache\BackendInterface; /** * Phalcon\Firewall\Adapter\Annotations @@ -38,27 +27,27 @@ use Phalcon\Cache\BackendInterface; class Annotations extends Adapter { /** - * Adapter for annotations - * @var mixed + * Number of active active arguments in active annotation + * @var int */ - protected _annotationsAdapter { get, set }; + protected activeArgumentsNumber = 0; /** - * Number of active active arguments in active annotation - * @var int + * Adapter for annotations + * @var mixed */ - protected _activeArgumentsNumber = 0; + protected annotationsAdapter { get, set }; /** * Dispatcher * @var mixed */ - protected _dispatcher; + protected dispatcher; /** * Role for which access was granted */ - protected _resolvedRole; + protected resolvedRole; /** * Phalcon\Firewall\Adapter\Annotations constructor @@ -67,58 +56,59 @@ class Annotations extends Adapter */ public function __construct( annotationsAdapter) { - let this->_annotationsAdapter = annotationsAdapter; - } - - /** - * Gets dispatcher - */ - public function getDispatcher() -> - { - return this->_dispatcher; + let this->annotationsAdapter = annotationsAdapter; } public function beforeExecuteRoute( event, dispatcher, var data) { - var role, controllerName, actionName, defaultAccess, eventsManager, value, cacheKey, controllerClass, - singleRole, access, dependencyInjector; - - let this->_activeArgumentsNumber = 0; - let this->_dispatcher = dispatcher; - let defaultAccess = (bool)this->_defaultAccess; - let eventsManager = this->_eventsManager; - let controllerName = dispatcher->getControllerName(); - let controllerClass = dispatcher->getControllerClass(); - let actionName = dispatcher->getActionName(); - let this->_resolvedRole = null; - let dependencyInjector = dispatcher->getDI(); - - if this->_activeRole == null || this->_alwaysResolvingRole { - let this->_activeRole = null; - let this->_activeIdentity = null; - this->callRoleCallback(dependencyInjector); + var access, actionName, cacheKey, container, controllerClass, + controllerName, defaultAccess, eventsManager, role, singleRole, + value; + + let this->activeArgumentsNumber = 0; + + let this->dispatcher = dispatcher, + defaultAccess = (bool) this->defaultAccess, + eventsManager = this->eventsManager, + controllerName = dispatcher->getControllerName(), + controllerClass = dispatcher->getControllerClass(), + actionName = dispatcher->getActionName(), + this->resolvedRole = null, + container = dispatcher->getDI(); + + if this->activeRole == null || this->alwaysResolvingRole { + let this->activeRole = null, + this->activeIdentity = null; + + this->callRoleCallback(container); } - let role = this->_activeRole; + let role = this->activeRole; if typeof role == "array" { for singleRole in role { - let cacheKey = singleRole."!".controllerName."!".actionName; - let access = this->getAccessFromCache(cacheKey); + let cacheKey = singleRole . "!" . controllerName . "!" . actionName, + access = this->getAccessFromCache(cacheKey); if typeof access == "boolean" { break; } } } else { - let cacheKey = role."!".controllerName."!".actionName; - let access = this->getAccessFromCache(cacheKey); + let cacheKey = role . "!" . controllerName . "!" . actionName, + access = this->getAccessFromCache(cacheKey); } if typeof role != "string" && typeof role != "array" { - throw new Exception("When using firewall based on annotations you must pass role as string, array or object implementing 'RoleAware'."); + throw new Exception( + "When using firewall based on annotations you must pass " . + "role as string, array or object implementing 'RoleAware'." + ); } - if this->_annotationsAdapter == null { - throw new Exception("You need to set annotations adapter for firewall based on annotations configurator to work"); + if this->annotationsAdapter == null { + throw new Exception( + "You need to set annotations adapter for firewall based " . + "on annotations configurator to work" + ); } if typeof eventsManager == "object" { eventsManager->fire("firewall:beforeCheck", this); @@ -149,19 +139,26 @@ class Annotations extends Adapter } } + /** + * Gets dispatcher + */ + public function getDispatcher() -> + { + return this->dispatcher; + } + protected function checkControllerAnnotationAccess(string controllerClass, string controllerName, var role) { var annotationsAdapter, reflector, annotations, access, singleRole, resolvedRole; - let annotationsAdapter = this->_annotationsAdapter; - let reflector = annotationsAdapter->get(controllerClass); - let annotations = reflector->getClassAnnotations(); - - let access = this->_checkAnnotations(annotations, role); + let annotationsAdapter = this->annotationsAdapter, + reflector = annotationsAdapter->get(controllerClass), + annotations = reflector->getClassAnnotations(), + access = this->checkAnnotations(annotations, role); if typeof access == "boolean" { - if this->_activeArgumentsNumber > 0 { - let resolvedRole = this->_resolvedRole; + if this->activeArgumentsNumber > 0 { + let resolvedRole = this->resolvedRole; if typeof resolvedRole == "array" { for singleRole in resolvedRole { this->saveAccessInCache(singleRole."!".controllerName."!*", access); @@ -177,46 +174,19 @@ class Annotations extends Adapter return access; } - protected function checkActionAnnotationAccess(string controllerClass, string controllerName, string actionName, var role) - { - var annotationsAdapter, annotations, access, singleRole, resolvedRole; - - let annotationsAdapter = this->_annotationsAdapter; - let annotations = annotationsAdapter->getMethod(controllerClass, actionName."Action"); - - let access = this->_checkAnnotations(annotations, role); - - if typeof access == "boolean" { - if this->_activeArgumentsNumber > 0 { - let resolvedRole = this->_resolvedRole; - if typeof resolvedRole == "array" { - for singleRole in resolvedRole { - this->saveAccessInCache(singleRole."!".controllerName."!".actionName, access); - } - } else { - this->saveAccessInCache(resolvedRole."!".controllerName."!".actionName, access); - } - } else { - this->saveAccessInCache("*!".controllerName."!".actionName, access); - } - } - - return access; - } - - protected function _checkAnnotations(var annotations, var role) + protected function checkAnnotations(var annotations, var role) { var returnAllow; if !empty annotations { if annotations->has("Allow") { - let returnAllow = this->_handleAnnotation(annotations->get("Allow"), true, role); + let returnAllow = this->handleAnnotation(annotations->get("Allow"), true, role); if typeof returnAllow == "boolean" { return returnAllow; } } if annotations->has("Deny") { - let returnAllow = this->_handleAnnotation(annotations->get("Deny"), false, role); + let returnAllow = this->handleAnnotation(annotations->get("Deny"), false, role); if typeof returnAllow == "boolean" { return returnAllow; } @@ -226,55 +196,43 @@ class Annotations extends Adapter return null; } - protected function _handleAnnotation(var annotation, boolean access, var role) + protected function checkActionAnnotationAccess( + string controllerClass, + string controllerName, + string actionName, + var role + ) { - var numberArguments, annotationRoles, roleIntersect; + var annotationsAdapter, annotations, access, singleRole, resolvedRole; - let numberArguments = annotation->numberArguments(); - let this->_activeArgumentsNumber = numberArguments; - if numberArguments === 1 { - let annotationRoles = annotation->getArguments()[0]; - if typeof annotationRoles == "array" { - if typeof role == "string" && in_array(role, annotationRoles) { - let this->_resolvedRole = role; - return access; - } elseif typeof role == "array" { - let roleIntersect = array_intersect(role, annotationRoles); - if (boolean)roleIntersect { - let this->_resolvedRole = roleIntersect; - return access; - } - } elseif access == false { - let this->_resolvedRole = role; - return true; - } + let annotationsAdapter = this->annotationsAdapter, + annotations = annotationsAdapter->getMethod(controllerClass, actionName."Action"); - return null; - } elseif typeof annotationRoles == "string" { - if typeof role == "string" && annotationRoles == role { - let this->_resolvedRole = role; - return access; - } elseif typeof role == "array" && in_array(annotationRoles, role) { - let this->_resolvedRole = annotationRoles; - return access; - } elseif access == false { - let this->_resolvedRole = role; - return true; - } + let access = this->checkAnnotations(annotations, role); - return null; + if typeof access == "boolean" { + if this->activeArgumentsNumber > 0 { + let resolvedRole = this->resolvedRole; + if typeof resolvedRole == "array" { + for singleRole in resolvedRole { + this->saveAccessInCache(singleRole."!".controllerName."!".actionName, access); + } + } else { + this->saveAccessInCache(resolvedRole."!".controllerName."!".actionName, access); + } } else { - throw new Exception("Allowed or denied role must be provided as string or array of roles."); + this->saveAccessInCache("*!".controllerName."!".actionName, access); } - } elseif numberArguments === 0 { - let this->_resolvedRole = role; - return access; - } else { - throw new Exception("Allow or deny annotation expect one or none arguments"); } + + return access; } - protected function getAccessFromCache(string! key, array originalValues = null, string roleCacheKey = null) -> boolean|null + protected function getAccessFromCache( + string! key, + array originalValues = null, + string roleCacheKey = null + ) -> bool | null { var explodedKey, access; @@ -313,4 +271,62 @@ class Annotations extends Adapter return access; } + + protected function handleAnnotation(var annotation, bool access, var role) + { + var numberArguments, annotationRoles, roleIntersect; + + let numberArguments = annotation->numberArguments(), + this->activeArgumentsNumber = numberArguments; + if numberArguments === 1 { + let annotationRoles = annotation->getArguments()[0]; + if typeof annotationRoles == "array" { + if typeof role == "string" && in_array(role, annotationRoles) { + let this->resolvedRole = role; + + return access; + } elseif typeof role == "array" { + let roleIntersect = array_intersect(role, annotationRoles); + if (bool) roleIntersect { + let this->resolvedRole = roleIntersect; + + return access; + } + } elseif access == false { + let this->resolvedRole = role; + + return true; + } + + return null; + } elseif typeof annotationRoles == "string" { + if typeof role == "string" && annotationRoles == role { + let this->resolvedRole = role; + + return access; + } elseif typeof role == "array" && in_array(annotationRoles, role) { + let this->resolvedRole = annotationRoles; + + return access; + } elseif access == false { + let this->resolvedRole = role; + + return true; + } + + return null; + } else { + throw new Exception( + "Allowed or denied role must be provided as string or array of roles." + ); + } + } elseif numberArguments === 0 { + let this->resolvedRole = role; + return access; + } else { + throw new Exception( + "Allow or deny annotation expect one or none arguments" + ); + } + } } diff --git a/phalcon/firewall/adapter/micro/acl.zep b/phalcon/Firewall/Adapter/Micro/Acl.zep similarity index 51% rename from phalcon/firewall/adapter/micro/acl.zep rename to phalcon/Firewall/Adapter/Micro/Acl.zep index 79ea8493624..38fbe938506 100644 --- a/phalcon/firewall/adapter/micro/acl.zep +++ b/phalcon/Firewall/Adapter/Micro/Acl.zep @@ -1,36 +1,25 @@ -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (http://www.phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - | Wojciech Ślawski | - +------------------------------------------------------------------------+ +/** + * This file is part of the Phalcon Framework. + * + * (c) Phalcon Team + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. */ - namespace Phalcon\Firewall\Adapter\Micro; +use Phalcon\Di; +use Phalcon\Cache\Adapter\AdapterInterface; +use Phalcon\DiInterface; +use Phalcon\Events\Event; +use Phalcon\Events\ManagerInterface; use Phalcon\Firewall\Adapter; use Phalcon\Firewall\Exception; -use Phalcon\Events\Event; use Phalcon\Mvc\Micro; -use Phalcon\Di; -use Phalcon\Events\ManagerInterface; -use Phalcon\Cache\BackendInterface; -use Phalcon\Mvc\Router; use Phalcon\Mvc\Model\BinderInterface; -use Phalcon\DiInterface; +use Phalcon\Mvc\Router; /** * Phalcon\Mvc\Dispatcher\Firewall\Adapter\Micro\Acl @@ -43,59 +32,73 @@ class Acl extends Adapter * Acl service name * @var string */ - protected _aclServiceName { get, set }; + protected aclServiceName { get, set }; /** - * By default using route names which are required, you can change it to false to use route patterns - * @var bool + * Bound models + * @var array */ - protected _routeNameConfiguration = true { set }; + protected boundModels; /** - * Resource name used to acquire access, be default it's Micro - * @var string + * Property used for setting different key names in associated acl function than got from Binder */ - protected _resourceName = "Micro" { get, set }; + protected boundModelsKeyMap { get, set }; /** - * Router object + * Micro object * @var mixed */ - protected _router; + protected micro; /** - * Micro object - * @var mixed + * Resource name used to acquire access, be default it's Micro + * @var string */ - protected _micro; + protected resourceName = "Micro" { get, set }; /** * Function returning string for role cache key * @var mixed */ - protected _roleCacheCallback { get, set }; + protected roleCacheCallback { get, set }; /** - * Bound models - * @var array + * Router object + * @var mixed */ - protected _boundModels; + protected router; /** - * Property used for setting different key names in associated acl function than got from Binder + * By default using route names which are required, you can change it to false to use route patterns + * @var bool */ - protected _boundModelsKeyMap { get, set }; + protected routeNameConfiguration = true { set }; /** - * Phalcon\Firewall\Adapter\Micro\Acl constructor - * - * @param string aclServiceName - * @param array boundModelsKeyMap + * Constructor */ - public function __construct(string aclServiceName, array boundModelsKeyMap = null) + public function __construct(string! aclServiceName, array! boundModelsKeyMap = null) { - let this->_aclServiceName = aclServiceName; - let this->_boundModelsKeyMap = boundModelsKeyMap; + let this->aclServiceName = aclServiceName, + this->boundModelsKeyMap = boundModelsKeyMap; + } + + public function afterBinding( event, micro, var data) + { + let this->boundModels = micro->getBoundModels(), + this->router = micro->getRouter(), + this->micro = micro; + + return this->handleRouter(micro); + } + + public function beforeExecuteRoute( event, micro, var data) + { + let this->router = micro->getRouter(), + this->micro = micro; + + return this->handleRouter(micro); } /** @@ -103,94 +106,193 @@ class Acl extends Adapter */ public function getMicro() -> { - return this->_micro; + return this->micro; } /** * Gets route name configuration */ - public function isRouteNameConfiguration() -> boolean + public function isRouteNameConfiguration() -> bool { - return this->_routeNameConfiguration; + return this->routeNameConfiguration; } - public function afterBinding( event, micro, var data) + /** + * Fires event or throwing exception + */ + protected function fireEventOrThrowException( + var role, + string actionName, + string controllerName, + bool access + ) { - let this->_boundModels = micro->getBoundModels(); - let this->_router = micro->getRouter(); - let this->_micro = micro; + var eventsManager, roleName; - return this->handleRouter(micro); + if access { + if typeof eventsManager == "object" { + eventsManager->fire("firewall:afterCheck",this); + } + } else { + if typeof role == "array" { + let roleName = implode(", ",role); + } else { + let roleName = role; + } + if this->routeNameConfiguration { + return this->throwFirewallException( + "Role name " . roleName . " doesn't have access to route called " . actionName, + 403 + ); + } else { + return this->throwFirewallException( + "Role name " . roleName . " doesn't have access to route with pattern " . + actionName, + 403 + ); + } + } } - public function beforeExecuteRoute( event, micro, var data) + protected function getAccessFromCache( + string! key, + array originalValues = null, + string roleCacheKey = null + ) -> bool | null { - let this->_router = micro->getRouter(); - let this->_micro = micro; + var explodedKey, access, keyWithValues, originalKeysJoin; - return this->handleRouter(micro); + if roleCacheKey != null { + let roleCacheKey = "!".roleCacheKey; + } + + let explodedKey = explode("!", key); + + /** + * If this is inherited role we change it to our active role to keep things simpler + */ + if explodedKey[0] != this->activeRole { + let explodedKey[0] = this->activeRole, + key = join("!", explodedKey); + } + + /** + * If there is original values from binding then use it first + */ + if !empty originalValues { + let originalKeysJoin = join("!", originalValues), + keyWithValues = key."!".originalKeysJoin.roleCacheKey, + access = parent::getAccessFromCache(keyWithValues); + + if access !== null { + return access; + } + + let access = parent::getAccessFromCache( + explodedKey[0] . "!" . explodedKey[1] . "!*!" . originalKeysJoin . roleCacheKey + ); + + if access !== null { + return access; + } + let access = parent::getAccessFromCache( + explodedKey[0] . "!*!*!" . originalKeysJoin . roleCacheKey + ); + + if access !== null { + return access; + } + } + + let access = parent::getAccessFromCache(key.roleCacheKey); + + if access !== null { + return access; + } + + /** + * Try role-resource-* + */ + + let access = parent::getAccessFromCache(explodedKey[0]."!".explodedKey[1]."!*".roleCacheKey); + + if access !== null { + return access; + } + + /** + * Try role-*-* + */ + + let access = parent::getAccessFromCache(explodedKey[0]."!*!*".roleCacheKey); + + return access; } protected function handleRouter( micro) { - var role, acl, aclServiceName, aclRole, aclAccess, defaultAccess, resourceName, - parameters, value, dependencyInjector, boundModel, boundModelKey, boundModels, - boundModelsKeyMap, boundModelKeyMap, cacheKey, originalValues, route, - roleCacheKey, roleCacheCallback, actionName, modelBinder; - - let dependencyInjector = micro->getDI(); - if typeof dependencyInjector != "object" { + var acl, aclAccess, aclRole, aclServiceName, actionName, boundModel, + boundModelKey, boundModelKeyMap, boundModels, boundModelsKeyMap, + cacheKey, container, defaultAccess, modelBinder, originalValues, + parameters, resourceName, role, roleCacheKey, roleCacheCallback, + route, value; + + let container = micro->getDI(); + if typeof container != "object" { throw new Exception("A dependency injector container is required to obtain ACL service"); } - let defaultAccess = (bool)this->_defaultAccess; - let parameters = []; - let route = this->_router->getMatchedRoute(); - let boundModels = this->_boundModels; - let boundModelsKeyMap = this->_boundModelsKeyMap; + let defaultAccess = (bool) this->defaultAccess, + parameters = [], + route = this->router->getMatchedRoute(), + boundModels = this->boundModels, + boundModelsKeyMap = this->boundModelsKeyMap; - if this->_routeNameConfiguration { + if this->routeNameConfiguration { let actionName = route->getName(); } else { let actionName = route->getPattern(); } - if this->_activeRole == null || this->_alwaysResolvingRole { - let this->_activeRole = null; - let this->_activeIdentity = null; - this->callRoleCallback(dependencyInjector); + if this->activeRole == null || this->alwaysResolvingRole { + let this->activeRole = null, + this->activeIdentity = null; + this->callRoleCallback(container); } - let aclRole = this->_activeRole; - let resourceName = this->_resourceName; + let aclRole = this->activeRole, + resourceName = this->resourceName; if typeof aclRole != "string" { throw new Exception("When using ACL service as firewall configuration you can pass role only as string or object implementing 'Phalcon\\Acl\\RoleAware'."); } // handle role as object - if typeof this->_activeIdentity == "object" { - let role = this->_activeIdentity; + if typeof this->activeIdentity == "object" { + let role = this->activeIdentity; } else { let role = aclRole; } - let cacheKey = aclRole."!".resourceName."!".actionName; - let modelBinder = micro->getModelBinder(); + let cacheKey = aclRole . "!" . resourceName . "!" . actionName, + modelBinder = micro->getModelBinder(); if modelBinder != null { let originalValues = modelBinder->getOriginalValues(); } - let roleCacheCallback = this->_roleCacheCallback; + let roleCacheCallback = this->roleCacheCallback; if typeof role == "object" && roleCacheCallback != null { let roleCacheKey = {roleCacheCallback}(role); } let aclAccess = this->getAccessFromCache(cacheKey, originalValues, roleCacheKey); if aclAccess === null { - let aclServiceName = this->_aclServiceName; - let acl = dependencyInjector->get(aclServiceName); + let aclServiceName = this->aclServiceName, + acl = container->get(aclServiceName); if typeof acl != "object" || !(acl instanceof \Phalcon\Acl\AdapterInterface) { - throw new Exception("You need to add acl service to dependency injector container which is implementing 'Phalcon\\Acl\\AdapterInterface'"); + throw new Exception( + "You need to add acl service to dependency injector " . + "container which is implementing 'Phalcon\\Acl\\AdapterInterface'" + ); } // check if role exist @@ -200,7 +302,12 @@ class Acl extends Adapter // if resource doesn't exist check against firewall defaultAccess if !acl->isResource(resourceName) { - let value = this->fireEventOrThrowException(aclRole, actionName, resourceName, defaultAccess); + let value = this->fireEventOrThrowException( + aclRole, + actionName, + resourceName, + defaultAccess + ); if roleCacheKey != null { this->saveAccessInCache(cacheKey."!".roleCacheKey, defaultAccess); } else { @@ -248,113 +355,22 @@ class Acl extends Adapter } } - protected function saveAccessInCache(string! key, boolean access) -> void + protected function saveAccessInCache(string! key, bool access) -> void { var explodedKey, activeRole; - let explodedKey = explode("!", key); - let activeRole = this->_activeRole; + let explodedKey = explode("!", key), + activeRole = this->activeRole; /** - * We are not saving info about inherited role, if access was got from inherited role, save it as an actual role to keep things simple + * We are not saving info about inherited role, if access was got + * from inherited role, save it as an actual role to keep things simple */ if explodedKey[0] != activeRole { - let explodedKey[0] = activeRole; - let key = join("!", explodedKey); + let explodedKey[0] = activeRole, + key = join("!", explodedKey); } parent::saveAccessInCache(key, access); } - - protected function getAccessFromCache(string! key, array originalValues = null, string roleCacheKey = null) -> boolean|null - { - var explodedKey, access, keyWithValues, originalKeysJoin; - - if roleCacheKey != null { - let roleCacheKey = "!".roleCacheKey; - } - - let explodedKey = explode("!", key); - - /** - * If this is inherited role we change it to our active role to keep things simpler - */ - if explodedKey[0] != this->_activeRole { - let explodedKey[0] = this->_activeRole; - let key = join("!", explodedKey); - } - - /** - * If there is original values from binding then use it first - */ - if !empty originalValues { - let originalKeysJoin = join("!", originalValues); - let keyWithValues = key."!".originalKeysJoin.roleCacheKey; - let access = parent::getAccessFromCache(keyWithValues); - - if access !== null { - return access; - } - - let access = parent::getAccessFromCache(explodedKey[0]."!".explodedKey[1]."!*!".originalKeysJoin.roleCacheKey); - - if access !== null { - return access; - } - let access = parent::getAccessFromCache(explodedKey[0]."!*!*!".originalKeysJoin.roleCacheKey); - - if access !== null { - return access; - } - } - - let access = parent::getAccessFromCache(key.roleCacheKey); - - if access !== null { - return access; - } - - /** - * Try role-resource-* - */ - - let access = parent::getAccessFromCache(explodedKey[0]."!".explodedKey[1]."!*".roleCacheKey); - - if access !== null { - return access; - } - - /** - * Try role-*-* - */ - - let access = parent::getAccessFromCache(explodedKey[0]."!*!*".roleCacheKey); - - return access; - } - - /** - * Fires event or throwing exception - */ - protected function fireEventOrThrowException(var role, string actionName, string controllerName, boolean access) - { - var eventsManager, roleName; - - if access { - if typeof eventsManager == "object" { - eventsManager->fire("firewall:afterCheck",this); - } - } else { - if typeof role == "array" { - let roleName = implode(", ",role); - } else { - let roleName = role; - } - if this->_routeNameConfiguration { - return this->_throwFirewallException("Role name ".roleName." doesn't have access to route called ".actionName, 403); - } else { - return this->_throwFirewallException("Role name ".roleName." doesn't have access to route with pattern ".actionName, 403); - } - } - } } diff --git a/phalcon/Firewall/AdapterInterface.zep b/phalcon/Firewall/AdapterInterface.zep new file mode 100644 index 00000000000..99fafdc67fe --- /dev/null +++ b/phalcon/Firewall/AdapterInterface.zep @@ -0,0 +1,57 @@ + +/** + * This file is part of the Phalcon Framework. + * + * (c) Phalcon Team + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Phalcon\Firewall; + +use Phalcon\Mvc\DispatcherInterface; +use Phalcon\Cache\Adapter\AdapterInterface as CacheAdapterInterface; + +/** + * Phalcon\Mvc\Dispatcher\Firewall\AdapterInterface + * + * Interface for Phalcon\Mvc\Dispatcher\Firewall adapters + */ +interface AdapterInterface +{ + /** + * Returns the default ACL access level + */ + public function getDefaultAccess() -> int; + + /** + * Gets role callback to fetch role name + */ + public function getRoleCallback(); + + /** + * Gets always resolving role option + */ + public function isAlwaysResolvingRole() -> bool; + + /** + * Sets always resolving role option + */ + public function setAlwaysResolvingRole(bool alwaysResolvingRole) -> ; + + /** + * Sets cache backend + */ + public function setCache( cache) -> ; + + /** + * Sets the default access level (Phalcon\Acl::ALLOW or Phalcon\Acl::DENY) + */ + public function setDefaultAccess(int defaultAccess) -> ; + + /** + * Sets role callback to fetch role name + */ + public function setRoleCallback(var callback) -> ; +} diff --git a/phalcon/Firewall/Exception.zep b/phalcon/Firewall/Exception.zep new file mode 100644 index 00000000000..0bd4f942743 --- /dev/null +++ b/phalcon/Firewall/Exception.zep @@ -0,0 +1,20 @@ + +/** + * This file is part of the Phalcon Framework. + * + * (c) Phalcon Team + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Phalcon\Firewall; + +/** + * Phalcon\Firewall\Exception + * + * Exceptions thrown in Phalcon\Firewall will use this class + */ +class Exception extends \Phalcon\Exception +{ +} diff --git a/phalcon/acl/adapter/memory.zep b/phalcon/acl/adapter/memory.zep deleted file mode 100644 index e45568e7df6..00000000000 --- a/phalcon/acl/adapter/memory.zep +++ /dev/null @@ -1,841 +0,0 @@ - -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (https://phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - +------------------------------------------------------------------------+ - */ - -namespace Phalcon\Acl\Adapter; - -use Phalcon\Acl; -use Phalcon\Acl\Adapter; -use Phalcon\Acl\Role; -use Phalcon\Acl\RoleInterface; -use Phalcon\Acl\Resource; -use Phalcon\Acl\Exception; -use Phalcon\Events\Manager as EventsManager; -use Phalcon\Acl\RoleAware; -use Phalcon\Acl\ResourceAware; -use Phalcon\Acl\RoleInterface; -use Phalcon\Acl\ResourceInterface; - -/** - * Phalcon\Acl\Adapter\Memory - * - * Manages ACL lists in memory - * - * - * $acl = new \Phalcon\Acl\Adapter\Memory(); - * - * $acl->setDefaultAction( - * \Phalcon\Acl::DENY - * ); - * - * // Register roles - * $roles = [ - * "users" => new \Phalcon\Acl\Role("Users"), - * "guests" => new \Phalcon\Acl\Role("Guests"), - * ]; - * foreach ($roles as $role) { - * $acl->addRole($role); - * } - * - * // Private area resources - * $privateResources = [ - * "companies" => ["index", "search", "new", "edit", "save", "create", "delete"], - * "products" => ["index", "search", "new", "edit", "save", "create", "delete"], - * "invoices" => ["index", "profile"], - * ]; - * - * foreach ($privateResources as $resourceName => $actions) { - * $acl->addResource( - * new \Phalcon\Acl\Resource($resourceName), - * $actions - * ); - * } - * - * // Public area resources - * $publicResources = [ - * "index" => ["index"], - * "about" => ["index"], - * "session" => ["index", "register", "start", "end"], - * "contact" => ["index", "send"], - * ]; - * - * foreach ($publicResources as $resourceName => $actions) { - * $acl->addResource( - * new \Phalcon\Acl\Resource($resourceName), - * $actions - * ); - * } - * - * // Grant access to public areas to both users and guests - * foreach ($roles as $role){ - * foreach ($publicResources as $resource => $actions) { - * $acl->allow($role->getName(), $resource, "*"); - * } - * } - * - * // Grant access to private area to role Users - * foreach ($privateResources as $resource => $actions) { - * foreach ($actions as $action) { - * $acl->allow("Users", $resource, $action); - * } - * } - * - */ -class Memory extends Adapter -{ - - /** - * Roles Names - * - * @var mixed - */ - protected _rolesNames; - - /** - * Roles - * - * @var mixed - */ - protected _roles; - - /** - * Resource Names - * - * @var mixed - */ - protected _resourcesNames; - - /** - * Resources - * - * @var mixed - */ - protected _resources; - - /** - * Access - * - * @var mixed - */ - protected _access; - - /** - * Role Inherits - * - * @var mixed - */ - protected _roleInherits; - - /** - * Access List - * - * @var mixed - */ - protected _accessList; - - /** - * Function List - * - * @var mixed - */ - protected _func; - - /** - * Default action for no arguments is allow - * - * @var mixed - */ - protected _noArgumentsDefaultAction = Acl::ALLOW; - - /** - * Returns latest key used to acquire access - * - * @var string|null - */ - protected _activeKey { get }; - - /** - * Returns latest function used to acquire access - * - * @var mixed - */ - protected _activeFunction { get }; - - /** - * Returns number of additional arguments(excluding role and resource) for active function - * - * @var int - */ - protected _activeFunctionCustomArgumentsCount = 0 { get }; - - /** - * Phalcon\Acl\Adapter\Memory constructor - */ - public function __construct() - { - let this->_resourcesNames = ["*": true]; - let this->_accessList = ["*!*": true]; - } - - /** - * Adds a role to the ACL list. Second parameter allows inheriting access data from other existing role - * - * Example: - * - * $acl->addRole( - * new Phalcon\Acl\Role("administrator"), - * "consultant" - * ); - * - * $acl->addRole("administrator", "consultant"); - * - * - * @param array|string accessInherits - * @param RoleInterface|string role - */ - public function addRole(role, accessInherits = null) -> boolean - { - var roleName, roleObject; - - if typeof role == "object" && role instanceof RoleInterface { - let roleName = role->getName(); - let roleObject = role; - } elseif is_string(role) { - let roleName = role; - let roleObject = new Role(role); - } else { - throw new Exception("Role must be either an string or implement RoleInterface"); - } - - if isset this->_rolesNames[roleName] { - return false; - } - - let this->_roles[] = roleObject; - let this->_rolesNames[roleName] = true; - let this->_access[roleName . "!*!*"] = this->_defaultAccess; - - if accessInherits != null { - return this->addInherit(roleName, accessInherits); - } - - return true; - } - - /** - * Do a role inherit from another existing role - */ - public function addInherit(string roleName, var roleToInherit) -> boolean - { - var roleInheritName, rolesNames, deepInheritName; - - let rolesNames = this->_rolesNames; - if !isset rolesNames[roleName] { - throw new Exception("Role '" . roleName . "' does not exist in the role list"); - } - - if typeof roleToInherit == "object" { - let roleInheritName = roleToInherit->getName(); - } else { - let roleInheritName = roleToInherit; - } - - /** - * Deep inherits - */ - if isset this->_roleInherits[roleInheritName] { - for deepInheritName in this->_roleInherits[roleInheritName] { - this->addInherit(roleName, deepInheritName); - } - } - - /** - * Check if the role to inherit is valid - */ - if !isset rolesNames[roleInheritName] { - throw new Exception("Role '" . roleInheritName . "' (to inherit) does not exist in the role list"); - } - - if roleName == roleInheritName { - return false; - } - - if !isset this->_roleInherits[roleName] { - let this->_roleInherits[roleName] = true; - } - - let this->_roleInherits[roleName][] = roleInheritName; - - return true; - } - - /** - * Check whether role exist in the roles list - */ - public function isRole(string roleName) -> boolean - { - return isset this->_rolesNames[roleName]; - } - - /** - * Check whether resource exist in the resources list - */ - public function isResource(string resourceName) -> boolean - { - return isset this->_resourcesNames[resourceName]; - } - - /** - * Adds a resource to the ACL list - * - * Access names can be a particular action, by example - * search, update, delete, etc or a list of them - * - * Example: - * - * // Add a resource to the the list allowing access to an action - * $acl->addResource( - * new Phalcon\Acl\Resource("customers"), - * "search" - * ); - * - * $acl->addResource("customers", "search"); - * - * // Add a resource with an access list - * $acl->addResource( - * new Phalcon\Acl\Resource("customers"), - * [ - * "create", - * "search", - * ] - * ); - * - * $acl->addResource( - * "customers", - * [ - * "create", - * "search", - * ] - * ); - * - * - * @param Phalcon\Acl\Resource|string resourceValue - * @param array|string accessList - */ - public function addResource(var resourceValue, var accessList) -> boolean - { - var resourceName, resourceObject; - - if typeof resourceValue == "object" { - let resourceName = resourceValue->getName(); - let resourceObject = resourceValue; - } else { - let resourceName = resourceValue; - let resourceObject = new $Resource(resourceName); - } - - if !isset this->_resourcesNames[resourceName] { - let this->_resources[] = resourceObject; - let this->_resourcesNames[resourceName] = true; - } - - return this->addResourceAccess(resourceName, accessList); - } - - /** - * Adds access to resources - * - * @param array|string accessList - */ - public function addResourceAccess(string resourceName, var accessList) -> boolean - { - var accessName, accessKey, exists; - - if !isset this->_resourcesNames[resourceName] { - throw new Exception("Resource '" . resourceName . "' does not exist in ACL"); - } - - if typeof accessList != "array" && typeof accessList != "string" { - throw new Exception("Invalid value for accessList"); - } - - let exists = true; - if typeof accessList == "array" { - for accessName in accessList { - let accessKey = resourceName . "!" . accessName; - if !isset this->_accessList[accessKey] { - let this->_accessList[accessKey] = exists; - } - } - } else { - let accessKey = resourceName . "!" . accessList; - if !isset this->_accessList[accessKey] { - let this->_accessList[accessKey] = exists; - } - } - - return true; - } - - /** - * Removes an access from a resource - * - * @param array|string accessList - */ - public function dropResourceAccess(string resourceName, var accessList) - { - var accessName, accessKey; - - if typeof accessList == "array" { - for accessName in accessList { - let accessKey = resourceName . "!" . accessName; - if isset this->_accessList[accessKey] { - unset this->_accessList[accessKey]; - } - } - } else { - if typeof accessList == "string" { - let accessKey = resourceName . "!" . accessName; - if isset this->_accessList[accessKey] { - unset this->_accessList[accessKey]; - } - } - } - } - - /** - * Checks if a role has access to a resource - */ - protected function _allowOrDeny(string roleName, string resourceName, var access, var action, var func = null) - { - var accessList, accessName, accessKey; - - if !isset this->_rolesNames[roleName] { - throw new Exception("Role '" . roleName . "' does not exist in ACL"); - } - - if !isset this->_resourcesNames[resourceName] { - throw new Exception("Resource '" . resourceName . "' does not exist in ACL"); - } - - let accessList = this->_accessList; - - if typeof access == "array" { - - for accessName in access { - let accessKey = resourceName . "!" . accessName; - if !isset accessList[accessKey] { - throw new Exception("Access '" . accessName . "' does not exist in resource '" . resourceName . "'"); - } - } - - for accessName in access { - - let accessKey = roleName . "!" .resourceName . "!" . accessName; - let this->_access[accessKey] = action; - if func != null { - let this->_func[accessKey] = func; - } - } - - } else { - - if access != "*" { - let accessKey = resourceName . "!" . access; - if !isset accessList[accessKey] { - throw new Exception("Access '" . access . "' does not exist in resource '" . resourceName . "'"); - } - } - - let accessKey = roleName . "!" . resourceName . "!" . access; - - /** - * Define the access action for the specified accessKey - */ - let this->_access[accessKey] = action; - if func != null { - let this->_func[accessKey] = func; - } - - } - } - - /** - * Allow access to a role on a resource - * - * You can use '*' as wildcard - * - * Example: - * - * //Allow access to guests to search on customers - * $acl->allow("guests", "customers", "search"); - * - * //Allow access to guests to search or create on customers - * $acl->allow("guests", "customers", ["search", "create"]); - * - * //Allow access to any role to browse on products - * $acl->allow("*", "products", "browse"); - * - * //Allow access to any role to browse on any resource - * $acl->allow("*", "*", "browse"); - * - */ - public function allow(string roleName, string resourceName, var access, var func = null) - { - var innerRoleName; - - if roleName != "*" { - return this->_allowOrDeny(roleName, resourceName, access, Acl::ALLOW, func); - } else { - for innerRoleName, _ in this->_rolesNames { - this->_allowOrDeny(innerRoleName, resourceName, access, Acl::ALLOW, func); - } - } - } - - /** - * Deny access to a role on a resource - * - * You can use '*' as wildcard - * - * Example: - * - * //Deny access to guests to search on customers - * $acl->deny("guests", "customers", "search"); - * - * //Deny access to guests to search or create on customers - * $acl->deny("guests", "customers", ["search", "create"]); - * - * //Deny access to any role to browse on products - * $acl->deny("*", "products", "browse"); - * - * //Deny access to any role to browse on any resource - * $acl->deny("*", "*", "browse"); - * - */ - public function deny(string roleName, string resourceName, var access, var func = null) - { - var innerRoleName; - - if roleName != "*" { - return this->_allowordeny(roleName, resourceName, access, Acl::DENY, func); - } else { - for innerRoleName, _ in this->_rolesNames { - this->_allowordeny(innerRoleName, resourceName, access, Acl::DENY, func); - } - } - } - - /** - * Check whether a role is allowed to access an action from a resource - * - * - * //Does andres have access to the customers resource to create? - * $acl->isAllowed("andres", "Products", "create"); - * - * //Do guests have access to any resource to edit? - * $acl->isAllowed("guests", "*", "edit"); - * - */ - public function isAllowed(var roleName, var resourceName, string access, array parameters = null) -> boolean - { - var eventsManager, accessList, accessKey, - haveAccess = null, roleInherits, inheritedRole, rolesNames, - inheritedRoles, funcAccess = null, resourceObject = null, roleObject = null, funcList, - reflectionFunction, reflectionParameters, parameterNumber, parametersForFunction, - numberOfRequiredParameters, userParametersSizeShouldBe, reflectionClass, parameterToCheck, - reflectionParameter; - - if typeof roleName == "object" { - if !(roleName instanceof RoleAware) { - throw new Exception("Object passed as roleName must implement RoleAware"); - } - let roleObject = roleName; - let roleName = roleObject->getRoleName(); - } - - if typeof resourceName == "object" { - if !(resourceName instanceof ResourceAware) { - throw new Exception("Object passed as resourceName must implement ResourceAware"); - } - let resourceObject = resourceName; - let resourceName = resourceObject->getResourceName(); - } - - let this->_activeRole = roleName; - let this->_activeResource = resourceName; - let this->_activeAccess = access; - let this->_activeKey = null; - let this->_activeFunction = null; - let this->_activeFunctionCustomArgumentsCount = 0; - - let accessList = this->_access; - let eventsManager = this->_eventsManager; - let funcList = this->_func; - - if typeof eventsManager == "object" { - if eventsManager->fire("acl:beforeCheckAccess", this) === false { - return false; - } - } - - /** - * Check if the role exists - */ - let rolesNames = this->_rolesNames; - if !isset rolesNames[roleName] { - return (this->_defaultAccess == Acl::ALLOW); - } - - let accessKey = roleName . "!" . resourceName . "!" . access; - - /** - * Check if there is a direct combination for role-resource-access - */ - if isset accessList[accessKey] { - let haveAccess = accessList[accessKey]; - } - - fetch funcAccess, funcList[accessKey]; - - /** - * Check in the inherits roles - */ - if haveAccess == null { - - let roleInherits = this->_roleInherits; - if fetch inheritedRoles, roleInherits[roleName] { - if typeof inheritedRoles == "array" { - for inheritedRole in inheritedRoles { - let accessKey = inheritedRole . "!" . resourceName . "!" . access; - - /** - * Check if there is a direct combination in one of the inherited roles - */ - if isset accessList[accessKey] { - let haveAccess = accessList[accessKey]; - } - fetch funcAccess, funcList[accessKey]; - } - } - } - } - - /** - * If access wasn't found yet, try role-resource-* - */ - if haveAccess == null { - - let accessKey = roleName . "!" . resourceName . "!*"; - - /** - * In the direct role - */ - if isset accessList[accessKey] { - let haveAccess = accessList[accessKey]; - fetch funcAccess, funcList[accessKey]; - } else { - if typeof inheritedRoles == "array" { - for inheritedRole in inheritedRoles { - let accessKey = inheritedRole . "!" . resourceName . "!*"; - - /** - * In the inherited roles - */ - fetch funcAccess, funcList[accessKey]; - if isset accessList[accessKey] { - let haveAccess = accessList[accessKey]; - break; - } - } - } - } - } - - /** - * If access wasn't found yet, try role-*-* - */ - if haveAccess == null { - - let accessKey = roleName . "!*!*"; - - /** - * Try in the direct role - */ - if isset accessList[accessKey] { - let haveAccess = accessList[accessKey]; - fetch funcAccess, funcList[accessKey]; - } else { - if typeof inheritedRoles == "array" { - for inheritedRole in inheritedRoles { - let accessKey = inheritedRole . "!*!*"; - - /** - * In the inherited roles - */ - fetch funcAccess, funcList[accessKey]; - if isset accessList[accessKey] { - let haveAccess = accessList[accessKey]; - break; - } - } - } - } - } - - let this->_accessGranted = haveAccess; - if typeof eventsManager == "object" { - eventsManager->fire("acl:afterCheckAccess", this); - } - - let this->_activeKey = accessKey; - let this->_activeFunction = funcAccess; - - if haveAccess == null { - /** - * Change activeKey to most narrow if there was no access for any patterns found - */ - let this->_activeKey = roleName . "!" . resourceName . "!" . access; - - return this->_defaultAccess == Acl::ALLOW; - } - - /** - * If we have funcAccess then do all the checks for it - */ - if funcAccess !== null { - let reflectionFunction = new \ReflectionFunction(funcAccess); - let reflectionParameters = reflectionFunction->getParameters(); - let parameterNumber = count(reflectionParameters); - - // No parameters, just return haveAccess and call function without array - if parameterNumber === 0 { - return haveAccess == Acl::ALLOW && call_user_func(funcAccess); - } - - let parametersForFunction = []; - let numberOfRequiredParameters = reflectionFunction->getNumberOfRequiredParameters(); - let userParametersSizeShouldBe = parameterNumber; - - for reflectionParameter in reflectionParameters { - let reflectionClass = reflectionParameter->getClass(); - let parameterToCheck = reflectionParameter->getName(); - - if reflectionClass !== null { - // roleObject is this class - if roleObject !== null && reflectionClass->isInstance(roleObject) { - let parametersForFunction[] = roleObject; - let userParametersSizeShouldBe--; - - continue; - } - - // resourceObject is this class - if resourceObject !== null && reflectionClass->isInstance(resourceObject) { - let parametersForFunction[] = resourceObject; - let userParametersSizeShouldBe--; - - continue; - } - - // This is some user defined class, check if his parameter is instance of it - if isset parameters[parameterToCheck] && typeof parameters[parameterToCheck] == "object" && !reflectionClass->isInstance(parameters[parameterToCheck]) { - throw new Exception( - "Your passed parameter doesn't have the same class as the parameter in defined function when check " . roleName . " can " . access . " " . resourceName . ". Class passed: " . get_class(parameters[parameterToCheck])." , Class in defined function: " . reflectionClass->getName() . "." - ); - } - } - - if isset parameters[parameterToCheck] { - // We can't check type of ReflectionParameter in PHP 5.x so we just add it as it is - let parametersForFunction[] = parameters[parameterToCheck]; - } - } - - let this->_activeFunctionCustomArgumentsCount = userParametersSizeShouldBe; - - if count(parameters) > userParametersSizeShouldBe { - trigger_error( - "Number of parameters in array is higher than the number of parameters in defined function when check " . roleName . " can " . access . " " . resourceName . ". Remember that more parameters than defined in function will be ignored.", - E_USER_WARNING - ); - } - - // We dont have any parameters so check default action - if count(parametersForFunction) == 0 { - if numberOfRequiredParameters > 0 { - trigger_error( - "You didn't provide any parameters when check " . roleName . " can " . access . " " . resourceName . ". We will use default action when no arguments." - ); - - return haveAccess == Acl::ALLOW && this->_noArgumentsDefaultAction == Acl::ALLOW; - } - - // Number of required parameters == 0 so call funcAccess without any arguments - return haveAccess == Acl::ALLOW && call_user_func(funcAccess); - } - - // Check necessary parameters - if count(parametersForFunction) >= numberOfRequiredParameters { - return haveAccess == Acl::ALLOW && call_user_func_array(funcAccess, parametersForFunction); - } - - // We don't have enough parameters - throw new Exception( - "You didn't provide all necessary parameters for defined function when check " . roleName . " can " . access . " " . resourceName - ); - } - - return haveAccess == Acl::ALLOW; - } - - /** - * Sets the default access level (Phalcon\Acl::ALLOW or Phalcon\Acl::DENY) - * for no arguments provided in isAllowed action if there exists func for - * accessKey - */ - public function setNoArgumentsDefaultAction(int defaultAccess) - { - let this->_noArgumentsDefaultAction = defaultAccess; - } - - /** - * Returns the default ACL access level for no arguments provided in - * isAllowed action if there exists func for accessKey - */ - public function getNoArgumentsDefaultAction() -> int - { - return this->_noArgumentsDefaultAction; - } - - /** - * Return an array with every role registered in the list - */ - public function getRoles() -> - { - return this->_roles; - } - - /** - * Return an array with every resource registered in the list - */ - public function getResources() -> - { - return this->_resources; - } -} diff --git a/phalcon/firewall/adapter.zep b/phalcon/firewall/adapter.zep deleted file mode 100644 index a70cb66ba3e..00000000000 --- a/phalcon/firewall/adapter.zep +++ /dev/null @@ -1,244 +0,0 @@ - -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (http://www.phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - | Wojciech Ślawski | - +------------------------------------------------------------------------+ - */ - - -namespace Phalcon\Firewall; - -use Phalcon\Events\EventsAwareInterface; -use Phalcon\Events\ManagerInterface; -use Phalcon\Acl; -use Phalcon\Mvc\Dispatcher; -use Phalcon\Cache\BackendInterface; -use Phalcon\DiInterface; -use Phalcon\Acl\RoleAware; - -/** - * Phalcon\Firewall\Adapter - * - * Adapter for Phalcon\Firewall adapters - */ -abstract class Adapter implements AdapterInterface, EventsAwareInterface -{ - /** - * Events manager - * @var mixed - */ - protected _eventsManager; - - /** - * Default access - * @var int - */ - protected _defaultAccess = Acl::DENY { get, set }; - - /** - * Anonymous function for getting user identity - this function must return string, array or object implementing Phalcon\Acl\RoleAware - * @var mixed - */ - protected _roleCallback; - - /** - * Internal cache for caching access during request time - * @var mixed - */ - protected _internalCache; - - /** - * Cache for caching access - * @var \Phalcon\Cache\BackendInterface - */ - protected _cache; - - /** - * Storing active user role - */ - protected _activeRole { get }; - - /** - * Storing active identity object implementing Phalcon/Acl/RoleAware - */ - protected _activeIdentity { get }; - - /** - * Should role always be resolved using role callback or just once? - * @var bool - */ - protected _alwaysResolvingRole = false { set }; - - /** - * Sets the events manager - */ - public function setEventsManager( eventsManager) -> - { - let this->_eventsManager = eventsManager; - - return this; - } - - /** - * Returns the internal event manager - */ - public function getEventsManager() -> - { - return this->_eventsManager; - } - - /** - * Sets role callback to fetch role name - */ - public function setRoleCallback(var callback) -> - { - if !is_callable(callback){ - throw new Exception("Role callback must be function."); - } - let this->_roleCallback = callback; - - return this; - } - - /** - * Gets role callback to fetch role name - */ - public function getRoleCallback() -> <\Closure> - { - return this->_roleCallback; - } - - /** - * Gets always resolving role option - */ - public function isAlwaysResolvingRole() -> bool - { - return this->_alwaysResolvingRole; - } - - /** - * Throws an internal exception - */ - protected function _throwFirewallException(string message, int exceptionCode = 0) - { - var exception; - - let exception = new Exception(message, exceptionCode); - - if this->_handleException(exception) === false { - return false; - } - - throw exception; - } - - /** - * Handles a user exception - */ - protected function _handleException(<\Exception> exception) - { - var eventsManager; - let eventsManager = this->_eventsManager; - if typeof eventsManager == "object" { - if eventsManager->fire("firewall:beforeException", this, exception) === false { - return false; - } - } - } - - /** - * Fires event or throwing exception - */ - protected function fireEventOrThrowException(var role, string actionName, string controllerName, boolean access) - { - var eventsManager, roleName; - let eventsManager = this->_eventsManager; - if access { - if typeof eventsManager == "object" { - eventsManager->fire("firewall:afterCheck",this); - } - } else { - if typeof role == "array" { - let roleName = implode(", ",role); - } else { - let roleName = role; - } - return this->_throwFirewallException("Role name ".roleName." doesn't have access to action ".actionName." in controller ".controllerName, 403); - } - } - - /** - * Saves access in cache and internal cache - */ - protected function saveAccessInCache(string! key, boolean access) -> void - { - var cache; - - let this->_internalCache[key] = access; - - let cache = this->_cache; - - if cache != null { - cache->save("_PHF_", this->_internalCache); - } - } - - /** - * Gets access from cache - */ - protected function getAccessFromCache(string! key, array originalValues = null, string roleCacheKey = null) -> boolean|null - { - var access; - - fetch access, this->_internalCache[key]; - - return access; - } - - protected function callRoleCallback( dependencyInjector) -> void - { - var roleCallback, identity; - - let roleCallback = this->_roleCallback; - - let identity = {roleCallback}(dependencyInjector); - - if empty identity { - throw new Exception("Function defined as roleCallback must return something."); - } - - if typeof identity == "object" { - if !(identity instanceof RoleAware) { - throw new Exception("Role passed as object must implement 'Phalcon\\Acl\\RoleAware'"); - } - let this->_activeIdentity = identity; - let this->_activeRole = identity->getRoleName(); - } else { - let this->_activeRole = identity; - } - } - - public function setCache( cache) -> - { - let this->_cache = cache; - - if this->_internalCache === null { - let this->_internalCache = cache->get("_PHF_"); - } - - return this; - } -} diff --git a/phalcon/firewall/adapterinterface.zep b/phalcon/firewall/adapterinterface.zep deleted file mode 100644 index 9d3fa761dd8..00000000000 --- a/phalcon/firewall/adapterinterface.zep +++ /dev/null @@ -1,67 +0,0 @@ - -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (http://www.phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - | Wojciech Ślawski | - +------------------------------------------------------------------------+ - */ - -namespace Phalcon\Firewall; - -use Phalcon\Mvc\DispatcherInterface; -use Phalcon\Cache\BackendInterface; - -/** - * Phalcon\Mvc\Dispatcher\Firewall\AdapterInterface - * - * Interface for Phalcon\Mvc\Dispatcher\Firewall adapters - */ -interface AdapterInterface -{ - /** - * Sets the default access level (Phalcon\Acl::ALLOW or Phalcon\Acl::DENY) - */ - public function setDefaultAccess(int defaultAccess) -> ; - - /** - * Returns the default ACL access level - */ - public function getDefaultAccess() -> int; - - /** - * Sets role callback to fetch role name - */ - public function setRoleCallback(var callback) -> ; - - /** - * Gets role callback to fetch role name - */ - public function getRoleCallback(); - - /** - * Gets always resolving role option - */ - public function isAlwaysResolvingRole() -> bool; - - /** - * Sets always resolving role option - */ - public function setAlwaysResolvingRole(bool alwaysResolvingRole) -> ; - - /** - * Sets cache backend - */ - public function setCache( cache) -> ; -} diff --git a/phalcon/firewall/exception.zep b/phalcon/firewall/exception.zep deleted file mode 100644 index b872a560bf1..00000000000 --- a/phalcon/firewall/exception.zep +++ /dev/null @@ -1,29 +0,0 @@ - -/* - +------------------------------------------------------------------------+ - | Phalcon Framework | - +------------------------------------------------------------------------+ - | Copyright (c) 2011-2016 Phalcon Team (https://phalconphp.com) | - +------------------------------------------------------------------------+ - | This source file is subject to the New BSD License that is bundled | - | with this package in the file docs/LICENSE.txt. | - | | - | If you did not receive a copy of the license and are unable to | - | obtain it through the world-wide-web, please send an email | - | to license@phalconphp.com so we can send you a copy immediately. | - +------------------------------------------------------------------------+ - | Authors: Andres Gutierrez | - | Eduar Carvajal | - +------------------------------------------------------------------------+ - */ - -namespace Phalcon\Firewall; - -/** - * Phalcon\Firewall\Exception - * - * Exceptions thrown in Phalcon\Firewall will use this class - */ -class Exception extends \Phalcon\Exception -{ -}