summaryrefslogtreecommitdiffstats
path: root/ACL.php
diff options
context:
space:
mode:
authorMichael Francis <edude03@gmail.com>2011-05-28 13:28:16 -0400
committerMichael Francis <edude03@gmail.com>2011-05-28 13:28:16 -0400
commit2389d66da849798f8d4ec5f10e3b07c11da49185 (patch)
treee22556d12982395b469a23420c662662e3e064cc /ACL.php
downloadotakuhub-2389d66da849798f8d4ec5f10e3b07c11da49185.tar.xz
Initial Commit
Diffstat (limited to 'ACL.php')
-rw-r--r--ACL.php319
1 files changed, 319 insertions, 0 deletions
diff --git a/ACL.php b/ACL.php
new file mode 100644
index 0000000..aacd406
--- /dev/null
+++ b/ACL.php
@@ -0,0 +1,319 @@
+To Configure
+
+<?php
+
+Access::config(array(
+ 'permissions' => array(
+ 'adapter' => 'Permissions',
+ 'model' => 'app\models\Perms',
+ 'defaultNoUser' => array(),
+ 'defaultUser' => array(
+ 'route' => array(
+ 'users' => array(
+ 'logout', 'account'
+ )
+ )
+ ),
+ 'userIdentifier' => 'PrincipalID'
+ )
+));
+
+Perms::applyFilter('find', function($self, $params, $chain) {
+ if($params['type'] != 'first') {
+ return $chain->next($self, $params, $chain);
+ }
+ $cacheKey = 'permissions_' . $params['options']['conditions']['id'];
+ $cache = Cache::read('default', $cacheKey);
+ if($cache) {
+ return $cache;
+ }
+ $result = $chain->next($self, $params, $chain);
+ Cache::write('default', $cacheKey, $result, '+1 day');
+ return $result;
+});
+?>
+
+<?php
+
+namespace li3_access\extensions\adapter\security\access;
+
+use lithium\core\ConfigException;
+use lithium\util\Set;
+
+class Permissions extends \lithium\core\Object {
+ const pathRoute = 'route';
+ const pathCustom = 'custom';
+ protected $_model = null;
+ public function __construct(array $config = array()) {
+ $defaults = array(
+ 'model' => 'app\models\perms',
+ 'defaultNoUser' => array(),
+ 'defaultUser' => array(),
+ 'userIdentifier' => 'id'
+ );
+ parent::__construct($config + $defaults);
+ $this->_model = $this->_config['model'];
+ }
+
+ /**
+ * @throws \lithium\core\ConfigException
+ * @param $user
+ * @param $request
+ * @param array $options
+ * @return array
+ */
+ public function check($user, $request, array $options = array()) {
+ $config = $this->_config;
+ $model = $this->_model;
+ $params = compact('user', 'request', 'options');
+ return $this->_filter(__METHOD__, $params, function($self, $params) use($config, $model) {
+ $user = $params['user'];
+ $request = $params['request'];
+ $options = $params['options'];
+ $reqIsObject = is_object($request);
+ $path = array();
+
+ switch (true) {
+ case $reqIsObject:
+ $path = array(
+ Permissions::pathRoute,
+ $request->params['controller'],
+ $request->params['action']
+ );
+ break;
+ case (!$reqIsObject && is_string($request)):
+ $path = explode('.', $request);
+ array_unshift($path, Permissions::pathCustom);
+ break;
+ case (!$reqIsObject && is_array($request)):
+ $path = $request;
+ break;
+ }
+ switch(true) {
+ case !$user:
+ $hasAccess = $self->_processPath($path, $config['defaultNoUser']);
+ return $hasAccess ? false : $options;
+ case ($result = $self->_processPath($path, $config['defaultUser'])):
+ return $result ? false : $options;
+ default:
+ $userId = $config['userIdentifier'];
+ if(!isset($user[$userId])) {
+ $message = "The user identifier '{$userId}' is not available.";
+ throw new ConfigException($message);
+ }
+ $perms = $model::find('first', array(
+ 'conditions' => array(
+ 'id' => $user[$userId]
+ )
+ ));
+ if(!$perms) {
+ return false;
+ }
+ $userPath = unserialize($perms->perms);
+ $result = $self->_processPath($path, $userPath);
+ return $result ? array() : $options;
+ }
+ });
+ }
+
+ /**
+ * Adds a custom route to the users permission list.
+ *
+ * $customRoute is formatted as a dot path string, this is done as 'foo.bar.baz' for example.
+ * Asterisks are usable at the end of the path however not in the middle. A user with access
+ * to 'foo.bar.*' will have access to foo.bar.baz, foo.bar.aaa etc.
+ *
+ * @param $user
+ * @param $customRoute
+ * @return bool
+ */
+ public function addCustomPath($user, $customRoute) {
+ if(!is_string($customRoute)) {
+ return false;
+ }
+ $parts = explode('.', $customRoute);
+ $value = array_pop($parts);
+ $parts = array_merge((array)self::pathCustom, $parts, (array)0);
+ return $this->add($user, Set::expand(array(implode('.', $parts) => $value)));
+ }
+
+ /**
+ * Adds an action to the users permission list. If the action is set to * the user will have
+ * access to all of the controllers actions.
+ */
+ public function addAction($user, $controller, $action) {
+ return $this->add($user, array(
+ self::pathRoute => array(
+ $controller => array(
+ $action
+ )
+ )
+ ));
+ }
+
+ /**
+ * $user must contain the 'userIdentifier' key defined in config
+ * $paths are the paths which are to be added this is an array representation of the path and
+ * is from the origin, so 'route' or 'custom' must be specified. Multiple paths can be defined
+ * using this function
+ *
+ * @throws \lithium\core\ConfigException
+ * @param $user
+ * @param array $paths
+ * @return bool
+ */
+ public function add($user, array $paths = array()) {
+ $model = $this->_model;
+ $userId = $this->_config['userIdentifier'];
+ $params = compact('model', 'userId', 'user', 'paths');
+ return $this->_filter(__METHOD__, $params, function($self, $params) {
+ $model = $params['model'];
+ $userId = $params['userId'];
+ $user = $params['user'];
+ $paths = $params['paths'];
+
+ if(!isset($user[$userId])) {
+ throw new ConfigException("The user identifier '{$userId}' is not available.");
+ }
+ $result = $model::find('first', array(
+ 'conditions' => array(
+ 'id' => $user[$userId]
+ )
+ ));
+ if(!$result) {
+ $perms = $model::create(array(
+ 'id' => $user[$userId],
+ 'perms' => serialize($paths)
+ ));
+ return $perms->save();
+ }
+ $allowedPaths = unserialize($result->perms);
+ $allowedPaths = array_merge_recursive($allowedPaths, $paths);
+ $result->perms = serialize($allowedPaths);
+ return $result->save();
+ });
+ }
+
+ public function removeCustomPath($user, $customRoute) {
+ if(!is_string($customRoute)) {
+ return false;
+ }
+ $parts = explode('.', $customRoute);
+ $value = array_pop($parts);
+ $parts = array_merge((array)self::pathCustom, $parts, (array)0);
+ return $this->remove($user, Set::expand(array(implode('.', $parts) => $value)));
+ }
+
+ /**
+ * Removes an action from a users permission list. Setting action to * removes all actions
+ * in the controller thus removing the controller from the users permission list.
+ */
+ public function removeAction($user, $controller, $action) {
+ return $this->remove($user, array(
+ self::pathRoute => array(
+ $controller => array(
+ $action
+ )
+ )
+ ));
+ }
+
+ /**
+ * use this to remove permissions from a user, multiple permissions can be defined in the paths
+ * array. The user must have the configured userIdentifier available.
+ *
+ * @throws \lithium\core\ConfigException
+ * @param $user
+ * @param array $paths
+ * @return bool
+ */
+ public function remove($user, array $paths = array()) {
+ $model = $this->_model;
+ $userId = $this->_config['userIdentifier'];
+ $params = compact('model', 'userId', 'user', 'paths');
+ return $this->_filter(__METHOD__, $params, function($self, $params) {
+ $model = $params['model'];
+ $userId = $params['userId'];
+ $user = $params['user'];
+ $paths = $params['paths'];
+
+ if (!isset($user[$userId])) {
+ throw new ConfigException("The user identifier '{$userId}' is not available.");
+ }
+ $result = $model::find('first', array(
+ 'conditions' => array(
+ 'id' => $user[$userId]
+ )
+ ));
+ if (!$result) {
+ return true;
+ }
+ $allowedPaths = unserialize($result->perms);
+ $pathsFlat = Set::flatten($paths);
+ foreach ($pathsFlat as $path => $value) {
+ $pointer = &$allowedPaths;
+ $pathParts = explode('.', $path);
+ array_pop($pathParts);
+ foreach ($pathParts as $pathPart) {
+ if (!isset($pointer[$pathPart])) {
+ unset($pointer);
+ $pointer = null;
+ break;
+ }
+ $pointer = &$pointer[$pathPart];
+ }
+ switch(true) {
+ case !$pointer:
+ break;
+ case $value == '*':
+ $pointer = null;
+ break;
+ case (($index = array_search($value, $pointer)) !== false):
+ unset($pointer[$index]);
+ break;
+ }
+ }
+ $result->perms = serialize($self->_cleanPaths($allowedPaths));
+ return $result->save();
+ });
+ }
+
+ public function listPerms($user) {
+ $userId = $user[$this->_config['userIdentifier']];
+ $model = $this->_model;
+ $result = $model::find('first', array(
+ 'conditions' => array(
+ 'id' => $userId
+ )
+ ));
+ return $result ? unserialize($result->perms) : array();
+ }
+
+ public function _cleanPaths($paths) {
+ foreach ($paths as &$path) {
+ if (is_array($path)) {
+ $path = $this->_cleanPaths($path);
+ }
+ }
+ return array_filter($paths);
+ }
+
+ public function _processPath($path, &$allowedPaths) {
+ $pointer = &$allowedPaths;
+ foreach($path as $item) {
+ switch(true) {
+ case (in_array('*', $pointer)):
+ return true;
+ case (in_array($item, $pointer)):
+ $pointer = array();
+ continue;
+ case (!isset($pointer[$item])):
+ return false;
+ }
+ $pointer = &$pointer[$item];
+ }
+ return true;
+ }
+}
+
+?> \ No newline at end of file