Mercurial > hg > Members > shoshi > webvirt
comparison cake/libs/controller/components/acl.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:261e66bd5a0c |
---|---|
1 <?php | |
2 /** | |
3 * Access Control List factory class. | |
4 * | |
5 * Permissions system. | |
6 * | |
7 * PHP versions 4 and 5 | |
8 * | |
9 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | |
10 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
11 * | |
12 * Licensed under The MIT License | |
13 * Redistributions of files must retain the above copyright notice. | |
14 * | |
15 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) | |
16 * @link http://cakephp.org CakePHP(tm) Project | |
17 * @package cake | |
18 * @subpackage cake.cake.libs.controller.components | |
19 * @since CakePHP(tm) v 0.10.0.1076 | |
20 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) | |
21 */ | |
22 | |
23 /** | |
24 * Access Control List factory class. | |
25 * | |
26 * Uses a strategy pattern to allow custom ACL implementations to be used with the same component interface. | |
27 * You can define by changing `Configure::write('Acl.classname', 'DbAcl');` in your core.php. Concrete ACL | |
28 * implementations should extend `AclBase` and implement the methods it defines. | |
29 * | |
30 * @package cake | |
31 * @subpackage cake.cake.libs.controller.components | |
32 * @link http://book.cakephp.org/view/1242/Access-Control-Lists | |
33 */ | |
34 class AclComponent extends Object { | |
35 | |
36 /** | |
37 * Instance of an ACL class | |
38 * | |
39 * @var object | |
40 * @access protected | |
41 */ | |
42 var $_Instance = null; | |
43 | |
44 /** | |
45 * Constructor. Will return an instance of the correct ACL class as defined in `Configure::read('Acl.classname')` | |
46 * | |
47 */ | |
48 function __construct() { | |
49 $name = Inflector::camelize(strtolower(Configure::read('Acl.classname'))); | |
50 if (!class_exists($name)) { | |
51 if (App::import('Component', $name)) { | |
52 list($plugin, $name) = pluginSplit($name); | |
53 $name .= 'Component'; | |
54 } else { | |
55 trigger_error(sprintf(__('Could not find %s.', true), $name), E_USER_WARNING); | |
56 } | |
57 } | |
58 $this->_Instance =& new $name(); | |
59 $this->_Instance->initialize($this); | |
60 } | |
61 | |
62 /** | |
63 * Startup is not used | |
64 * | |
65 * @param object $controller Controller using this component | |
66 * @return boolean Proceed with component usage (true), or fail (false) | |
67 * @access public | |
68 */ | |
69 function startup(&$controller) { | |
70 return true; | |
71 } | |
72 | |
73 /** | |
74 * Empty class defintion, to be overridden in subclasses. | |
75 * | |
76 * @access protected | |
77 */ | |
78 function _initACL() { | |
79 } | |
80 | |
81 /** | |
82 * Pass-thru function for ACL check instance. Check methods | |
83 * are used to check whether or not an ARO can access an ACO | |
84 * | |
85 * @param string $aro ARO The requesting object identifier. | |
86 * @param string $aco ACO The controlled object identifier. | |
87 * @param string $action Action (defaults to *) | |
88 * @return boolean Success | |
89 * @access public | |
90 */ | |
91 function check($aro, $aco, $action = "*") { | |
92 return $this->_Instance->check($aro, $aco, $action); | |
93 } | |
94 | |
95 /** | |
96 * Pass-thru function for ACL allow instance. Allow methods | |
97 * are used to grant an ARO access to an ACO. | |
98 * | |
99 * @param string $aro ARO The requesting object identifier. | |
100 * @param string $aco ACO The controlled object identifier. | |
101 * @param string $action Action (defaults to *) | |
102 * @return boolean Success | |
103 * @access public | |
104 */ | |
105 function allow($aro, $aco, $action = "*") { | |
106 return $this->_Instance->allow($aro, $aco, $action); | |
107 } | |
108 | |
109 /** | |
110 * Pass-thru function for ACL deny instance. Deny methods | |
111 * are used to remove permission from an ARO to access an ACO. | |
112 * | |
113 * @param string $aro ARO The requesting object identifier. | |
114 * @param string $aco ACO The controlled object identifier. | |
115 * @param string $action Action (defaults to *) | |
116 * @return boolean Success | |
117 * @access public | |
118 */ | |
119 function deny($aro, $aco, $action = "*") { | |
120 return $this->_Instance->deny($aro, $aco, $action); | |
121 } | |
122 | |
123 /** | |
124 * Pass-thru function for ACL inherit instance. Inherit methods | |
125 * modify the permission for an ARO to be that of its parent object. | |
126 * | |
127 * @param string $aro ARO The requesting object identifier. | |
128 * @param string $aco ACO The controlled object identifier. | |
129 * @param string $action Action (defaults to *) | |
130 * @return boolean Success | |
131 * @access public | |
132 */ | |
133 function inherit($aro, $aco, $action = "*") { | |
134 return $this->_Instance->inherit($aro, $aco, $action); | |
135 } | |
136 | |
137 /** | |
138 * Pass-thru function for ACL grant instance. An alias for AclComponent::allow() | |
139 * | |
140 * @param string $aro ARO The requesting object identifier. | |
141 * @param string $aco ACO The controlled object identifier. | |
142 * @param string $action Action (defaults to *) | |
143 * @return boolean Success | |
144 * @access public | |
145 */ | |
146 function grant($aro, $aco, $action = "*") { | |
147 return $this->_Instance->grant($aro, $aco, $action); | |
148 } | |
149 | |
150 /** | |
151 * Pass-thru function for ACL grant instance. An alias for AclComponent::deny() | |
152 * | |
153 * @param string $aro ARO The requesting object identifier. | |
154 * @param string $aco ACO The controlled object identifier. | |
155 * @param string $action Action (defaults to *) | |
156 * @return boolean Success | |
157 * @access public | |
158 */ | |
159 function revoke($aro, $aco, $action = "*") { | |
160 return $this->_Instance->revoke($aro, $aco, $action); | |
161 } | |
162 } | |
163 | |
164 /** | |
165 * Access Control List abstract class. Not to be instantiated. | |
166 * Subclasses of this class are used by AclComponent to perform ACL checks in Cake. | |
167 * | |
168 * @package cake | |
169 * @subpackage cake.cake.libs.controller.components | |
170 * @abstract | |
171 */ | |
172 class AclBase extends Object { | |
173 | |
174 /** | |
175 * This class should never be instantiated, just subclassed. | |
176 * | |
177 */ | |
178 function __construct() { | |
179 if (strcasecmp(get_class($this), "AclBase") == 0 || !is_subclass_of($this, "AclBase")) { | |
180 trigger_error(__("[acl_base] The AclBase class constructor has been called, or the class was instantiated. This class must remain abstract. Please refer to the Cake docs for ACL configuration.", true), E_USER_ERROR); | |
181 return NULL; | |
182 } | |
183 } | |
184 | |
185 /** | |
186 * Empty method to be overridden in subclasses | |
187 * | |
188 * @param string $aro ARO The requesting object identifier. | |
189 * @param string $aco ACO The controlled object identifier. | |
190 * @param string $action Action (defaults to *) | |
191 * @access public | |
192 */ | |
193 function check($aro, $aco, $action = "*") { | |
194 } | |
195 | |
196 /** | |
197 * Empty method to be overridden in subclasses | |
198 * | |
199 * @param object $component Component | |
200 * @access public | |
201 */ | |
202 function initialize(&$component) { | |
203 } | |
204 } | |
205 | |
206 /** | |
207 * DbAcl implements an ACL control system in the database. ARO's and ACO's are | |
208 * structured into trees and a linking table is used to define permissions. You | |
209 * can install the schema for DbAcl with the Schema Shell. | |
210 * | |
211 * `$aco` and `$aro` parameters can be slash delimited paths to tree nodes. | |
212 * | |
213 * eg. `controllers/Users/edit` | |
214 * | |
215 * Would point to a tree structure like | |
216 * | |
217 * {{{ | |
218 * controllers | |
219 * Users | |
220 * edit | |
221 * }}} | |
222 * | |
223 * @package cake | |
224 * @subpackage cake.cake.libs.model | |
225 */ | |
226 class DbAcl extends AclBase { | |
227 | |
228 /** | |
229 * Constructor | |
230 * | |
231 */ | |
232 function __construct() { | |
233 parent::__construct(); | |
234 if (!class_exists('AclNode')) { | |
235 require LIBS . 'model' . DS . 'db_acl.php'; | |
236 } | |
237 $this->Aro =& ClassRegistry::init(array('class' => 'Aro', 'alias' => 'Aro')); | |
238 $this->Aco =& ClassRegistry::init(array('class' => 'Aco', 'alias' => 'Aco')); | |
239 } | |
240 | |
241 /** | |
242 * Initializes the containing component and sets the Aro/Aco objects to it. | |
243 * | |
244 * @param AclComponent $component | |
245 * @return void | |
246 * @access public | |
247 */ | |
248 function initialize(&$component) { | |
249 $component->Aro =& $this->Aro; | |
250 $component->Aco =& $this->Aco; | |
251 } | |
252 | |
253 /** | |
254 * Checks if the given $aro has access to action $action in $aco | |
255 * | |
256 * @param string $aro ARO The requesting object identifier. | |
257 * @param string $aco ACO The controlled object identifier. | |
258 * @param string $action Action (defaults to *) | |
259 * @return boolean Success (true if ARO has access to action in ACO, false otherwise) | |
260 * @access public | |
261 * @link http://book.cakephp.org/view/1249/Checking-Permissions-The-ACL-Component | |
262 */ | |
263 function check($aro, $aco, $action = "*") { | |
264 if ($aro == null || $aco == null) { | |
265 return false; | |
266 } | |
267 | |
268 $permKeys = $this->_getAcoKeys($this->Aro->Permission->schema()); | |
269 $aroPath = $this->Aro->node($aro); | |
270 $acoPath = $this->Aco->node($aco); | |
271 | |
272 if (empty($aroPath) || empty($acoPath)) { | |
273 trigger_error(__("DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ", true) . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); | |
274 return false; | |
275 } | |
276 | |
277 if ($acoPath == null || $acoPath == array()) { | |
278 trigger_error(__("DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ", true) . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); | |
279 return false; | |
280 } | |
281 | |
282 $aroNode = $aroPath[0]; | |
283 $acoNode = $acoPath[0]; | |
284 | |
285 if ($action != '*' && !in_array('_' . $action, $permKeys)) { | |
286 trigger_error(sprintf(__("ACO permissions key %s does not exist in DbAcl::check()", true), $action), E_USER_NOTICE); | |
287 return false; | |
288 } | |
289 | |
290 $inherited = array(); | |
291 $acoIDs = Set::extract($acoPath, '{n}.' . $this->Aco->alias . '.id'); | |
292 | |
293 $count = count($aroPath); | |
294 for ($i = 0 ; $i < $count; $i++) { | |
295 $permAlias = $this->Aro->Permission->alias; | |
296 | |
297 $perms = $this->Aro->Permission->find('all', array( | |
298 'conditions' => array( | |
299 "{$permAlias}.aro_id" => $aroPath[$i][$this->Aro->alias]['id'], | |
300 "{$permAlias}.aco_id" => $acoIDs | |
301 ), | |
302 'order' => array($this->Aco->alias . '.lft' => 'desc'), | |
303 'recursive' => 0 | |
304 )); | |
305 | |
306 if (empty($perms)) { | |
307 continue; | |
308 } else { | |
309 $perms = Set::extract($perms, '{n}.' . $this->Aro->Permission->alias); | |
310 foreach ($perms as $perm) { | |
311 if ($action == '*') { | |
312 | |
313 foreach ($permKeys as $key) { | |
314 if (!empty($perm)) { | |
315 if ($perm[$key] == -1) { | |
316 return false; | |
317 } elseif ($perm[$key] == 1) { | |
318 $inherited[$key] = 1; | |
319 } | |
320 } | |
321 } | |
322 | |
323 if (count($inherited) === count($permKeys)) { | |
324 return true; | |
325 } | |
326 } else { | |
327 switch ($perm['_' . $action]) { | |
328 case -1: | |
329 return false; | |
330 case 0: | |
331 continue; | |
332 break; | |
333 case 1: | |
334 return true; | |
335 break; | |
336 } | |
337 } | |
338 } | |
339 } | |
340 } | |
341 return false; | |
342 } | |
343 | |
344 /** | |
345 * Allow $aro to have access to action $actions in $aco | |
346 * | |
347 * @param string $aro ARO The requesting object identifier. | |
348 * @param string $aco ACO The controlled object identifier. | |
349 * @param string $actions Action (defaults to *) | |
350 * @param integer $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit) | |
351 * @return boolean Success | |
352 * @access public | |
353 * @link http://book.cakephp.org/view/1248/Assigning-Permissions | |
354 */ | |
355 function allow($aro, $aco, $actions = "*", $value = 1) { | |
356 $perms = $this->getAclLink($aro, $aco); | |
357 $permKeys = $this->_getAcoKeys($this->Aro->Permission->schema()); | |
358 $save = array(); | |
359 | |
360 if ($perms == false) { | |
361 trigger_error(__('DbAcl::allow() - Invalid node', true), E_USER_WARNING); | |
362 return false; | |
363 } | |
364 if (isset($perms[0])) { | |
365 $save = $perms[0][$this->Aro->Permission->alias]; | |
366 } | |
367 | |
368 if ($actions == "*") { | |
369 $permKeys = $this->_getAcoKeys($this->Aro->Permission->schema()); | |
370 $save = array_combine($permKeys, array_pad(array(), count($permKeys), $value)); | |
371 } else { | |
372 if (!is_array($actions)) { | |
373 $actions = array('_' . $actions); | |
374 } | |
375 if (is_array($actions)) { | |
376 foreach ($actions as $action) { | |
377 if ($action{0} != '_') { | |
378 $action = '_' . $action; | |
379 } | |
380 if (in_array($action, $permKeys)) { | |
381 $save[$action] = $value; | |
382 } | |
383 } | |
384 } | |
385 } | |
386 list($save['aro_id'], $save['aco_id']) = array($perms['aro'], $perms['aco']); | |
387 | |
388 if ($perms['link'] != null && !empty($perms['link'])) { | |
389 $save['id'] = $perms['link'][0][$this->Aro->Permission->alias]['id']; | |
390 } else { | |
391 unset($save['id']); | |
392 $this->Aro->Permission->id = null; | |
393 } | |
394 return ($this->Aro->Permission->save($save) !== false); | |
395 } | |
396 | |
397 /** | |
398 * Deny access for $aro to action $action in $aco | |
399 * | |
400 * @param string $aro ARO The requesting object identifier. | |
401 * @param string $aco ACO The controlled object identifier. | |
402 * @param string $actions Action (defaults to *) | |
403 * @return boolean Success | |
404 * @access public | |
405 * @link http://book.cakephp.org/view/1248/Assigning-Permissions | |
406 */ | |
407 function deny($aro, $aco, $action = "*") { | |
408 return $this->allow($aro, $aco, $action, -1); | |
409 } | |
410 | |
411 /** | |
412 * Let access for $aro to action $action in $aco be inherited | |
413 * | |
414 * @param string $aro ARO The requesting object identifier. | |
415 * @param string $aco ACO The controlled object identifier. | |
416 * @param string $actions Action (defaults to *) | |
417 * @return boolean Success | |
418 * @access public | |
419 */ | |
420 function inherit($aro, $aco, $action = "*") { | |
421 return $this->allow($aro, $aco, $action, 0); | |
422 } | |
423 | |
424 /** | |
425 * Allow $aro to have access to action $actions in $aco | |
426 * | |
427 * @param string $aro ARO The requesting object identifier. | |
428 * @param string $aco ACO The controlled object identifier. | |
429 * @param string $actions Action (defaults to *) | |
430 * @return boolean Success | |
431 * @see allow() | |
432 * @access public | |
433 */ | |
434 function grant($aro, $aco, $action = "*") { | |
435 return $this->allow($aro, $aco, $action); | |
436 } | |
437 | |
438 /** | |
439 * Deny access for $aro to action $action in $aco | |
440 * | |
441 * @param string $aro ARO The requesting object identifier. | |
442 * @param string $aco ACO The controlled object identifier. | |
443 * @param string $actions Action (defaults to *) | |
444 * @return boolean Success | |
445 * @see deny() | |
446 * @access public | |
447 */ | |
448 function revoke($aro, $aco, $action = "*") { | |
449 return $this->deny($aro, $aco, $action); | |
450 } | |
451 | |
452 /** | |
453 * Get an array of access-control links between the given Aro and Aco | |
454 * | |
455 * @param string $aro ARO The requesting object identifier. | |
456 * @param string $aco ACO The controlled object identifier. | |
457 * @return array Indexed array with: 'aro', 'aco' and 'link' | |
458 * @access public | |
459 */ | |
460 function getAclLink($aro, $aco) { | |
461 $obj = array(); | |
462 $obj['Aro'] = $this->Aro->node($aro); | |
463 $obj['Aco'] = $this->Aco->node($aco); | |
464 | |
465 if (empty($obj['Aro']) || empty($obj['Aco'])) { | |
466 return false; | |
467 } | |
468 | |
469 return array( | |
470 'aro' => Set::extract($obj, 'Aro.0.'.$this->Aro->alias.'.id'), | |
471 'aco' => Set::extract($obj, 'Aco.0.'.$this->Aco->alias.'.id'), | |
472 'link' => $this->Aro->Permission->find('all', array('conditions' => array( | |
473 $this->Aro->Permission->alias . '.aro_id' => Set::extract($obj, 'Aro.0.'.$this->Aro->alias.'.id'), | |
474 $this->Aro->Permission->alias . '.aco_id' => Set::extract($obj, 'Aco.0.'.$this->Aco->alias.'.id') | |
475 ))) | |
476 ); | |
477 } | |
478 | |
479 /** | |
480 * Get the keys used in an ACO | |
481 * | |
482 * @param array $keys Permission model info | |
483 * @return array ACO keys | |
484 * @access protected | |
485 */ | |
486 function _getAcoKeys($keys) { | |
487 $newKeys = array(); | |
488 $keys = array_keys($keys); | |
489 foreach ($keys as $key) { | |
490 if (!in_array($key, array('id', 'aro_id', 'aco_id'))) { | |
491 $newKeys[] = $key; | |
492 } | |
493 } | |
494 return $newKeys; | |
495 } | |
496 } | |
497 | |
498 /** | |
499 * IniAcl implements an access control system using an INI file. An example | |
500 * of the ini file used can be found in /config/acl.ini.php. | |
501 * | |
502 * @package cake | |
503 * @subpackage cake.cake.libs.model.iniacl | |
504 */ | |
505 class IniAcl extends AclBase { | |
506 | |
507 /** | |
508 * Array with configuration, parsed from ini file | |
509 * | |
510 * @var array | |
511 * @access public | |
512 */ | |
513 var $config = null; | |
514 | |
515 /** | |
516 * The constructor must be overridden, as AclBase is abstract. | |
517 * | |
518 */ | |
519 function __construct() { | |
520 } | |
521 | |
522 /** | |
523 * Main ACL check function. Checks to see if the ARO (access request object) has access to the | |
524 * ACO (access control object).Looks at the acl.ini.php file for permissions | |
525 * (see instructions in /config/acl.ini.php). | |
526 * | |
527 * @param string $aro ARO | |
528 * @param string $aco ACO | |
529 * @param string $aco_action Action | |
530 * @return boolean Success | |
531 * @access public | |
532 */ | |
533 function check($aro, $aco, $aco_action = null) { | |
534 if ($this->config == null) { | |
535 $this->config = $this->readConfigFile(CONFIGS . 'acl.ini.php'); | |
536 } | |
537 $aclConfig = $this->config; | |
538 | |
539 if (isset($aclConfig[$aro]['deny'])) { | |
540 $userDenies = $this->arrayTrim(explode(",", $aclConfig[$aro]['deny'])); | |
541 | |
542 if (array_search($aco, $userDenies)) { | |
543 return false; | |
544 } | |
545 } | |
546 | |
547 if (isset($aclConfig[$aro]['allow'])) { | |
548 $userAllows = $this->arrayTrim(explode(",", $aclConfig[$aro]['allow'])); | |
549 | |
550 if (array_search($aco, $userAllows)) { | |
551 return true; | |
552 } | |
553 } | |
554 | |
555 if (isset($aclConfig[$aro]['groups'])) { | |
556 $userGroups = $this->arrayTrim(explode(",", $aclConfig[$aro]['groups'])); | |
557 | |
558 foreach ($userGroups as $group) { | |
559 if (array_key_exists($group, $aclConfig)) { | |
560 if (isset($aclConfig[$group]['deny'])) { | |
561 $groupDenies=$this->arrayTrim(explode(",", $aclConfig[$group]['deny'])); | |
562 | |
563 if (array_search($aco, $groupDenies)) { | |
564 return false; | |
565 } | |
566 } | |
567 | |
568 if (isset($aclConfig[$group]['allow'])) { | |
569 $groupAllows = $this->arrayTrim(explode(",", $aclConfig[$group]['allow'])); | |
570 | |
571 if (array_search($aco, $groupAllows)) { | |
572 return true; | |
573 } | |
574 } | |
575 } | |
576 } | |
577 } | |
578 return false; | |
579 } | |
580 | |
581 /** | |
582 * Parses an INI file and returns an array that reflects the INI file's section structure. Double-quote friendly. | |
583 * | |
584 * @param string $fileName File | |
585 * @return array INI section structure | |
586 * @access public | |
587 */ | |
588 function readConfigFile($fileName) { | |
589 $fileLineArray = file($fileName); | |
590 | |
591 foreach ($fileLineArray as $fileLine) { | |
592 $dataLine = trim($fileLine); | |
593 $firstChar = substr($dataLine, 0, 1); | |
594 | |
595 if ($firstChar != ';' && $dataLine != '') { | |
596 if ($firstChar == '[' && substr($dataLine, -1, 1) == ']') { | |
597 $sectionName = preg_replace('/[\[\]]/', '', $dataLine); | |
598 } else { | |
599 $delimiter = strpos($dataLine, '='); | |
600 | |
601 if ($delimiter > 0) { | |
602 $key = strtolower(trim(substr($dataLine, 0, $delimiter))); | |
603 $value = trim(substr($dataLine, $delimiter + 1)); | |
604 | |
605 if (substr($value, 0, 1) == '"' && substr($value, -1) == '"') { | |
606 $value = substr($value, 1, -1); | |
607 } | |
608 | |
609 $iniSetting[$sectionName][$key]=stripcslashes($value); | |
610 } else { | |
611 if (!isset($sectionName)) { | |
612 $sectionName = ''; | |
613 } | |
614 | |
615 $iniSetting[$sectionName][strtolower(trim($dataLine))]=''; | |
616 } | |
617 } | |
618 } | |
619 } | |
620 | |
621 return $iniSetting; | |
622 } | |
623 | |
624 /** | |
625 * Removes trailing spaces on all array elements (to prepare for searching) | |
626 * | |
627 * @param array $array Array to trim | |
628 * @return array Trimmed array | |
629 * @access public | |
630 */ | |
631 function arrayTrim($array) { | |
632 foreach ($array as $key => $value) { | |
633 $array[$key] = trim($value); | |
634 } | |
635 array_unshift($array, ""); | |
636 return $array; | |
637 } | |
638 } |