ACL.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. To Configure
  2. <?php
  3. Access::config(array(
  4. 'permissions' => array(
  5. 'adapter' => 'Permissions',
  6. 'model' => 'app\models\Perms',
  7. 'defaultNoUser' => array(),
  8. 'defaultUser' => array(
  9. 'route' => array(
  10. 'users' => array(
  11. 'logout', 'account'
  12. )
  13. )
  14. ),
  15. 'userIdentifier' => 'PrincipalID'
  16. )
  17. ));
  18. Perms::applyFilter('find', function($self, $params, $chain) {
  19. if($params['type'] != 'first') {
  20. return $chain->next($self, $params, $chain);
  21. }
  22. $cacheKey = 'permissions_' . $params['options']['conditions']['id'];
  23. $cache = Cache::read('default', $cacheKey);
  24. if($cache) {
  25. return $cache;
  26. }
  27. $result = $chain->next($self, $params, $chain);
  28. Cache::write('default', $cacheKey, $result, '+1 day');
  29. return $result;
  30. });
  31. ?>
  32. <?php
  33. namespace li3_access\extensions\adapter\security\access;
  34. use lithium\core\ConfigException;
  35. use lithium\util\Set;
  36. class Permissions extends \lithium\core\Object {
  37. const pathRoute = 'route';
  38. const pathCustom = 'custom';
  39. protected $_model = null;
  40. public function __construct(array $config = array()) {
  41. $defaults = array(
  42. 'model' => 'app\models\perms',
  43. 'defaultNoUser' => array(),
  44. 'defaultUser' => array(),
  45. 'userIdentifier' => 'id'
  46. );
  47. parent::__construct($config + $defaults);
  48. $this->_model = $this->_config['model'];
  49. }
  50. /**
  51. * @throws \lithium\core\ConfigException
  52. * @param $user
  53. * @param $request
  54. * @param array $options
  55. * @return array
  56. */
  57. public function check($user, $request, array $options = array()) {
  58. $config = $this->_config;
  59. $model = $this->_model;
  60. $params = compact('user', 'request', 'options');
  61. return $this->_filter(__METHOD__, $params, function($self, $params) use($config, $model) {
  62. $user = $params['user'];
  63. $request = $params['request'];
  64. $options = $params['options'];
  65. $reqIsObject = is_object($request);
  66. $path = array();
  67. switch (true) {
  68. case $reqIsObject:
  69. $path = array(
  70. Permissions::pathRoute,
  71. $request->params['controller'],
  72. $request->params['action']
  73. );
  74. break;
  75. case (!$reqIsObject && is_string($request)):
  76. $path = explode('.', $request);
  77. array_unshift($path, Permissions::pathCustom);
  78. break;
  79. case (!$reqIsObject && is_array($request)):
  80. $path = $request;
  81. break;
  82. }
  83. switch(true) {
  84. case !$user:
  85. $hasAccess = $self->_processPath($path, $config['defaultNoUser']);
  86. return $hasAccess ? false : $options;
  87. case ($result = $self->_processPath($path, $config['defaultUser'])):
  88. return $result ? false : $options;
  89. default:
  90. $userId = $config['userIdentifier'];
  91. if(!isset($user[$userId])) {
  92. $message = "The user identifier '{$userId}' is not available.";
  93. throw new ConfigException($message);
  94. }
  95. $perms = $model::find('first', array(
  96. 'conditions' => array(
  97. 'id' => $user[$userId]
  98. )
  99. ));
  100. if(!$perms) {
  101. return false;
  102. }
  103. $userPath = unserialize($perms->perms);
  104. $result = $self->_processPath($path, $userPath);
  105. return $result ? array() : $options;
  106. }
  107. });
  108. }
  109. /**
  110. * Adds a custom route to the users permission list.
  111. *
  112. * $customRoute is formatted as a dot path string, this is done as 'foo.bar.baz' for example.
  113. * Asterisks are usable at the end of the path however not in the middle. A user with access
  114. * to 'foo.bar.*' will have access to foo.bar.baz, foo.bar.aaa etc.
  115. *
  116. * @param $user
  117. * @param $customRoute
  118. * @return bool
  119. */
  120. public function addCustomPath($user, $customRoute) {
  121. if(!is_string($customRoute)) {
  122. return false;
  123. }
  124. $parts = explode('.', $customRoute);
  125. $value = array_pop($parts);
  126. $parts = array_merge((array)self::pathCustom, $parts, (array)0);
  127. return $this->add($user, Set::expand(array(implode('.', $parts) => $value)));
  128. }
  129. /**
  130. * Adds an action to the users permission list. If the action is set to * the user will have
  131. * access to all of the controllers actions.
  132. */
  133. public function addAction($user, $controller, $action) {
  134. return $this->add($user, array(
  135. self::pathRoute => array(
  136. $controller => array(
  137. $action
  138. )
  139. )
  140. ));
  141. }
  142. /**
  143. * $user must contain the 'userIdentifier' key defined in config
  144. * $paths are the paths which are to be added this is an array representation of the path and
  145. * is from the origin, so 'route' or 'custom' must be specified. Multiple paths can be defined
  146. * using this function
  147. *
  148. * @throws \lithium\core\ConfigException
  149. * @param $user
  150. * @param array $paths
  151. * @return bool
  152. */
  153. public function add($user, array $paths = array()) {
  154. $model = $this->_model;
  155. $userId = $this->_config['userIdentifier'];
  156. $params = compact('model', 'userId', 'user', 'paths');
  157. return $this->_filter(__METHOD__, $params, function($self, $params) {
  158. $model = $params['model'];
  159. $userId = $params['userId'];
  160. $user = $params['user'];
  161. $paths = $params['paths'];
  162. if(!isset($user[$userId])) {
  163. throw new ConfigException("The user identifier '{$userId}' is not available.");
  164. }
  165. $result = $model::find('first', array(
  166. 'conditions' => array(
  167. 'id' => $user[$userId]
  168. )
  169. ));
  170. if(!$result) {
  171. $perms = $model::create(array(
  172. 'id' => $user[$userId],
  173. 'perms' => serialize($paths)
  174. ));
  175. return $perms->save();
  176. }
  177. $allowedPaths = unserialize($result->perms);
  178. $allowedPaths = array_merge_recursive($allowedPaths, $paths);
  179. $result->perms = serialize($allowedPaths);
  180. return $result->save();
  181. });
  182. }
  183. public function removeCustomPath($user, $customRoute) {
  184. if(!is_string($customRoute)) {
  185. return false;
  186. }
  187. $parts = explode('.', $customRoute);
  188. $value = array_pop($parts);
  189. $parts = array_merge((array)self::pathCustom, $parts, (array)0);
  190. return $this->remove($user, Set::expand(array(implode('.', $parts) => $value)));
  191. }
  192. /**
  193. * Removes an action from a users permission list. Setting action to * removes all actions
  194. * in the controller thus removing the controller from the users permission list.
  195. */
  196. public function removeAction($user, $controller, $action) {
  197. return $this->remove($user, array(
  198. self::pathRoute => array(
  199. $controller => array(
  200. $action
  201. )
  202. )
  203. ));
  204. }
  205. /**
  206. * use this to remove permissions from a user, multiple permissions can be defined in the paths
  207. * array. The user must have the configured userIdentifier available.
  208. *
  209. * @throws \lithium\core\ConfigException
  210. * @param $user
  211. * @param array $paths
  212. * @return bool
  213. */
  214. public function remove($user, array $paths = array()) {
  215. $model = $this->_model;
  216. $userId = $this->_config['userIdentifier'];
  217. $params = compact('model', 'userId', 'user', 'paths');
  218. return $this->_filter(__METHOD__, $params, function($self, $params) {
  219. $model = $params['model'];
  220. $userId = $params['userId'];
  221. $user = $params['user'];
  222. $paths = $params['paths'];
  223. if (!isset($user[$userId])) {
  224. throw new ConfigException("The user identifier '{$userId}' is not available.");
  225. }
  226. $result = $model::find('first', array(
  227. 'conditions' => array(
  228. 'id' => $user[$userId]
  229. )
  230. ));
  231. if (!$result) {
  232. return true;
  233. }
  234. $allowedPaths = unserialize($result->perms);
  235. $pathsFlat = Set::flatten($paths);
  236. foreach ($pathsFlat as $path => $value) {
  237. $pointer = &$allowedPaths;
  238. $pathParts = explode('.', $path);
  239. array_pop($pathParts);
  240. foreach ($pathParts as $pathPart) {
  241. if (!isset($pointer[$pathPart])) {
  242. unset($pointer);
  243. $pointer = null;
  244. break;
  245. }
  246. $pointer = &$pointer[$pathPart];
  247. }
  248. switch(true) {
  249. case !$pointer:
  250. break;
  251. case $value == '*':
  252. $pointer = null;
  253. break;
  254. case (($index = array_search($value, $pointer)) !== false):
  255. unset($pointer[$index]);
  256. break;
  257. }
  258. }
  259. $result->perms = serialize($self->_cleanPaths($allowedPaths));
  260. return $result->save();
  261. });
  262. }
  263. public function listPerms($user) {
  264. $userId = $user[$this->_config['userIdentifier']];
  265. $model = $this->_model;
  266. $result = $model::find('first', array(
  267. 'conditions' => array(
  268. 'id' => $userId
  269. )
  270. ));
  271. return $result ? unserialize($result->perms) : array();
  272. }
  273. public function _cleanPaths($paths) {
  274. foreach ($paths as &$path) {
  275. if (is_array($path)) {
  276. $path = $this->_cleanPaths($path);
  277. }
  278. }
  279. return array_filter($paths);
  280. }
  281. public function _processPath($path, &$allowedPaths) {
  282. $pointer = &$allowedPaths;
  283. foreach($path as $item) {
  284. switch(true) {
  285. case (in_array('*', $pointer)):
  286. return true;
  287. case (in_array($item, $pointer)):
  288. $pointer = array();
  289. continue;
  290. case (!isset($pointer[$item])):
  291. return false;
  292. }
  293. $pointer = &$pointer[$item];
  294. }
  295. return true;
  296. }
  297. }
  298. ?>