Permission.php 6.5 KB

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