PageRenderTime 79ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/yii/framework/web/auth/CPhpAuthManager.php

https://github.com/joshuaswarren/weatherhub
PHP | 500 lines | 288 code | 33 blank | 179 comment | 46 complexity | 3fb5fd28a18a763021a8b0df83670f84 MD5 | raw file
  1. <?php
  2. /**
  3. * CPhpAuthManager class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CPhpAuthManager represents an authorization manager that stores authorization information in terms of a PHP script file.
  12. *
  13. * The authorization data will be saved to and loaded from a file
  14. * specified by {@link authFile}, which defaults to 'protected/data/auth.php'.
  15. *
  16. * CPhpAuthManager is mainly suitable for authorization data that is not too big
  17. * (for example, the authorization data for a personal blog system).
  18. * Use {@link CDbAuthManager} for more complex authorization data.
  19. *
  20. * @author Qiang Xue <qiang.xue@gmail.com>
  21. * @version $Id: CPhpAuthManager.php 3001 2011-02-24 16:42:44Z alexander.makarow $
  22. * @package system.web.auth
  23. * @since 1.0
  24. */
  25. class CPhpAuthManager extends CAuthManager
  26. {
  27. /**
  28. * @var string the path of the PHP script that contains the authorization data.
  29. * If not set, it will be using 'protected/data/auth.php' as the data file.
  30. * Make sure this file is writable by the Web server process if the authorization
  31. * needs to be changed.
  32. * @see loadFromFile
  33. * @see saveToFile
  34. */
  35. public $authFile;
  36. private $_items=array(); // itemName => item
  37. private $_children=array(); // itemName, childName => child
  38. private $_assignments=array(); // userId, itemName => assignment
  39. /**
  40. * Initializes the application component.
  41. * This method overrides parent implementation by loading the authorization data
  42. * from PHP script.
  43. */
  44. public function init()
  45. {
  46. parent::init();
  47. if($this->authFile===null)
  48. $this->authFile=Yii::getPathOfAlias('application.data.auth').'.php';
  49. $this->load();
  50. }
  51. /**
  52. * Performs access check for the specified user.
  53. * @param string $itemName the name of the operation that need access check
  54. * @param mixed $userId the user ID. This should can be either an integer and a string representing
  55. * the unique identifier of a user. See {@link IWebUser::getId}.
  56. * @param array $params name-value pairs that would be passed to biz rules associated
  57. * with the tasks and roles assigned to the user.
  58. * @return boolean whether the operations can be performed by the user.
  59. */
  60. public function checkAccess($itemName,$userId,$params=array())
  61. {
  62. if(!isset($this->_items[$itemName]))
  63. return false;
  64. $item=$this->_items[$itemName];
  65. Yii::trace('Checking permission "'.$item->getName().'"','system.web.auth.CPhpAuthManager');
  66. if($this->executeBizRule($item->getBizRule(),$params,$item->getData()))
  67. {
  68. if(in_array($itemName,$this->defaultRoles))
  69. return true;
  70. if(isset($this->_assignments[$userId][$itemName]))
  71. {
  72. $assignment=$this->_assignments[$userId][$itemName];
  73. if($this->executeBizRule($assignment->getBizRule(),$params,$assignment->getData()))
  74. return true;
  75. }
  76. foreach($this->_children as $parentName=>$children)
  77. {
  78. if(isset($children[$itemName]) && $this->checkAccess($parentName,$userId,$params))
  79. return true;
  80. }
  81. }
  82. return false;
  83. }
  84. /**
  85. * Adds an item as a child of another item.
  86. * @param string $itemName the parent item name
  87. * @param string $childName the child item name
  88. * @throws CException if either parent or child doesn't exist or if a loop has been detected.
  89. */
  90. public function addItemChild($itemName,$childName)
  91. {
  92. if(!isset($this->_items[$childName],$this->_items[$itemName]))
  93. throw new CException(Yii::t('yii','Either "{parent}" or "{child}" does not exist.',array('{child}'=>$childName,'{name}'=>$itemName)));
  94. $child=$this->_items[$childName];
  95. $item=$this->_items[$itemName];
  96. $this->checkItemChildType($item->getType(),$child->getType());
  97. if($this->detectLoop($itemName,$childName))
  98. throw new CException(Yii::t('yii','Cannot add "{child}" as a child of "{parent}". A loop has been detected.',
  99. array('{child}'=>$childName,'{parent}'=>$itemName)));
  100. if(isset($this->_children[$itemName][$childName]))
  101. throw new CException(Yii::t('yii','The item "{parent}" already has a child "{child}".',
  102. array('{child}'=>$childName,'{parent}'=>$itemName)));
  103. $this->_children[$itemName][$childName]=$this->_items[$childName];
  104. }
  105. /**
  106. * Removes a child from its parent.
  107. * Note, the child item is not deleted. Only the parent-child relationship is removed.
  108. * @param string $itemName the parent item name
  109. * @param string $childName the child item name
  110. * @return boolean whether the removal is successful
  111. */
  112. public function removeItemChild($itemName,$childName)
  113. {
  114. if(isset($this->_children[$itemName][$childName]))
  115. {
  116. unset($this->_children[$itemName][$childName]);
  117. return true;
  118. }
  119. else
  120. return false;
  121. }
  122. /**
  123. * Returns a value indicating whether a child exists within a parent.
  124. * @param string $itemName the parent item name
  125. * @param string $childName the child item name
  126. * @return boolean whether the child exists
  127. */
  128. public function hasItemChild($itemName,$childName)
  129. {
  130. return isset($this->_children[$itemName][$childName]);
  131. }
  132. /**
  133. * Returns the children of the specified item.
  134. * @param mixed $names the parent item name. This can be either a string or an array.
  135. * The latter represents a list of item names (available since version 1.0.5).
  136. * @return array all child items of the parent
  137. */
  138. public function getItemChildren($names)
  139. {
  140. if(is_string($names))
  141. return isset($this->_children[$names]) ? $this->_children[$names] : array();
  142. $children=array();
  143. foreach($names as $name)
  144. {
  145. if(isset($this->_children[$name]))
  146. $children=array_merge($children,$this->_children[$name]);
  147. }
  148. return $children;
  149. }
  150. /**
  151. * Assigns an authorization item to a user.
  152. * @param string $itemName the item name
  153. * @param mixed $userId the user ID (see {@link IWebUser::getId})
  154. * @param string $bizRule the business rule to be executed when {@link checkAccess} is called
  155. * for this particular authorization item.
  156. * @param mixed $data additional data associated with this assignment
  157. * @return CAuthAssignment the authorization assignment information.
  158. * @throws CException if the item does not exist or if the item has already been assigned to the user
  159. */
  160. public function assign($itemName,$userId,$bizRule=null,$data=null)
  161. {
  162. if(!isset($this->_items[$itemName]))
  163. throw new CException(Yii::t('yii','Unknown authorization item "{name}".',array('{name}'=>$itemName)));
  164. else if(isset($this->_assignments[$userId][$itemName]))
  165. throw new CException(Yii::t('yii','Authorization item "{item}" has already been assigned to user "{user}".',
  166. array('{item}'=>$itemName,'{user}'=>$userId)));
  167. else
  168. return $this->_assignments[$userId][$itemName]=new CAuthAssignment($this,$itemName,$userId,$bizRule,$data);
  169. }
  170. /**
  171. * Revokes an authorization assignment from a user.
  172. * @param string $itemName the item name
  173. * @param mixed $userId the user ID (see {@link IWebUser::getId})
  174. * @return boolean whether removal is successful
  175. */
  176. public function revoke($itemName,$userId)
  177. {
  178. if(isset($this->_assignments[$userId][$itemName]))
  179. {
  180. unset($this->_assignments[$userId][$itemName]);
  181. return true;
  182. }
  183. else
  184. return false;
  185. }
  186. /**
  187. * Returns a value indicating whether the item has been assigned to the user.
  188. * @param string $itemName the item name
  189. * @param mixed $userId the user ID (see {@link IWebUser::getId})
  190. * @return boolean whether the item has been assigned to the user.
  191. */
  192. public function isAssigned($itemName,$userId)
  193. {
  194. return isset($this->_assignments[$userId][$itemName]);
  195. }
  196. /**
  197. * Returns the item assignment information.
  198. * @param string $itemName the item name
  199. * @param mixed $userId the user ID (see {@link IWebUser::getId})
  200. * @return CAuthAssignment the item assignment information. Null is returned if
  201. * the item is not assigned to the user.
  202. */
  203. public function getAuthAssignment($itemName,$userId)
  204. {
  205. return isset($this->_assignments[$userId][$itemName])?$this->_assignments[$userId][$itemName]:null;
  206. }
  207. /**
  208. * Returns the item assignments for the specified user.
  209. * @param mixed $userId the user ID (see {@link IWebUser::getId})
  210. * @return array the item assignment information for the user. An empty array will be
  211. * returned if there is no item assigned to the user.
  212. */
  213. public function getAuthAssignments($userId)
  214. {
  215. return isset($this->_assignments[$userId])?$this->_assignments[$userId]:array();
  216. }
  217. /**
  218. * Returns the authorization items of the specific type and user.
  219. * @param integer $type the item type (0: operation, 1: task, 2: role). Defaults to null,
  220. * meaning returning all items regardless of their type.
  221. * @param mixed $userId the user ID. Defaults to null, meaning returning all items even if
  222. * they are not assigned to a user.
  223. * @return array the authorization items of the specific type.
  224. */
  225. public function getAuthItems($type=null,$userId=null)
  226. {
  227. if($type===null && $userId===null)
  228. return $this->_items;
  229. $items=array();
  230. if($userId===null)
  231. {
  232. foreach($this->_items as $name=>$item)
  233. {
  234. if($item->getType()==$type)
  235. $items[$name]=$item;
  236. }
  237. }
  238. else if(isset($this->_assignments[$userId]))
  239. {
  240. foreach($this->_assignments[$userId] as $assignment)
  241. {
  242. $name=$assignment->getItemName();
  243. if(isset($this->_items[$name]) && ($type===null || $this->_items[$name]->getType()==$type))
  244. $items[$name]=$this->_items[$name];
  245. }
  246. }
  247. return $items;
  248. }
  249. /**
  250. * Creates an authorization item.
  251. * An authorization item represents an action permission (e.g. creating a post).
  252. * It has three types: operation, task and role.
  253. * Authorization items form a hierarchy. Higher level items inheirt permissions representing
  254. * by lower level items.
  255. * @param string $name the item name. This must be a unique identifier.
  256. * @param integer $type the item type (0: operation, 1: task, 2: role).
  257. * @param string $description description of the item
  258. * @param string $bizRule business rule associated with the item. This is a piece of
  259. * PHP code that will be executed when {@link checkAccess} is called for the item.
  260. * @param mixed $data additional data associated with the item.
  261. * @return CAuthItem the authorization item
  262. * @throws CException if an item with the same name already exists
  263. */
  264. public function createAuthItem($name,$type,$description='',$bizRule=null,$data=null)
  265. {
  266. if(isset($this->_items[$name]))
  267. throw new CException(Yii::t('yii','Unable to add an item whose name is the same as an existing item.'));
  268. return $this->_items[$name]=new CAuthItem($this,$name,$type,$description,$bizRule,$data);
  269. }
  270. /**
  271. * Removes the specified authorization item.
  272. * @param string $name the name of the item to be removed
  273. * @return boolean whether the item exists in the storage and has been removed
  274. */
  275. public function removeAuthItem($name)
  276. {
  277. if(isset($this->_items[$name]))
  278. {
  279. foreach($this->_children as &$children)
  280. unset($children[$name]);
  281. foreach($this->_assignments as &$assignments)
  282. unset($assignments[$name]);
  283. unset($this->_items[$name]);
  284. return true;
  285. }
  286. else
  287. return false;
  288. }
  289. /**
  290. * Returns the authorization item with the specified name.
  291. * @param string $name the name of the item
  292. * @return CAuthItem the authorization item. Null if the item cannot be found.
  293. */
  294. public function getAuthItem($name)
  295. {
  296. return isset($this->_items[$name])?$this->_items[$name]:null;
  297. }
  298. /**
  299. * Saves an authorization item to persistent storage.
  300. * @param CAuthItem $item the item to be saved.
  301. * @param string $oldName the old item name. If null, it means the item name is not changed.
  302. */
  303. public function saveAuthItem($item,$oldName=null)
  304. {
  305. if($oldName!==null && ($newName=$item->getName())!==$oldName) // name changed
  306. {
  307. if(isset($this->_items[$newName]))
  308. throw new CException(Yii::t('yii','Unable to change the item name. The name "{name}" is already used by another item.',array('{name}'=>$newName)));
  309. if(isset($this->_items[$oldName]) && $this->_items[$oldName]===$item)
  310. {
  311. unset($this->_items[$oldName]);
  312. $this->_items[$newName]=$item;
  313. if(isset($this->_children[$oldName]))
  314. {
  315. $this->_children[$newName]=$this->_children[$oldName];
  316. unset($this->_children[$oldName]);
  317. }
  318. foreach($this->_children as &$children)
  319. {
  320. if(isset($children[$oldName]))
  321. {
  322. $children[$newName]=$children[$oldName];
  323. unset($children[$oldName]);
  324. }
  325. }
  326. foreach($this->_assignments as &$assignments)
  327. {
  328. if(isset($assignments[$oldName]))
  329. {
  330. $assignments[$newName]=$assignments[$oldName];
  331. unset($assignments[$oldName]);
  332. }
  333. }
  334. }
  335. }
  336. }
  337. /**
  338. * Saves the changes to an authorization assignment.
  339. * @param CAuthAssignment $assignment the assignment that has been changed.
  340. */
  341. public function saveAuthAssignment($assignment)
  342. {
  343. }
  344. /**
  345. * Saves authorization data into persistent storage.
  346. * If any change is made to the authorization data, please make
  347. * sure you call this method to save the changed data into persistent storage.
  348. */
  349. public function save()
  350. {
  351. $items=array();
  352. foreach($this->_items as $name=>$item)
  353. {
  354. $items[$name]=array(
  355. 'type'=>$item->getType(),
  356. 'description'=>$item->getDescription(),
  357. 'bizRule'=>$item->getBizRule(),
  358. 'data'=>$item->getData(),
  359. );
  360. if(isset($this->_children[$name]))
  361. {
  362. foreach($this->_children[$name] as $child)
  363. $items[$name]['children'][]=$child->getName();
  364. }
  365. }
  366. foreach($this->_assignments as $userId=>$assignments)
  367. {
  368. foreach($assignments as $name=>$assignment)
  369. {
  370. if(isset($items[$name]))
  371. {
  372. $items[$name]['assignments'][$userId]=array(
  373. 'bizRule'=>$assignment->getBizRule(),
  374. 'data'=>$assignment->getData(),
  375. );
  376. }
  377. }
  378. }
  379. $this->saveToFile($items,$this->authFile);
  380. }
  381. /**
  382. * Loads authorization data.
  383. */
  384. public function load()
  385. {
  386. $this->clearAll();
  387. $items=$this->loadFromFile($this->authFile);
  388. foreach($items as $name=>$item)
  389. $this->_items[$name]=new CAuthItem($this,$name,$item['type'],$item['description'],$item['bizRule'],$item['data']);
  390. foreach($items as $name=>$item)
  391. {
  392. if(isset($item['children']))
  393. {
  394. foreach($item['children'] as $childName)
  395. {
  396. if(isset($this->_items[$childName]))
  397. $this->_children[$name][$childName]=$this->_items[$childName];
  398. }
  399. }
  400. if(isset($item['assignments']))
  401. {
  402. foreach($item['assignments'] as $userId=>$assignment)
  403. {
  404. $this->_assignments[$userId][$name]=new CAuthAssignment($this,$name,$userId,$assignment['bizRule'],$assignment['data']);
  405. }
  406. }
  407. }
  408. }
  409. /**
  410. * Removes all authorization data.
  411. */
  412. public function clearAll()
  413. {
  414. $this->clearAuthAssignments();
  415. $this->_children=array();
  416. $this->_items=array();
  417. }
  418. /**
  419. * Removes all authorization assignments.
  420. */
  421. public function clearAuthAssignments()
  422. {
  423. $this->_assignments=array();
  424. }
  425. /**
  426. * Checks whether there is a loop in the authorization item hierarchy.
  427. * @param string $itemName parent item name
  428. * @param string $childName the name of the child item that is to be added to the hierarchy
  429. * @return boolean whether a loop exists
  430. */
  431. protected function detectLoop($itemName,$childName)
  432. {
  433. if($childName===$itemName)
  434. return true;
  435. if(!isset($this->_children[$childName], $this->_items[$itemName]))
  436. return false;
  437. foreach($this->_children[$childName] as $child)
  438. {
  439. if($this->detectLoop($itemName,$child->getName()))
  440. return true;
  441. }
  442. return false;
  443. }
  444. /**
  445. * Loads the authorization data from a PHP script file.
  446. * @param string $file the file path.
  447. * @return array the authorization data
  448. * @see saveToFile
  449. */
  450. protected function loadFromFile($file)
  451. {
  452. if(is_file($file))
  453. return require($file);
  454. else
  455. return array();
  456. }
  457. /**
  458. * Saves the authorization data to a PHP script file.
  459. * @param array $data the authorization data
  460. * @param string $file the file path.
  461. * @see loadFromFile
  462. */
  463. protected function saveToFile($data,$file)
  464. {
  465. file_put_contents($file,"<?php\nreturn ".var_export($data,true).";\n");
  466. }
  467. }