Permission.php 6.5 KB

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