mirror of
https://github.com/brmlab/brmbiolab_sklad.git
synced 2025-06-09 05:34:01 +02:00
Initial commit
This commit is contained in:
commit
3b93da31de
1004 changed files with 265840 additions and 0 deletions
73
lib/Cake/Controller/Component/Acl/AclInterface.php
Normal file
73
lib/Cake/Controller/Component/Acl/AclInterface.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Access Control List interface.
|
||||
* Implementing classes are used by AclComponent to perform ACL checks in Cake.
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
interface AclInterface {
|
||||
|
||||
/**
|
||||
* Empty method to be overridden in subclasses
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Allow methods are used to grant an ARO access to an ACO.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Deny methods are used to remove permission from an ARO to access an ACO.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Inherit methods modify the permission for an ARO to be that of its parent object.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Initialization method for the Acl implementation
|
||||
*
|
||||
* @param Component $component The AclComponent instance.
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $component);
|
||||
|
||||
}
|
163
lib/Cake/Controller/Component/Acl/DbAcl.php
Normal file
163
lib/Cake/Controller/Component/Acl/DbAcl.php
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AclInterface', 'Controller/Component/Acl');
|
||||
App::uses('Hash', 'Utility');
|
||||
App::uses('ClassRegistry', 'Utility');
|
||||
|
||||
/**
|
||||
* DbAcl implements an ACL control system in the database. ARO's and ACO's are
|
||||
* structured into trees and a linking table is used to define permissions. You
|
||||
* can install the schema for DbAcl with the Schema Shell.
|
||||
*
|
||||
* `$aco` and `$aro` parameters can be slash delimited paths to tree nodes.
|
||||
*
|
||||
* eg. `controllers/Users/edit`
|
||||
*
|
||||
* Would point to a tree structure like
|
||||
*
|
||||
* {{{
|
||||
* controllers
|
||||
* Users
|
||||
* edit
|
||||
* }}}
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
class DbAcl extends Object implements AclInterface {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->Permission = ClassRegistry::init(array('class' => 'Permission', 'alias' => 'Permission'));
|
||||
$this->Aro = $this->Permission->Aro;
|
||||
$this->Aco = $this->Permission->Aco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the containing component and sets the Aro/Aco objects to it.
|
||||
*
|
||||
* @param AclComponent $component The AclComponent instance.
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $component) {
|
||||
$component->Aro = $this->Aro;
|
||||
$component->Aco = $this->Aco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given $aro has access to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success (true if ARO has access to action in ACO, false otherwise)
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#checking-permissions-the-acl-component
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*") {
|
||||
return $this->Permission->check($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow $aro to have access to action $actions in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @param int $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
|
||||
*/
|
||||
public function allow($aro, $aco, $actions = "*", $value = 1) {
|
||||
return $this->Permission->allow($aro, $aco, $actions, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for $aro to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Let access for $aro to action $action in $aco be inherited
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow $aro to have access to action $actions in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @see allow()
|
||||
*/
|
||||
public function grant($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for $aro to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @see deny()
|
||||
*/
|
||||
public function revoke($aro, $aco, $action = "*") {
|
||||
return $this->deny($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of access-control links between the given Aro and Aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @return array Indexed array with: 'aro', 'aco' and 'link'
|
||||
*/
|
||||
public function getAclLink($aro, $aco) {
|
||||
return $this->Permission->getAclLink($aro, $aco);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys used in an ACO
|
||||
*
|
||||
* @param array $keys Permission model info
|
||||
* @return array ACO keys
|
||||
*/
|
||||
protected function _getAcoKeys($keys) {
|
||||
return $this->Permission->getAcoKeys($keys);
|
||||
}
|
||||
|
||||
}
|
174
lib/Cake/Controller/Component/Acl/IniAcl.php
Normal file
174
lib/Cake/Controller/Component/Acl/IniAcl.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AclInterface', 'Controller/Component/Acl');
|
||||
|
||||
/**
|
||||
* IniAcl implements an access control system using an INI file. An example
|
||||
* of the ini file used can be found in /config/acl.ini.php.
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
class IniAcl extends Object implements AclInterface {
|
||||
|
||||
/**
|
||||
* Array with configuration, parsed from ini file
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $config = null;
|
||||
|
||||
/**
|
||||
* The Hash::extract() path to the user/aro identifier in the
|
||||
* acl.ini file. This path will be used to extract the string
|
||||
* representation of a user used in the ini file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $userPath = 'User.username';
|
||||
|
||||
/**
|
||||
* Initialize method
|
||||
*
|
||||
* @param Component $component The AclComponent instance.
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $component) {
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, allow cannot be done with IniAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, deny cannot be done with IniAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, inherit cannot be done with IniAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main ACL check function. Checks to see if the ARO (access request object) has access to the
|
||||
* ACO (access control object).Looks at the acl.ini.php file for permissions
|
||||
* (see instructions in /config/acl.ini.php).
|
||||
*
|
||||
* @param string $aro ARO
|
||||
* @param string $aco ACO
|
||||
* @param string $action Action
|
||||
* @return bool Success
|
||||
*/
|
||||
public function check($aro, $aco, $action = null) {
|
||||
if (!$this->config) {
|
||||
$this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php');
|
||||
}
|
||||
$aclConfig = $this->config;
|
||||
|
||||
if (is_array($aro)) {
|
||||
$aro = Hash::get($aro, $this->userPath);
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['deny'])) {
|
||||
$userDenies = $this->arrayTrim(explode(",", $aclConfig[$aro]['deny']));
|
||||
|
||||
if (array_search($aco, $userDenies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['allow'])) {
|
||||
$userAllows = $this->arrayTrim(explode(",", $aclConfig[$aro]['allow']));
|
||||
|
||||
if (array_search($aco, $userAllows)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['groups'])) {
|
||||
$userGroups = $this->arrayTrim(explode(",", $aclConfig[$aro]['groups']));
|
||||
|
||||
foreach ($userGroups as $group) {
|
||||
if (array_key_exists($group, $aclConfig)) {
|
||||
if (isset($aclConfig[$group]['deny'])) {
|
||||
$groupDenies = $this->arrayTrim(explode(",", $aclConfig[$group]['deny']));
|
||||
|
||||
if (array_search($aco, $groupDenies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$group]['allow'])) {
|
||||
$groupAllows = $this->arrayTrim(explode(",", $aclConfig[$group]['allow']));
|
||||
|
||||
if (array_search($aco, $groupAllows)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an INI file and returns an array that reflects the
|
||||
* INI file's section structure. Double-quote friendly.
|
||||
*
|
||||
* @param string $filename File
|
||||
* @return array INI section structure
|
||||
*/
|
||||
public function readConfigFile($filename) {
|
||||
App::uses('IniReader', 'Configure');
|
||||
$iniFile = new IniReader(dirname($filename) . DS);
|
||||
return $iniFile->read(basename($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes trailing spaces on all array elements (to prepare for searching)
|
||||
*
|
||||
* @param array $array Array to trim
|
||||
* @return array Trimmed array
|
||||
*/
|
||||
public function arrayTrim($array) {
|
||||
foreach ($array as $key => $value) {
|
||||
$array[$key] = trim($value);
|
||||
}
|
||||
array_unshift($array, "");
|
||||
return $array;
|
||||
}
|
||||
|
||||
}
|
563
lib/Cake/Controller/Component/Acl/PhpAcl.php
Normal file
563
lib/Cake/Controller/Component/Acl/PhpAcl.php
Normal file
|
@ -0,0 +1,563 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP configuration based AclInterface implementation
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 2.1
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* PhpAcl implements an access control system using a plain PHP configuration file.
|
||||
* An example file can be found in app/Config/acl.php
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
class PhpAcl extends Object implements AclInterface {
|
||||
|
||||
/**
|
||||
* Constant for deny
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
const DENY = false;
|
||||
|
||||
/**
|
||||
* Constant for allow
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
const ALLOW = true;
|
||||
|
||||
/**
|
||||
* Options:
|
||||
* - policy: determines behavior of the check method. Deny policy needs explicit allow rules, allow policy needs explicit deny rules
|
||||
* - config: absolute path to config file that contains the acl rules (@see app/Config/acl.php)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $options = array();
|
||||
|
||||
/**
|
||||
* Aro Object
|
||||
*
|
||||
* @var PhpAro
|
||||
*/
|
||||
public $Aro = null;
|
||||
|
||||
/**
|
||||
* Aco Object
|
||||
*
|
||||
* @var PhpAco
|
||||
*/
|
||||
public $Aco = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Sets a few default settings up.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->options = array(
|
||||
'policy' => self::DENY,
|
||||
'config' => APP . 'Config' . DS . 'acl.php',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize method
|
||||
*
|
||||
* @param AclComponent $Component Component instance
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $Component) {
|
||||
if (!empty($Component->settings['adapter'])) {
|
||||
$this->options = $Component->settings['adapter'] + $this->options;
|
||||
}
|
||||
|
||||
App::uses('PhpReader', 'Configure');
|
||||
$Reader = new PhpReader(dirname($this->options['config']) . DS);
|
||||
$config = $Reader->read(basename($this->options['config']));
|
||||
$this->build($config);
|
||||
$Component->Aco = $this->Aco;
|
||||
$Component->Aro = $this->Aro;
|
||||
}
|
||||
|
||||
/**
|
||||
* build and setup internal ACL representation
|
||||
*
|
||||
* @param array $config configuration array, see docs
|
||||
* @return void
|
||||
* @throws AclException When required keys are missing.
|
||||
*/
|
||||
public function build(array $config) {
|
||||
if (empty($config['roles'])) {
|
||||
throw new AclException(__d('cake_dev', '"roles" section not found in configuration.'));
|
||||
}
|
||||
|
||||
if (empty($config['rules']['allow']) && empty($config['rules']['deny'])) {
|
||||
throw new AclException(__d('cake_dev', 'Neither "allow" nor "deny" rules were provided in configuration.'));
|
||||
}
|
||||
|
||||
$rules['allow'] = !empty($config['rules']['allow']) ? $config['rules']['allow'] : array();
|
||||
$rules['deny'] = !empty($config['rules']['deny']) ? $config['rules']['deny'] : array();
|
||||
$roles = !empty($config['roles']) ? $config['roles'] : array();
|
||||
$map = !empty($config['map']) ? $config['map'] : array();
|
||||
$alias = !empty($config['alias']) ? $config['alias'] : array();
|
||||
|
||||
$this->Aro = new PhpAro($roles, $map, $alias);
|
||||
$this->Aco = new PhpAco($rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, allow cannot be done with PhpAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*") {
|
||||
return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'allow');
|
||||
}
|
||||
|
||||
/**
|
||||
* deny ARO access to ACO
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'deny');
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main ACL check function. Checks to see if the ARO (access request object) has access to the
|
||||
* ACO (access control object).
|
||||
*
|
||||
* @param string $aro ARO
|
||||
* @param string $aco ACO
|
||||
* @param string $action Action
|
||||
* @return bool true if access is granted, false otherwise
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*") {
|
||||
$allow = $this->options['policy'];
|
||||
$prioritizedAros = $this->Aro->roles($aro);
|
||||
|
||||
if ($action && $action !== "*") {
|
||||
$aco .= '/' . $action;
|
||||
}
|
||||
|
||||
$path = $this->Aco->path($aco);
|
||||
|
||||
if (empty($path)) {
|
||||
return $allow;
|
||||
}
|
||||
|
||||
foreach ($path as $node) {
|
||||
foreach ($prioritizedAros as $aros) {
|
||||
if (!empty($node['allow'])) {
|
||||
$allow = $allow || count(array_intersect($node['allow'], $aros));
|
||||
}
|
||||
|
||||
if (!empty($node['deny'])) {
|
||||
$allow = $allow && !count(array_intersect($node['deny'], $aros));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $allow;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Control Object
|
||||
*
|
||||
*/
|
||||
class PhpAco {
|
||||
|
||||
/**
|
||||
* holds internal ACO representation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_tree = array();
|
||||
|
||||
/**
|
||||
* map modifiers for ACO paths to their respective PCRE pattern
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modifiers = array(
|
||||
'*' => '.*',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $rules Rules array
|
||||
*/
|
||||
public function __construct(array $rules = array()) {
|
||||
foreach (array('allow', 'deny') as $type) {
|
||||
if (empty($rules[$type])) {
|
||||
$rules[$type] = array();
|
||||
}
|
||||
}
|
||||
|
||||
$this->build($rules['allow'], $rules['deny']);
|
||||
}
|
||||
|
||||
/**
|
||||
* return path to the requested ACO with allow and deny rules attached on each level
|
||||
*
|
||||
* @param string $aco ACO string
|
||||
* @return array
|
||||
*/
|
||||
public function path($aco) {
|
||||
$aco = $this->resolve($aco);
|
||||
$path = array();
|
||||
$level = 0;
|
||||
$root = $this->_tree;
|
||||
$stack = array(array($root, 0));
|
||||
|
||||
while (!empty($stack)) {
|
||||
list($root, $level) = array_pop($stack);
|
||||
|
||||
if (empty($path[$level])) {
|
||||
$path[$level] = array();
|
||||
}
|
||||
|
||||
foreach ($root as $node => $elements) {
|
||||
$pattern = '/^' . str_replace(array_keys(self::$modifiers), array_values(self::$modifiers), $node) . '$/';
|
||||
|
||||
if ($node == $aco[$level] || preg_match($pattern, $aco[$level])) {
|
||||
// merge allow/denies with $path of current level
|
||||
foreach (array('allow', 'deny') as $policy) {
|
||||
if (!empty($elements[$policy])) {
|
||||
if (empty($path[$level][$policy])) {
|
||||
$path[$level][$policy] = array();
|
||||
}
|
||||
$path[$level][$policy] = array_merge($path[$level][$policy], $elements[$policy]);
|
||||
}
|
||||
}
|
||||
|
||||
// traverse
|
||||
if (!empty($elements['children']) && isset($aco[$level + 1])) {
|
||||
array_push($stack, array($elements['children'], $level + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* allow/deny ARO access to ARO
|
||||
*
|
||||
* @param string $aro ARO string
|
||||
* @param string $aco ACO string
|
||||
* @param string $action Action string
|
||||
* @param string $type access type
|
||||
* @return void
|
||||
*/
|
||||
public function access($aro, $aco, $action, $type = 'deny') {
|
||||
$aco = $this->resolve($aco);
|
||||
$depth = count($aco);
|
||||
$root = $this->_tree;
|
||||
$tree = &$root;
|
||||
|
||||
foreach ($aco as $i => $node) {
|
||||
if (!isset($tree[$node])) {
|
||||
$tree[$node] = array(
|
||||
'children' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
if ($i < $depth - 1) {
|
||||
$tree = &$tree[$node]['children'];
|
||||
} else {
|
||||
if (empty($tree[$node][$type])) {
|
||||
$tree[$node][$type] = array();
|
||||
}
|
||||
|
||||
$tree[$node][$type] = array_merge(is_array($aro) ? $aro : array($aro), $tree[$node][$type]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_tree = &$root;
|
||||
}
|
||||
|
||||
/**
|
||||
* resolve given ACO string to a path
|
||||
*
|
||||
* @param string $aco ACO string
|
||||
* @return array path
|
||||
*/
|
||||
public function resolve($aco) {
|
||||
if (is_array($aco)) {
|
||||
return array_map('strtolower', $aco);
|
||||
}
|
||||
|
||||
// strip multiple occurrences of '/'
|
||||
$aco = preg_replace('#/+#', '/', $aco);
|
||||
// make case insensitive
|
||||
$aco = ltrim(strtolower($aco), '/');
|
||||
return array_filter(array_map('trim', explode('/', $aco)));
|
||||
}
|
||||
|
||||
/**
|
||||
* build a tree representation from the given allow/deny informations for ACO paths
|
||||
*
|
||||
* @param array $allow ACO allow rules
|
||||
* @param array $deny ACO deny rules
|
||||
* @return void
|
||||
*/
|
||||
public function build(array $allow, array $deny = array()) {
|
||||
$this->_tree = array();
|
||||
|
||||
foreach ($allow as $dotPath => $aros) {
|
||||
if (is_string($aros)) {
|
||||
$aros = array_map('trim', explode(',', $aros));
|
||||
}
|
||||
|
||||
$this->access($aros, $dotPath, null, 'allow');
|
||||
}
|
||||
|
||||
foreach ($deny as $dotPath => $aros) {
|
||||
if (is_string($aros)) {
|
||||
$aros = array_map('trim', explode(',', $aros));
|
||||
}
|
||||
|
||||
$this->access($aros, $dotPath, null, 'deny');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Request Object
|
||||
*
|
||||
*/
|
||||
class PhpAro {
|
||||
|
||||
/**
|
||||
* role to resolve to when a provided ARO is not listed in
|
||||
* the internal tree
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_ROLE = 'Role/default';
|
||||
|
||||
/**
|
||||
* map external identifiers. E.g. if
|
||||
*
|
||||
* array('User' => array('username' => 'jeff', 'role' => 'editor'))
|
||||
*
|
||||
* is passed as an ARO to one of the methods of AclComponent, PhpAcl
|
||||
* will check if it can be resolved to an User or a Role defined in the
|
||||
* configuration file.
|
||||
*
|
||||
* @var array
|
||||
* @see app/Config/acl.php
|
||||
*/
|
||||
public $map = array(
|
||||
'User' => 'User/username',
|
||||
'Role' => 'User/role',
|
||||
);
|
||||
|
||||
/**
|
||||
* aliases to map
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $aliases = array();
|
||||
|
||||
/**
|
||||
* internal ARO representation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_tree = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $aro The aro data
|
||||
* @param array $map The identifier mappings
|
||||
* @param array $aliases The aliases to map.
|
||||
*/
|
||||
public function __construct(array $aro = array(), array $map = array(), array $aliases = array()) {
|
||||
if (!empty($map)) {
|
||||
$this->map = $map;
|
||||
}
|
||||
|
||||
$this->aliases = $aliases;
|
||||
$this->build($aro);
|
||||
}
|
||||
|
||||
/**
|
||||
* From the perspective of the given ARO, walk down the tree and
|
||||
* collect all inherited AROs levelwise such that AROs from different
|
||||
* branches with equal distance to the requested ARO will be collected at the same
|
||||
* index. The resulting array will contain a prioritized list of (list of) roles ordered from
|
||||
* the most distant AROs to the requested one itself.
|
||||
*
|
||||
* @param string|array $aro An ARO identifier
|
||||
* @return array prioritized AROs
|
||||
*/
|
||||
public function roles($aro) {
|
||||
$aros = array();
|
||||
$aro = $this->resolve($aro);
|
||||
$stack = array(array($aro, 0));
|
||||
|
||||
while (!empty($stack)) {
|
||||
list($element, $depth) = array_pop($stack);
|
||||
$aros[$depth][] = $element;
|
||||
|
||||
foreach ($this->_tree as $node => $children) {
|
||||
if (in_array($element, $children)) {
|
||||
array_push($stack, array($node, $depth + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($aros);
|
||||
}
|
||||
|
||||
/**
|
||||
* resolve an ARO identifier to an internal ARO string using
|
||||
* the internal mapping information.
|
||||
*
|
||||
* @param string|array $aro ARO identifier (User.jeff, array('User' => ...), etc)
|
||||
* @return string internal aro string (e.g. User/jeff, Role/default)
|
||||
*/
|
||||
public function resolve($aro) {
|
||||
foreach ($this->map as $aroGroup => $map) {
|
||||
list ($model, $field) = explode('/', $map, 2);
|
||||
$mapped = '';
|
||||
|
||||
if (is_array($aro)) {
|
||||
if (isset($aro['model']) && isset($aro['foreign_key']) && $aro['model'] === $aroGroup) {
|
||||
$mapped = $aroGroup . '/' . $aro['foreign_key'];
|
||||
} elseif (isset($aro[$model][$field])) {
|
||||
$mapped = $aroGroup . '/' . $aro[$model][$field];
|
||||
} elseif (isset($aro[$field])) {
|
||||
$mapped = $aroGroup . '/' . $aro[$field];
|
||||
}
|
||||
} elseif (is_string($aro)) {
|
||||
$aro = ltrim($aro, '/');
|
||||
|
||||
if (strpos($aro, '/') === false) {
|
||||
$mapped = $aroGroup . '/' . $aro;
|
||||
} else {
|
||||
list($aroModel, $aroValue) = explode('/', $aro, 2);
|
||||
|
||||
$aroModel = Inflector::camelize($aroModel);
|
||||
|
||||
if ($aroModel === $model || $aroModel === $aroGroup) {
|
||||
$mapped = $aroGroup . '/' . $aroValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->_tree[$mapped])) {
|
||||
return $mapped;
|
||||
}
|
||||
|
||||
// is there a matching alias defined (e.g. Role/1 => Role/admin)?
|
||||
if (!empty($this->aliases[$mapped])) {
|
||||
return $this->aliases[$mapped];
|
||||
}
|
||||
}
|
||||
return self::DEFAULT_ROLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a new ARO to the tree
|
||||
*
|
||||
* @param array $aro one or more ARO records
|
||||
* @return void
|
||||
*/
|
||||
public function addRole(array $aro) {
|
||||
foreach ($aro as $role => $inheritedRoles) {
|
||||
if (!isset($this->_tree[$role])) {
|
||||
$this->_tree[$role] = array();
|
||||
}
|
||||
|
||||
if (!empty($inheritedRoles)) {
|
||||
if (is_string($inheritedRoles)) {
|
||||
$inheritedRoles = array_map('trim', explode(',', $inheritedRoles));
|
||||
}
|
||||
|
||||
foreach ($inheritedRoles as $dependency) {
|
||||
// detect cycles
|
||||
$roles = $this->roles($dependency);
|
||||
|
||||
if (in_array($role, Hash::flatten($roles))) {
|
||||
$path = '';
|
||||
|
||||
foreach ($roles as $roleDependencies) {
|
||||
$path .= implode('|', (array)$roleDependencies) . ' -> ';
|
||||
}
|
||||
|
||||
trigger_error(__d('cake_dev', 'cycle detected when inheriting %s from %s. Path: %s', $role, $dependency, $path . $role));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($this->_tree[$dependency])) {
|
||||
$this->_tree[$dependency] = array();
|
||||
}
|
||||
|
||||
$this->_tree[$dependency][] = $role;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds one or more aliases to the internal map. Overwrites existing entries.
|
||||
*
|
||||
* @param array $alias alias from => to (e.g. Role/13 -> Role/editor)
|
||||
* @return void
|
||||
*/
|
||||
public function addAlias(array $alias) {
|
||||
$this->aliases = $alias + $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* build an ARO tree structure for internal processing
|
||||
*
|
||||
* @param array $aros array of AROs as key and their inherited AROs as values
|
||||
* @return void
|
||||
*/
|
||||
public function build(array $aros) {
|
||||
$this->_tree = array();
|
||||
$this->addRole($aros);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue