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

/application/libraries/joomla/access/access.php

https://github.com/nikosdion/Akeeba-Example
PHP | 427 lines | 216 code | 59 blank | 152 comment | 26 complexity | 38725d7247faa27e898298fcdc34faa9 MD5 | raw file
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Access
  5. *
  6. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die();
  10. jimport('joomla.access.rules');
  11. jimport('joomla.utilities.arrayhelper');
  12. /**
  13. * Class that handles all access authorisation routines.
  14. *
  15. * @package Joomla.Platform
  16. * @subpackage Access
  17. * @since 11.1
  18. */
  19. class JAccess
  20. {
  21. /**
  22. * Array of view levels
  23. *
  24. * @var array
  25. * @since 11.1
  26. */
  27. protected static $viewLevels = array();
  28. /**
  29. * Array of rules for the asset
  30. *
  31. * @var array
  32. * @since 11.1
  33. */
  34. protected static $assetRules = array();
  35. /**
  36. * Method to check if a user is authorised to perform an action, optionally on an asset.
  37. *
  38. * @param integer $userId Id of the user for which to check authorisation.
  39. * @param string $action The name of the action to authorise.
  40. * @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node.
  41. *
  42. * @return boolean True if authorised.
  43. *
  44. * @since 11.1
  45. */
  46. public static function check($userId, $action, $asset = null)
  47. {
  48. // Sanitise inputs.
  49. $userId = (int) $userId;
  50. $action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action)));
  51. $asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset)));
  52. // Default to the root asset node.
  53. if (empty($asset))
  54. {
  55. $asset = 1;
  56. }
  57. // Get the rules for the asset recursively to root if not already retrieved.
  58. if (empty(self::$assetRules[$asset]))
  59. {
  60. self::$assetRules[$asset] = self::getAssetRules($asset, true);
  61. }
  62. // Get all groups against which the user is mapped.
  63. $identities = self::getGroupsByUser($userId);
  64. array_unshift($identities, $userId * -1);
  65. return self::$assetRules[$asset]->allow($action, $identities);
  66. }
  67. /**
  68. * Method to check if a group is authorised to perform an action, optionally on an asset.
  69. *
  70. * @param integer $groupId The path to the group for which to check authorisation.
  71. * @param string $action The name of the action to authorise.
  72. * @param mixed $asset Integer asset id or the name of the asset as a string. Defaults to the global asset node.
  73. *
  74. * @return boolean True if authorised.
  75. *
  76. * @since 11.1
  77. */
  78. public static function checkGroup($groupId, $action, $asset = null)
  79. {
  80. // Sanitize inputs.
  81. $groupId = (int) $groupId;
  82. $action = strtolower(preg_replace('#[\s\-]+#', '.', trim($action)));
  83. $asset = strtolower(preg_replace('#[\s\-]+#', '.', trim($asset)));
  84. // Get group path for group
  85. $groupPath = self::getGroupPath($groupId);
  86. // Default to the root asset node.
  87. if (empty($asset))
  88. {
  89. $asset = 1;
  90. }
  91. // Get the rules for the asset recursively to root if not already retrieved.
  92. if (empty(self::$assetRules[$asset]))
  93. {
  94. self::$assetRules[$asset] = self::getAssetRules($asset, true);
  95. }
  96. return self::$assetRules[$asset]->allow($action, $groupPath);
  97. }
  98. /**
  99. * Gets the parent groups that a leaf group belongs to in its branch back to the root of the tree
  100. * (including the leaf group id).
  101. *
  102. * @param mixed $groupId An integer or array of integers representing the identities to check.
  103. *
  104. * @return mixed True if allowed, false for an explicit deny, null for an implicit deny.
  105. *
  106. * @since 11.1
  107. */
  108. protected static function getGroupPath($groupId)
  109. {
  110. static $groups, $paths;
  111. // Preload all groups
  112. if (empty($groups))
  113. {
  114. $db = JFactory::getDbo();
  115. $query = $db->getQuery(true)
  116. ->select('parent.id, parent.lft, parent.rgt')
  117. ->from('#__usergroups AS parent')
  118. ->order('parent.lft');
  119. $db->setQuery($query);
  120. $groups = $db->loadObjectList('id');
  121. }
  122. // Make sure groupId is valid
  123. if (!array_key_exists($groupId, $groups))
  124. {
  125. return array();
  126. }
  127. // Get parent groups and leaf group
  128. if (!isset($paths[$groupId]))
  129. {
  130. $paths[$groupId] = array();
  131. foreach ($groups as $group)
  132. {
  133. if ($group->lft <= $groups[$groupId]->lft && $group->rgt >= $groups[$groupId]->rgt)
  134. {
  135. $paths[$groupId][] = $group->id;
  136. }
  137. }
  138. }
  139. return $paths[$groupId];
  140. }
  141. /**
  142. * Method to return the JRules object for an asset. The returned object can optionally hold
  143. * only the rules explicitly set for the asset or the summation of all inherited rules from
  144. * parent assets and explicit rules.
  145. *
  146. * @param mixed $asset Integer asset id or the name of the asset as a string.
  147. * @param boolean $recursive True to return the rules object with inherited rules.
  148. *
  149. * @return JRules JRules object for the asset.
  150. *
  151. * @since 11.1
  152. */
  153. public static function getAssetRules($asset, $recursive = false)
  154. {
  155. // Get the database connection object.
  156. $db = JFactory::getDbo();
  157. // Build the database query to get the rules for the asset.
  158. $query = $db->getQuery(true);
  159. $query->select($recursive ? 'b.rules' : 'a.rules');
  160. $query->from('#__assets AS a');
  161. // If the asset identifier is numeric assume it is a primary key, else lookup by name.
  162. if (is_numeric($asset))
  163. {
  164. $query->where('a.id = ' . (int) $asset);
  165. }
  166. else
  167. {
  168. $query->where('a.name = ' . $db->quote($asset));
  169. }
  170. // If we want the rules cascading up to the global asset node we need a self-join.
  171. if ($recursive)
  172. {
  173. $query->leftJoin('#__assets AS b ON b.lft <= a.lft AND b.rgt >= a.rgt');
  174. $query->order('b.lft');
  175. }
  176. // Execute the query and load the rules from the result.
  177. $db->setQuery($query);
  178. $result = $db->loadColumn();
  179. // Get the root even if the asset is not found and in recursive mode
  180. if ($recursive && empty($result))
  181. {
  182. $query = $db->getQuery(true);
  183. $query->select('rules');
  184. $query->from('#__assets');
  185. $query->where('parent_id = 0');
  186. $db->setQuery($query);
  187. $result = $db->loadColumn();
  188. }
  189. // Instantiate and return the JRules object for the asset rules.
  190. $rules = new JRules();
  191. $rules->mergeCollection($result);
  192. return $rules;
  193. }
  194. /**
  195. * Method to return a list of user groups mapped to a user. The returned list can optionally hold
  196. * only the groups explicitly mapped to the user or all groups both explicitly mapped and inherited
  197. * by the user.
  198. *
  199. * @param integer $userId Id of the user for which to get the list of groups.
  200. * @param boolean $recursive True to include inherited user groups.
  201. *
  202. * @return array List of user group ids to which the user is mapped.
  203. *
  204. * @since 11.1
  205. */
  206. public static function getGroupsByUser($userId, $recursive = true)
  207. {
  208. static $results = array();
  209. // Creates a simple unique string for each parameter combination:
  210. $storeId = $userId . ':' . (int) $recursive;
  211. if (!isset($results[$storeId]))
  212. {
  213. // Guest user
  214. if (empty($userId))
  215. {
  216. $result = array(JComponentHelper::getParams('com_users')->get('guest_usergroup', 1));
  217. }
  218. // Registered user
  219. else
  220. {
  221. $db = JFactory::getDbo();
  222. // Build the database query to get the rules for the asset.
  223. $query = $db->getQuery(true);
  224. $query->select($recursive ? 'b.id' : 'a.id');
  225. $query->from('#__user_usergroup_map AS map');
  226. $query->where('map.user_id = ' . (int) $userId);
  227. $query->leftJoin('#__usergroups AS a ON a.id = map.group_id');
  228. // If we want the rules cascading up to the global asset node we need a self-join.
  229. if ($recursive)
  230. {
  231. $query->leftJoin('#__usergroups AS b ON b.lft <= a.lft AND b.rgt >= a.rgt');
  232. }
  233. // Execute the query and load the rules from the result.
  234. $db->setQuery($query);
  235. $result = $db->loadColumn();
  236. // Clean up any NULL or duplicate values, just in case
  237. JArrayHelper::toInteger($result);
  238. if (empty($result))
  239. {
  240. $result = array('1');
  241. }
  242. else
  243. {
  244. $result = array_unique($result);
  245. }
  246. }
  247. $results[$storeId] = $result;
  248. }
  249. return $results[$storeId];
  250. }
  251. /**
  252. * Method to return a list of user Ids contained in a Group
  253. *
  254. * @param integer $groupId The group Id
  255. * @param boolean $recursive Recursively include all child groups (optional)
  256. *
  257. * @return array
  258. *
  259. * @since 11.1
  260. * @todo This method should move somewhere else
  261. */
  262. public static function getUsersByGroup($groupId, $recursive = false)
  263. {
  264. // Get a database object.
  265. $db = JFactory::getDbo();
  266. $test = $recursive ? '>=' : '=';
  267. // First find the users contained in the group
  268. $query = $db->getQuery(true);
  269. $query->select('DISTINCT(user_id)');
  270. $query->from('#__usergroups as ug1');
  271. $query->join('INNER', '#__usergroups AS ug2 ON ug2.lft' . $test . 'ug1.lft AND ug1.rgt' . $test . 'ug2.rgt');
  272. $query->join('INNER', '#__user_usergroup_map AS m ON ug2.id=m.group_id');
  273. $query->where('ug1.id=' . $db->Quote($groupId));
  274. $db->setQuery($query);
  275. $result = $db->loadColumn();
  276. // Clean up any NULL values, just in case
  277. JArrayHelper::toInteger($result);
  278. return $result;
  279. }
  280. /**
  281. * Method to return a list of view levels for which the user is authorised.
  282. *
  283. * @param integer $userId Id of the user for which to get the list of authorised view levels.
  284. *
  285. * @return array List of view levels for which the user is authorised.
  286. *
  287. * @since 11.1
  288. */
  289. public static function getAuthorisedViewLevels($userId)
  290. {
  291. // Get all groups that the user is mapped to recursively.
  292. $groups = self::getGroupsByUser($userId);
  293. // Only load the view levels once.
  294. if (empty(self::$viewLevels))
  295. {
  296. // Get a database object.
  297. $db = JFactory::getDBO();
  298. // Build the base query.
  299. $query = $db->getQuery(true);
  300. $query->select('id, rules');
  301. $query->from($query->qn('#__viewlevels'));
  302. // Set the query for execution.
  303. $db->setQuery((string) $query);
  304. // Build the view levels array.
  305. foreach ($db->loadAssocList() as $level)
  306. {
  307. self::$viewLevels[$level['id']] = (array) json_decode($level['rules']);
  308. }
  309. }
  310. // Initialise the authorised array.
  311. $authorised = array(1);
  312. // Find the authorised levels.
  313. foreach (self::$viewLevels as $level => $rule)
  314. {
  315. foreach ($rule as $id)
  316. {
  317. if (($id < 0) && (($id * -1) == $userId))
  318. {
  319. $authorised[] = $level;
  320. break;
  321. }
  322. // Check to see if the group is mapped to the level.
  323. elseif (($id >= 0) && in_array($id, $groups))
  324. {
  325. $authorised[] = $level;
  326. break;
  327. }
  328. }
  329. }
  330. return $authorised;
  331. }
  332. /**
  333. * Method to return a list of actions for which permissions can be set given a component and section.
  334. *
  335. * @param string $component The component from which to retrieve the actions.
  336. * @param string $section The name of the section within the component from which to retrieve the actions.
  337. *
  338. * @return array List of actions available for the given component and section.
  339. *
  340. * @since 11.1
  341. *
  342. * @todo Need to decouple this method from the CMS. Maybe check if $component is a
  343. * valid file (or create a getActionsFromFile method).
  344. */
  345. public static function getActions($component, $section = 'component')
  346. {
  347. $actions = array();
  348. if (defined('JPATH_ADMINISTRATOR') && is_file(JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml'))
  349. {
  350. $xml = simplexml_load_file(JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml');
  351. foreach ($xml->children() as $child)
  352. {
  353. if ($section == (string) $child['name'])
  354. {
  355. foreach ($child->children() as $action)
  356. {
  357. $actions[] = (object) array(
  358. 'name' => (string) $action['name'],
  359. 'title' => (string) $action['title'],
  360. 'description' => (string) $action['description']);
  361. }
  362. break;
  363. }
  364. }
  365. }
  366. return $actions;
  367. }
  368. }