Permission.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. /**
  3. *
  4. * PHP 5
  5. *
  6. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  7. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  8. *
  9. * Licensed under The MIT License
  10. * For full copyright and license information, please see the LICENSE.txt
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @since CakePHP(tm) v 0.2.9
  16. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  17. */
  18. namespace Cake\Model;
  19. use Cake\Core\Configure;
  20. use Cake\Error;
  21. use Cake\Utility\Hash;
  22. /**
  23. * Permissions linking AROs with ACOs
  24. *
  25. */
  26. class Permission extends Model {
  27. /**
  28. * Explicitly disable in-memory query caching
  29. *
  30. * @var boolean
  31. */
  32. public $cacheQueries = false;
  33. /**
  34. * Override default table name
  35. *
  36. * @var string
  37. */
  38. public $useTable = 'aros_acos';
  39. /**
  40. * Permissions link AROs with ACOs
  41. *
  42. * @var array
  43. */
  44. public $belongsTo = array('Aro', 'Aco');
  45. /**
  46. * No behaviors for this model
  47. *
  48. * @var array
  49. */
  50. public $actsAs = null;
  51. /**
  52. * Constructor, used to tell this model to use the
  53. * database configured for ACL
  54. */
  55. public function __construct() {
  56. $config = Configure::read('Acl.database');
  57. if (!empty($config)) {
  58. $this->useDbConfig = $config;
  59. }
  60. parent::__construct();
  61. }
  62. /**
  63. * Checks if the given $aro has access to action $action in $aco
  64. *
  65. * @param string $aro ARO The requesting object identifier.
  66. * @param string $aco ACO The controlled object identifier.
  67. * @param string $action Action (defaults to *)
  68. * @return boolean Success (true if ARO has access to action in ACO, false otherwise)
  69. */
  70. public function check($aro, $aco, $action = '*') {
  71. if (!$aro || !$aco) {
  72. return false;
  73. }
  74. $permKeys = $this->getAcoKeys($this->schema());
  75. $aroPath = $this->Aro->node($aro);
  76. $acoPath = $this->Aco->node($aco);
  77. if (!$aroPath || !$acoPath) {
  78. trigger_error(__d('cake_dev',
  79. "%s - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: %s\nAco: %s",
  80. 'DbAcl::check()',
  81. print_r($aro, true),
  82. print_r($aco, true)),
  83. E_USER_WARNING
  84. );
  85. return false;
  86. }
  87. if (!$acoPath) {
  88. trigger_error(__d('cake_dev',
  89. "%s - Failed ACO node lookup in permissions check. Node references:\nAro: %s\nAco: %s",
  90. 'DbAcl::check()',
  91. print_r($aro, true),
  92. print_r($aco, true)),
  93. E_USER_WARNING
  94. );
  95. return false;
  96. }
  97. if ($action !== '*' && !in_array('_' . $action, $permKeys)) {
  98. trigger_error(__d('cake_dev', "ACO permissions key %s does not exist in %s", $action, 'DbAcl::check()'), E_USER_NOTICE);
  99. return false;
  100. }
  101. $inherited = array();
  102. $acoIDs = Hash::extract($acoPath, '{n}.' . $this->Aco->alias . '.id');
  103. $count = count($aroPath);
  104. for ($i = 0; $i < $count; $i++) {
  105. $permAlias = $this->alias;
  106. $perms = $this->find('all', array(
  107. 'conditions' => array(
  108. "{$permAlias}.aro_id" => $aroPath[$i][$this->Aro->alias]['id'],
  109. "{$permAlias}.aco_id" => $acoIDs
  110. ),
  111. 'order' => array($this->Aco->alias . '.lft' => 'desc'),
  112. 'recursive' => 0
  113. ));
  114. if (empty($perms)) {
  115. continue;
  116. }
  117. $perms = Hash::extract($perms, '{n}.' . $this->alias);
  118. foreach ($perms as $perm) {
  119. if ($action === '*') {
  120. foreach ($permKeys as $key) {
  121. if (!empty($perm)) {
  122. if ($perm[$key] == -1) {
  123. return false;
  124. } elseif ($perm[$key] == 1) {
  125. $inherited[$key] = 1;
  126. }
  127. }
  128. }
  129. if (count($inherited) === count($permKeys)) {
  130. return true;
  131. }
  132. } else {
  133. switch ($perm['_' . $action]) {
  134. case -1:
  135. return false;
  136. case 0:
  137. continue;
  138. case 1:
  139. return true;
  140. }
  141. }
  142. }
  143. }
  144. return false;
  145. }
  146. /**
  147. * Allow $aro to have access to action $actions in $aco
  148. *
  149. * @param string $aro ARO The requesting object identifier.
  150. * @param string $aco ACO The controlled object identifier.
  151. * @param string $actions Action (defaults to *) Invalid permissions will result in an exception
  152. * @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
  153. * @return boolean Success
  154. * @throws Cake\Error\AclException on Invalid permission key.
  155. */
  156. public function allow($aro, $aco, $actions = '*', $value = 1) {
  157. $perms = $this->getAclLink($aro, $aco);
  158. $permKeys = $this->getAcoKeys($this->schema());
  159. $save = array();
  160. if (!$perms) {
  161. trigger_error(__d('cake_dev', '%s - Invalid node', 'DbAcl::allow()'), E_USER_WARNING);
  162. return false;
  163. }
  164. if (isset($perms[0])) {
  165. $save = $perms[0][$this->alias];
  166. }
  167. if ($actions === '*') {
  168. $save = array_combine($permKeys, array_pad(array(), count($permKeys), $value));
  169. } else {
  170. if (!is_array($actions)) {
  171. $actions = array('_' . $actions);
  172. }
  173. foreach ($actions as $action) {
  174. if ($action{0} !== '_') {
  175. $action = '_' . $action;
  176. }
  177. if (!in_array($action, $permKeys, true)) {
  178. throw new Error\AclException(__d('cake_dev', 'Invalid permission key "%s"', $action));
  179. }
  180. $save[$action] = $value;
  181. }
  182. }
  183. list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']);
  184. if ($perms['link'] && !empty($perms['link'])) {
  185. $save['id'] = $perms['link'][0][$this->alias]['id'];
  186. } else {
  187. unset($save['id']);
  188. $this->id = null;
  189. }
  190. return ($this->save($save) !== false);
  191. }
  192. /**
  193. * Get an array of access-control links between the given Aro and Aco
  194. *
  195. * @param string $aro ARO The requesting object identifier.
  196. * @param string $aco ACO The controlled object identifier.
  197. * @return array Indexed array with: 'aro', 'aco' and 'link'
  198. */
  199. public function getAclLink($aro, $aco) {
  200. $obj = array();
  201. $obj['Aro'] = $this->Aro->node($aro);
  202. $obj['Aco'] = $this->Aco->node($aco);
  203. if (empty($obj['Aro']) || empty($obj['Aco'])) {
  204. return false;
  205. }
  206. $aro = Hash::extract($obj, 'Aro.0.' . $this->Aro->alias . '.id');
  207. $aco = Hash::extract($obj, 'Aco.0.' . $this->Aco->alias . '.id');
  208. $aro = current($aro);
  209. $aco = current($aco);
  210. return array(
  211. 'aro' => $aro,
  212. 'aco' => $aco,
  213. 'link' => $this->find('all', array('conditions' => array(
  214. $this->alias . '.aro_id' => $aro,
  215. $this->alias . '.aco_id' => $aco
  216. )))
  217. );
  218. }
  219. /**
  220. * Get the crud type keys
  221. *
  222. * @param array $keys Permission schema
  223. * @return array permission keys
  224. */
  225. public function getAcoKeys($keys) {
  226. $newKeys = array();
  227. $keys = array_keys($keys);
  228. foreach ($keys as $key) {
  229. if (!in_array($key, array('id', 'aro_id', 'aco_id'))) {
  230. $newKeys[] = $key;
  231. }
  232. }
  233. return $newKeys;
  234. }
  235. }