PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/app/controllers/components/aclite.php

http://fredistrano.googlecode.com/
PHP | 356 lines | 231 code | 37 blank | 88 comment | 58 complexity | f207a7584074479c4d4eff7d9bd1e11b MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /* SVN FILE: $Id: aclite.php 318 2008-10-15 16:34:21Z fbollon $ */
  3. /**
  4. * Component that enforces authorizations
  5. *
  6. * PHP 4 and 5
  7. *
  8. * Licensed under The MIT License
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @filesource
  12. * @link http://code.google.com/p/fredistrano
  13. * @package app
  14. * @subpackage app.controllers.components
  15. * @version $Revision: 318 $
  16. * @modifiedby $Author: fbollon $
  17. * @lastmodified $Date: 2008-10-15 18:34:21 +0200 (Wed, 15 Oct 2008) $
  18. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  19. */
  20. /**
  21. * Component that enforces authorizations
  22. *
  23. * @package aclite
  24. * @subpackage aclite.components
  25. */
  26. class AcliteComponent extends Object {
  27. var $name = 'Aclite';
  28. var $controller = null;
  29. var $components = array (
  30. 'Acl',
  31. 'Session',
  32. 'RequestHandler'
  33. );
  34. var $lastCheckDetails = '';
  35. // Specal component's functions -----------------------------------------
  36. /**
  37. * If required ('Security.authorizationsDisabled'), authorizations are validated onload
  38. */
  39. function startup(& $controller) {
  40. // Is aclite globally disabled (see config)?
  41. if (Configure::read('Security.authorizationsDisabled')) {
  42. return;
  43. }
  44. // Init Aclite
  45. $this->controller = & $controller;
  46. // Callback to beforeAuthorize for dynamic authorizations
  47. $this->Session->delete('dynamicGroup');
  48. if (method_exists($this->controller, $tmp = 'beforeAuthorize')) {
  49. $this->controller->{$tmp}();
  50. }
  51. // Init config
  52. $config = & AcliteComponent :: getConfig();
  53. // Once not twice
  54. if ($config['done'] === true) {
  55. return;
  56. }
  57. // Setting groups for the view
  58. $groups = $config['groups'];
  59. $myGroups = Set::extract($groups,'{n}.name');
  60. $this->controller->set('myGroups',$myGroups);
  61. // Check GLOBAL access violation
  62. if (isset ($this->controller->authGlobal)) {
  63. $parentName = get_parent_class($controller);
  64. $parentName = substr($parentName, 0 , strlen($parentName) - strlen('Controller'));
  65. $isAuthorized = $this->_checkAccess($parentName,$this->controller->authGlobal);
  66. if (!$isAuthorized) {
  67. $this->_displayAccessDeniedPage();
  68. }
  69. }
  70. // Check LOCAL access violation
  71. if (isset ($this->controller->authLocal)) {
  72. $isAuthorized = $this->_checkAccess($config['controller'], $this->controller->authLocal);
  73. if (!$isAuthorized) {
  74. $this->_displayAccessDeniedPage();
  75. }
  76. }
  77. // Successfully authorized once
  78. $config['done'] = true;
  79. } // startup
  80. /**
  81. * Build a config out of session variable and context data
  82. *
  83. * @return array Provide information about the current user's groups and the requested ressource
  84. * @access public
  85. */
  86. function & getConfig() {
  87. static $config = null;
  88. $user = $this->Session->read('User');
  89. $dynamicGroups = $this->Session->read('dynamicGroup');
  90. if (is_array($dynamicGroups) && is_array($user['Group'])) {
  91. $groups = array_merge ($user['Group'],$dynamicGroups);
  92. } else if (is_array($dynamicGroups)) {
  93. $groups = $dynamicGroups;
  94. } else if (is_array($user['Group'])) {
  95. $groups = $user['Group'];
  96. } else {
  97. // groupe 'anonymous' si pas de groupe
  98. $groups[] = array('name' => 'anonymous');
  99. }
  100. if (!isset ($config) || !$config) {
  101. $config = array (
  102. 'groups' => $groups,
  103. 'controller' => $this->controller->name,
  104. 'action' => $this->controller->action,
  105. 'done' => false
  106. );
  107. }
  108. return $config;
  109. }// getConfig
  110. /**
  111. * Return a list of the current user's groups (static dynamic)
  112. *
  113. * @return array List of the names of each group
  114. * @access public
  115. */
  116. function getGroupsOfCurrrentUser() {
  117. $config = & AcliteComponent :: getConfig();
  118. $groups = $config['groups'];
  119. return Set::extract($groups,'{n}.name');
  120. }// getGroupsOfCurrrentUser
  121. // Public functions -----------------------------------------
  122. /**
  123. * Check if the current user is allowed to access a given ressource
  124. *
  125. * @param array $requirements Requirements that protects the resource
  126. * @param array $redirectOptions What to do if the user is not allowed to continue (flash message or error page)
  127. * @access public
  128. */
  129. function checkAccess( $requirements=array(), $redirectOptions=array() ) {
  130. $isAuthorized = $this->isAuthorized($requirements);
  131. if (!$isAuthorized){
  132. if (!is_array($redirectOptions)) {
  133. $redirectOptions = array('message' => $redirectOptions);
  134. }
  135. $mode = isset($redirectOptions['mode'])?$redirectOptions['mode']:'render';
  136. $this->_displayAccessDeniedPage($mode, $redirectOptions);
  137. }
  138. }// checkAccess
  139. /**
  140. * Check if the current user is authoriez to access a given ressource
  141. *
  142. * @param array $requirements Requirements that protects the resource
  143. * @return boolean true if allowed; false otherwise
  144. * @access public
  145. */
  146. function isAuthorized($requirements=array()) {
  147. $res = true;
  148. $config = & AcliteComponent :: getConfig();
  149. $groups = $config['groups'];
  150. if (empty($requirements) || !is_array($requirements)) {
  151. // Bad array syntax
  152. $this->lastCheckDetails = 'Bad ACL syntax';
  153. return false;
  154. }
  155. foreach ($requirements as $requirement) {
  156. if (is_array($requirement)) {
  157. if (isset ($requirement['require'])) {
  158. $acos = $requirement['require'];
  159. } else {
  160. // Bad array syntax
  161. $this->lastCheckDetails = 'Missing require directive';
  162. return false;
  163. }
  164. if (isset ($requirement['action'])) {
  165. if (is_array($requirement['action']) && !empty ($requirement['action'])) {
  166. foreach ($requirement['action'] as $action) {
  167. $directive = " `$acos` [$action] with group(s) : ";
  168. foreach ($groups as $group) {
  169. $directive .= $group['name'].' ';
  170. $res = $this->Acl->check('group.'.$group['name'], $acos,$action);
  171. if ($res === true) {
  172. break;
  173. }
  174. }
  175. if ($res === false) {
  176. $this->lastCheckDetails = "Authentication failure for $directive";
  177. return false;
  178. }
  179. } // foreach
  180. } else {
  181. $directive = " `$acos` [".$requirement['action']."] with group(s) : ";
  182. foreach ($groups as $group) {
  183. $directive .= $group['name'].' ';
  184. $res = $this->Acl->check('group.'.$group['name'], $acos,$requirement['action']);
  185. if ($res === true) {
  186. break;
  187. }
  188. }
  189. }
  190. } else {
  191. $directive = " `$acos` with group(s) : ";
  192. foreach ($groups as $group) {
  193. $directive .= $group['name'].' ';
  194. $res = $this->Acl->check('group.'.$group['name'], $acos);
  195. if ($res === true) {
  196. break;
  197. }
  198. }
  199. }
  200. } else {
  201. $directive = " `$requirement` with group(s) : ";
  202. foreach ($groups as $group) {
  203. $directive .= $group['name'].' ';
  204. $res = $this->Acl->check('group.'.$group['name'], $requirement);
  205. if ($res === true) {
  206. break;
  207. }
  208. }
  209. }
  210. if ($res === false) {
  211. $this->lastCheckDetails = "Authentication failure for $directive";
  212. return false;
  213. }
  214. } // foreach
  215. $this->lastCheckDetails = 'All requirements ended successfully';
  216. return true;
  217. }// isAuthorized
  218. /**
  219. * Add a dynamic group to the current User's session
  220. *
  221. * @param string $acceptedUsers List of accepted users
  222. * @param string $dynamicGroup Dynamic group to be added
  223. * @access public
  224. */
  225. function updateSessionWithDynamicGroup($acceptedUsers = null, $dynamicGroup = null){
  226. if (!isset($_SESSION['User']['User']['cn'])) {
  227. return;
  228. }
  229. $currentUser = trim(strtoupper($_SESSION['User']['User']['cn']));
  230. if (is_string($acceptedUsers)){
  231. $acceptedUsers = array($acceptedUsers);
  232. }
  233. foreach($acceptedUsers as $acceptedUser) {
  234. if ($currentUser == trim(strtoupper($acceptedUser))) {
  235. $this->Session->write('dynamicGroup', array( array( 'name' => $dynamicGroup )));
  236. }
  237. }
  238. }// updateSessionWithDynamicGroup
  239. /**
  240. * Ask the Acl model to reload the acl contained in the database
  241. *
  242. * @see app/plugins/models/acl_management.php for further details
  243. * @param string $type REload only a given type of Acl (Aro,Aco)
  244. * @access public
  245. */
  246. function reloadsAcls($type = null) {
  247. App::import('Model', 'Aclite.AclManagement');
  248. $aclite = new AclManagement();
  249. $aclite->reloadAcls($type);
  250. }//reloadsAcls
  251. // Private functions -----------------------------------------
  252. function _checkAccess($controller, $authorizations = array()) {
  253. $config = & AcliteComponent :: getConfig();
  254. if (!empty($authorizations)) {
  255. if (isset ($authorizations[$controller])) {
  256. // Controller wide ACL
  257. $requireList = $authorizations[$controller];
  258. if (isset ($authorizations['except'])) {
  259. // Handling aurthorization exceptions
  260. if (isset ($authorizations['except'][$config['action']])) {
  261. $exceptList = $authorizations['except'][$config['action']];
  262. return $this->isAuthorized($exceptList);
  263. } else if (isset ($authorizations['except'][$config['controller'].'.'.$config['action']])) {
  264. $exceptList = $authorizations['except'][$config['controller'].'.'.$config['action']];
  265. return $this->isAuthorized($exceptList);
  266. } else
  267. // No usable exception found
  268. return $this->isAuthorized($requireList);
  269. } else {
  270. // No usable exception found
  271. return $this->isAuthorized($requireList);
  272. }
  273. } else {
  274. // Action specific ACL
  275. if (isset ($authorizations[$config['action']])) {
  276. return $this->isAuthorized($authorizations[$config['action']]);
  277. } else {
  278. $this->lastCheckDetails = 'No ACL directive found for current action';
  279. return true;
  280. }
  281. }
  282. } else {
  283. // No auth required
  284. $this->lastCheckDetails = 'No ACL directive found';
  285. return true;
  286. }
  287. }// checkAccess
  288. function _displayAccessDeniedPage($mode='render',$options=array()) {
  289. if ($mode=='render') {
  290. $defaultOptions = array(
  291. 'message' => $this->lastCheckDetails,
  292. 'view' => null,
  293. 'layout' => ($this->RequestHandler->isAjax()?'ajax':null)
  294. );
  295. $options = am($defaultOptions, $options);
  296. extract($options);
  297. if (Configure::read('debug') === 0) {
  298. $message = __('Insufficient privileges for accessing the requested ressource', true);
  299. }
  300. $this->controller->set('denialDetails', $message);
  301. if (is_null($view)) {
  302. $file = APP . 'plugins/aclite/views/pages/denied.ctp';
  303. }
  304. e($this->controller->render($view, $layout, $file));
  305. exit;
  306. } else if ($mode=='redirect') {
  307. $defaultOptions = array(
  308. 'url' => '/',
  309. 'message' => $this->lastCheckDetails,
  310. );
  311. $options = am($defaultOptions, $options);
  312. extract($options);
  313. $this->controller->Session->setFlash($message);
  314. $this->controller->redirect($url);
  315. exit;
  316. }
  317. }// displayAccessDeniedPage
  318. } // Aclite
  319. ?>