Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/croogo/croogo/Acl/src/Auth/AclCachedAuthorize.php
<?php

namespace Croogo\Acl\Auth;

use
Acl\Auth\BaseAuthorize;
use
Cake\Cache\Cache;
use
Cake\Controller\ComponentRegistry;
use
Cake\Core\Configure;
use
Cake\Core\Exception\Exception;
use
Cake\Http\ServerRequest;
use
Cake\Log\Log;
use
Cake\Network\Request;
use
Cake\ORM\TableRegistry;
use
Cake\Utility\Inflector;

/**
 * An authentication adapter for AuthComponent. Provides similar functionality
 * to ActionsAuthorize class from CakePHP core _with_ caching capability.
 *
 * @package  Croogo.Acl.Controller.Component.Auth
 * @since    1.5
 * @author   Rachman Chavik <rchavik@xintesa.com>
 * @see      RowLevelAclComponent
 * @license  http://www.opensource.org/licenses/mit-license.php The MIT License
 * @link     http://www.croogo.org
 */
class AclCachedAuthorize extends BaseAuthorize
{

    protected
$_defaultConfig = [
       
'actionMap' => [
           
'toggle' => 'update',
           
'moveup' => 'update',
           
'movedown' => 'update',
           
'process' => 'delete',
           
'index' => 'read',
           
'add' => 'create',
           
'edit' => 'update',
           
'view' => 'read',
           
'remove' => 'delete',
           
'create' => 'create',
           
'read' => 'read',
           
'update' => 'update',
           
'delete' => 'delete',
        ],
    ];

   
/**
     * Constructor
     */
   
public function __construct(ComponentRegistry $registry, $config = [])
    {
       
parent::__construct($registry, $config);
    }

   
/**
     * Checks whether $user is an administrator
     *
     * @param bool True if user has administrative role
     */
   
protected function _isAdmin($user)
    {
        static
$Role = null;
        if (empty(
$user['role_id'])) {
            return
false;
        }
        if (empty(
$this->_adminRole)) {
            if (empty(
$Role)) {
               
$Role = TableRegistry::get('Croogo/Users.Roles');
               
$Role->addBehavior('Croogo/Core.Aliasable');
            }
           
$this->_adminRole = $Role->byAlias('superadmin');
        }

        return
$user['role_id'] == $this->_adminRole;
    }

   
/**
     * Get the action path for a given request.
     *
     * @see BaseAuthorize::action()
     */
   
public function action(ServerRequest $request, $path = '/:plugin/:prefix/:controller/:action')
    {
       
$apiPath = Configure::read('Croogo.Api.path');
        if (!
$request->is('api')) {
            return
parent::action($request, $path);
        }

       
$api = isset($request['api']) ? $apiPath : null;
        if (isset(
$request['prefix'])) {
           
$prefix = $request['prefix'];
           
$action = str_replace($request['prefix'] . '_', '', $request['action']);
        } else {
           
$prefix = null;
           
$action = $request['action'];
        }
       
$plugin = empty($request['plugin']) ? null : str_replace('/', '\\', Inflector::camelize($request['plugin']));
       
$controller = Inflector::camelize($request['controller']);

       
$path = str_replace(
            [
$apiPath, ':prefix', ':plugin', ':controller', ':action'],
            [
$api, $prefix, $plugin, $controller, $action],
           
$this->getConfig('actionPath') . $path
       
);
       
$path = str_replace('//', '/', $path);

        return
trim($path, '/');
    }

   
/**
     * check request request authorization
     *
     */
   
public function authorize($user, ServerRequest $request)
    {
       
// Admin role is allowed to perform all actions, bypassing ACL
       
if ($this->_isAdmin($user)) {
            return
true;
        }

       
$allowed = false;
       
$Acl = $this->_registry->load('Acl');
        list(
$plugin, $userModel) = pluginSplit($this->getConfig('userModel'));

       
$action = $this->action($request);

       
$cacheName = 'permissions_' . (string)$user['id'];
        if ((
$permissions = Cache::read($cacheName, 'permissions')) === false) {
           
$permissions = [];
           
Cache::write($cacheName, $permissions, 'permissions');
        }

        if (!isset(
$permissions[$action])) {
           
$userTable = TableRegistry::getTableLocator()->get($this->getConfig('userModel'));
           
$user = $userTable->get($user['id']);
           
$allowed = $Acl->check($user, $action);
           
$permissions[$action] = $allowed;
           
Cache::write($cacheName, $permissions, 'permissions');
           
$hit = false;
        } else {
           
$allowed = $permissions[$action];
           
$hit = true;
        }

        if (
Configure::read('debug')) {
           
$status = $allowed ? ' allowed.' : ' denied.';
           
$cached = $hit ? ' (cache hit)' : ' (cache miss)';
           
Log::write(LOG_ERR, $user['username'] . ' - ' . $action . $status . $cached);
        }

        if (!
$allowed) {
            return
false;
        }

        if (!
Configure::read('Access Control.rowLevel')) {
            return
$allowed;
        }

       
// bail out when controller's primary model does not want row level acl
       
$controller = $this->_registry->getController();
       
$model = $controller->name;
       
$Model = $controller->{$model};
        if (
$Model && !$Model->behaviors()->has('RowLevelAcl')) {
            return
$allowed;
        }

       
$primaryKey = $Model->primaryKey();
       
$ids = [];
        if (
$request->is('get') && $request->getParam('pass.0')) {
           
// collect id from actions such as: Nodes/admin_edit/1
           
$ids[] = $request->getParam('pass.0');
        } elseif (
$request->is('post') || $request->is('put')) {
           
$action = $request->getData('action');
            if (
$action) {
               
// collect ids from 'bulk' processing action
               
foreach ($request->getData($model) as $id => $flag) {
                    if (isset(
$flag[$primaryKey]) && $flag[$primaryKey] == 1) {
                       
$ids[] = $id;
                    }
                }
            }

           
$id = $request->param('pass.0');
            if (
$id) {
               
$ids[] = $id;
            }
        }

        foreach (
$ids as $id) {
            if (
is_numeric($id)) {
                try {
                   
$allowed = $this->_authorizeByContent($user, $request, $id);
                } catch (\
Exception $e) {
                   
$allowed = false;
                }
            } else {
                continue;
            }
            if (!
$allowed) {
                break;
            }
        }

        return
$allowed;
    }

   
/**
     * Checks authorization by content
     *
     * @throws Exception
     */
   
protected function _authorizeByContent($user, ServerRequest $request, $id)
    {
        if (!isset(
$this->getConfig('actionMap')[$request->params['action']])) {
           
$message = __d(
               
'croogo',
               
'_authorizeByContent() - Access of un-mapped action "%1$s" in controller "%2$s"',
               
$request->action,
               
$request->controller
           
);
           
Log::critical($message);
            throw new
Exception($message);
        }

        list(
$plugin, $userModel) = pluginSplit($this->getConfig('userModel'));
       
$acoNode = [
           
'model' => $this->_registry->getController()->name,
           
'foreign_key' => $id,
        ];
       
$alias = sprintf('%s.%s', $acoNode['model'], $acoNode['foreign_key']);
       
$action = $this->getConfig('actionMap')[$request->param('action')];

       
$cacheName = 'permissions_content_' . strval($user['id']);
        if ((
$permissions = Cache::read($cacheName, 'permissions')) === false) {
           
$permissions = [];
           
Cache::write($cacheName, $permissions, 'permissions');
        }

        if (!isset(
$permissions[$alias][$action])) {
           
$Acl = $this->_registry->load('Acl');
            try {
               
$allowed = $Acl->check([$userModel => $user], $acoNode, $action);
            } catch (\
Exception $e) {
               
Log::warning('authorizeByContent: ' . $e->getMessage());
               
$allowed = false;
            }
           
$permissions[$alias][$action] = $allowed;
           
Cache::write($cacheName, $permissions, 'permissions');
           
$hit = false;
        } else {
           
$allowed = $permissions[$alias][$action];
           
$hit = true;
        }

        if (
Configure::read('debug')) {
           
$status = $allowed ? ' allowed.' : ' denied.';
           
$cached = $hit ? ' (cache hit)' : ' (cache miss)';
           
Log::write(LOG_ERR, $user['username'] . ' - ' . $action . '/' . $id . $status . $cached);
        }

        return
$allowed;
    }
}