Archived
1
0
Fork 0

Improve ACL handling.

This commit is contained in:
Henrik Hautakoski 2018-09-30 23:47:43 +02:00
parent bcd50a8453
commit 80a8cdca3f
No known key found for this signature in database
GPG key ID: 839F3A7EAFAEAFAA
2 changed files with 87 additions and 47 deletions

View file

@ -2,50 +2,93 @@
namespace Httpcb;
use Phalcon\Acl\Role,
Phalcon\Acl\Adapter\Memory as AclList;
use Phalcon\Config,
Phalcon\Acl\Role,
Phalcon\Acl\Adapter\Memory as Adapter;
class Acl extends AclList
class Acl
{
const ROLE_USER = 'user';
const ROLE_GUEST = 'guest';
public function __construct()
/**
* @var Adapter
*/
protected $_adapter = null;
public function __construct(Config $config)
{
$this->_adapter = new Adapter();
// Deny access to everything by default.
$this->setDefaultAction(\Phalcon\Acl::DENY);
$this->_adapter->setDefaultAction(\Phalcon\Acl::DENY);
// Roles
$guest = new Role(self::ROLE_GUEST);
$user = new Role(self::ROLE_USER);
$this->addRole($guest);
$this->addRole($user, $guest);
// Public Resources
$public = array(
'index',
'error',
'auth',
'api',
);
$this->_grant($guest, $public);
// Protected Resources
$protected = array(
'callback',
'user',
);
$this->_grant($user, $protected);
$this->fromConfig($config);
}
protected function _grant(Role $role, array $resources)
/**
* @param $role
* @param $resource
* @return bool
*/
public function isAllowed($role, $resource)
{
foreach($resources as $resource) {
$this->addResource($resource, 'Read');
$this->allow($role->getName(), $resource, 'Read');
return $this->_adapter->isAllowed($role, $resource, 'All') == \Phalcon\Acl::ALLOW;
}
/**
* @param string $resource
* @return bool
*/
public function hasResource($resource)
{
return $this->_adapter->isResource($resource);
}
public function fromConfig(Config $config)
{
// Add roles.
foreach($config->roles as $name => $def) {
$inherits = null;
$description = null;
if ($def instanceof Config) {
$inherits = $def->get('inherits');
$description = $def->get('description');
}
$role = new Role($name, $description);
$this->_adapter->addRole($role, $inherits);
}
// Zones
foreach($config->zones as $name => $resources) {
if (!($resources instanceof Config)) {
$resources = new Config([ $resources ]);
}
foreach($resources as $resource) {
$this->_adapter->addResource($resource, 'All');
}
}
// Grant access for roles and resources.
foreach($config->roles as $name => $def) {
$zones = $def->get('allowed-zones', []);
if (is_string($zones)) {
$zones = [ $zones ];
}
foreach($zones as $zone) {
foreach($config->zones->get($zone) as $resource) {
$this->_adapter->allow($name, $resource, 'All');
}
}
}
}
}

View file

@ -10,6 +10,11 @@ use Httpcb\Acl;
class AclListener extends Plugin
{
protected $_ignored_resources = [
'index',
'error'
];
public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher) : bool
{
// We only have two roles for now, authenticated users and guests.
@ -19,24 +24,17 @@ class AclListener extends Plugin
$role = Acl::ROLE_GUEST;
}
// Support annotations for actions to define custom resources.
$controllerClass = $dispatcher->getControllerClass();
$activeMethod = $dispatcher->getActiveMethod();
// Get the resource from controller name.
$resource = $dispatcher->getControllerName();
$annotation = $this->annotations->getMethod($controllerClass, $activeMethod);
// ACL annotation found. use that.
if ($annotation->has('Acl')) {
$resource = $annotation->get('Acl')->getArgument('resource');
}
// Otherwise, default to controller name.
else {
$resource = $dispatcher->getControllerName();
// Ignore checks for error resource.
if (in_array($resource, $this->_ignored_resources)) {
return true;
}
// Now, check and redirect user to login page if
// this role does not have access to this resource.
if ($this->acl->isAllowed($role, $resource, 'Read') == \Phalcon\Acl::DENY) {
if ($this->acl->isAllowed($role, $resource) === false) {
// Forward to login page.
$dispatcher->forward(array(
@ -47,7 +45,6 @@ class AclListener extends Plugin
// Return false to stop the dispatch loop.
return false;
}
return true;
}
}