From: Michael M Slusarz Date: Fri, 20 Nov 2009 17:26:28 +0000 (-0700) Subject: Import Horde_Perms from CVS HEAD. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=7c59a447b1b3eba5bad16f7fedf99695599193e2;p=horde.git Import Horde_Perms from CVS HEAD. --- diff --git a/framework/Auth/lib/Horde/Auth.php b/framework/Auth/lib/Horde/Auth.php index f63075852..2a836ec4c 100644 --- a/framework/Auth/lib/Horde/Auth.php +++ b/framework/Auth/lib/Horde/Auth.php @@ -831,9 +831,8 @@ class Horde_Auth * * @param string $permission Allow users with this permission admin access * in the current context. - * @param integer $permlevel The level of permissions to check for - * (PERMS_EDIT, PERMS_DELETE, etc). Defaults - * to PERMS_EDIT. + * @param integer $permlevel The level of permissions to check for. + * Defaults to Horde_Perms::EDIT. * @param string $user The user to check. Defaults to * self::getAuth(). * @@ -854,7 +853,7 @@ class Horde_Auth if (!is_null($permission)) { if (is_null($permlevel)) { - $permlevel = PERMS_EDIT; + $permlevel = Horde_Perms::EDIT; } return $GLOBALS['perms']->hasPermission($permission, $user, $permlevel); } diff --git a/framework/Core/lib/Horde/Menu.php b/framework/Core/lib/Horde/Menu.php index 036d17666..746409c1f 100644 --- a/framework/Core/lib/Horde/Menu.php +++ b/framework/Core/lib/Horde/Menu.php @@ -263,7 +263,7 @@ class Horde_Menu if (isset($conf['menu']['apps']) && is_array($conf['menu']['apps'])) { foreach ($conf['menu']['apps'] as $app) { - if ($registry->get('status', $app) != 'inactive' && $registry->hasPermission($app, PERMS_SHOW)) { + if ($registry->get('status', $app) != 'inactive' && $registry->hasPermission($app, Horde_Perms::SHOW)) { try { $this->add(Horde::url($registry->getInitialPage($app)), $registry->get('name', $app), $registry->get('icon', $app), ''); } catch (Horde_Exception $e) {} diff --git a/framework/Core/lib/Horde/Registry.php b/framework/Core/lib/Horde/Registry.php index c762a78cf..f3ae178fb 100644 --- a/framework/Core/lib/Horde/Registry.php +++ b/framework/Core/lib/Horde/Registry.php @@ -196,9 +196,9 @@ class Horde_Registry throw new Horde_Exception(_("This system is currently deactivated.")); } - /* Create the global Perms object. */ + /* Create the global permissions object. */ // TODO: Remove(?) - $GLOBALS['perms'] = Perms::singleton(); + $GLOBALS['perms'] = Horde_Perms::singleton(); } /** @@ -411,7 +411,7 @@ class Horde_Registry * applications are defined returns an empty array. */ public function listApps($filter = null, $assoc = false, - $perms = PERMS_SHOW) + $perms = Horde_Perms::SHOW) { $apps = array(); if (is_null($filter)) { @@ -860,7 +860,7 @@ class Horde_Registry * - To all admins. * - To all authenticated users if no permission is set on $app. * - To anyone who is allowed by an explicit ACL on $app. */ - if ($checkPerms && !$this->hasPermission($app, PERMS_READ)) { + if ($checkPerms && !$this->hasPermission($app, Horde_Perms::READ)) { if (!Horde_Auth::isAuthenticated(array('app' => $app))) { throw new Horde_Exception('User is not authorized', self::AUTH_FAILURE); } @@ -975,14 +975,14 @@ class Horde_Registry * * @return boolean Whether access is allowed. */ - public function hasPermission($app, $perms = PERMS_READ) + public function hasPermission($app, $perms = Horde_Perms::READ) { /* Always do isAuthenticated() check first. You can be an admin, but * application auth != Horde admin auth. And there can *never* be * non-SHOW access to an application that requires authentication. */ if (!Horde_Auth::isAuthenticated(array('app' => $app)) && Horde_Auth::requireAuth($app) && - ($perms != PERMS_SHOW)) { + ($perms != Horde_Perms::SHOW)) { return false; } diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php index cdf6c2723..d3c9cf767 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Folder.php @@ -1200,7 +1200,7 @@ class Horde_Kolab_Storage_Folder * Checks to see if a user has a given permission. * * @param string $userid The userid of the user. - * @param integer $permission A PERMS_* constant to test for. + * @param integer $permission A Horde_Perms::* constant to test for. * @param string $creator The creator of the shared object. * * @return boolean|PEAR_Error Whether or not $userid has $permission. @@ -1233,8 +1233,9 @@ class Horde_Kolab_Storage_Folder } else { $perms = array( 'users' => array( - Horde_Auth::getAuth() => PERMS_SHOW | PERMS_READ | - PERMS_EDIT | PERMS_DELETE)); + Horde_Auth::getAuth() => Horde_Perms::ALL + ) + ); } $this->_perms = new Horde_Kolab_Storage_Permission($this, $perms); } diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php index eea928e44..54276b73f 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Permission.php @@ -19,7 +19,6 @@ require_once 'Horde/Autoloader.php'; /** * Packages that aren't autoloadable yet */ -require_once 'Horde/Perms.php'; require_once 'Horde/Group.php'; /** @@ -156,16 +155,16 @@ class Horde_Kolab_Storage_Permission extends Horde_Permission for ($i = 0, $j = strlen($rights); $i < $j; $i++) { switch ($rights[$i]) { case 'l': - $result |= PERMS_SHOW; + $result |= Horde_Perms::SHOW; break; case 'r': - $result |= PERMS_READ; + $result |= Horde_Perms::READ; break; case 'i': - $result |= PERMS_EDIT; + $result |= Horde_Perms::EDIT; break; case 'd': - $result |= PERMS_DELETE; + $result |= Horde_Perms::DELETE; break; } } @@ -302,16 +301,16 @@ class Horde_Kolab_Storage_Permission extends Horde_Permission { // Convert the horde permission style to IMAP permissions $result = $user == $this->_folder->getOwner() ? 'a' : ''; - if ($perms & PERMS_SHOW) { + if ($perms & Horde_Perms::SHOW) { $result .= 'l'; } - if ($perms & PERMS_READ) { + if ($perms & Horde_Perms::READ) { $result .= 'r'; } - if ($perms & PERMS_EDIT) { + if ($perms & Horde_Perms::EDIT) { $result .= 'iswc'; } - if ($perms & PERMS_DELETE) { + if ($perms & Horde_Perms::DELETE) { $result .= 'd'; } diff --git a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Perms.php b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Perms.php index e722da95f..ab9dcb22a 100644 --- a/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Perms.php +++ b/framework/Kolab_Storage/lib/Horde/Kolab/Storage/Perms.php @@ -1,14 +1,11 @@ _folder->getOwner() ? 'a' : ''; - if ($perms & PERMS_SHOW) { + if ($perms & Horde_Perms::SHOW) { $result .= 'l'; } - if ($perms & PERMS_READ) { + if ($perms & Horde_Perms::READ) { $result .= 'r'; } - if ($perms & PERMS_EDIT) { + if ($perms & Horde_Perms::EDIT) { $result .= 'iswc'; } - if ($perms & PERMS_DELETE) { + if ($perms & Horde_Perms::DELETE) { $result .= 'd'; } diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php index 5fcdafe8c..b5b681f1c 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/PermsTest.php @@ -43,11 +43,7 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase $this->assertEquals(array(), $perms->get('perm')); $permissions = array('users' => array( - 'wrobel' => - PERMS_SHOW | - PERMS_READ | - PERMS_EDIT | - PERMS_DELETE + 'wrobel' => Horde_Perms::ALL )); $perms = new Horde_Kolab_Storage_Permission($folder, $permissions); $this->assertTrue(is_array($perms->get('perm'))); @@ -107,9 +103,9 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase unset($data['guest']); unset($data['default']); unset($data['users']['viewer']); - $data['users']['editor'] = PERMS_SHOW | PERMS_READ | PERMS_EDIT | PERMS_DELETE; - $data['users']['test'] = PERMS_SHOW | PERMS_READ; - $data['groups']['group'] = PERMS_SHOW | PERMS_READ; + $data['users']['editor'] = Horde_Perms::ALL; + $data['users']['test'] = Horde_Perms::SHOW | Horde_Perms::READ; + $data['groups']['group'] = Horde_Perms::SHOW | Horde_Perms::READ; $perms->setData($data); $perms->save(); $this->assertNotContains('anyone', array_keys($folder->acl)); @@ -129,7 +125,7 @@ class Horde_Kolab_Storage_PermsTest extends PHPUnit_Framework_TestCase $folder = new DummyFolder(array(), 'wrobel'); $hperms = new Horde_Permission('test'); - $hperms->addUserPermission('wrobel', PERMS_SHOW, false); + $hperms->addUserPermission('wrobel', Horde_Perms::SHOW, false); $perms = new Horde_Kolab_Storage_Permission($folder, $hperms->data); $perms->save(); $this->assertEquals('al', $folder->acl['wrobel']); diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/Scenario.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/Scenario.php index dd96c61bf..a3af0a786 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/Scenario.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/Scenario.php @@ -2,8 +2,6 @@ /** * Base for PHPUnit scenarios. * - * $Horde: framework/Kolab_Storage/lib/Horde/Kolab/Test/Storage.php,v 1.9 2009/06/24 23:39:23 slusarz Exp $ - * * PHP version 5 * * @category Kolab @@ -16,8 +14,6 @@ /** * Base for PHPUnit scenarios. * - * $Horde: framework/Kolab_Storage/lib/Horde/Kolab/Test/Storage.php,v 1.9 2009/06/24 23:39:23 slusarz Exp $ - * * Copyright 2008-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you @@ -317,8 +313,7 @@ EOD; $this->prepareNotification(); if (!isset($GLOBALS['perms'])) { - include_once 'Horde/Perms.php'; - $GLOBALS['perms'] = Perms::singleton(); + $GLOBALS['perms'] = Horde_Perms::singleton(); } /** Provide the horde registry */ diff --git a/framework/Kolab_Storage/test/Horde/Kolab/Storage/StorageTest.php b/framework/Kolab_Storage/test/Horde/Kolab/Storage/StorageTest.php index 6b89c4630..029178ed5 100644 --- a/framework/Kolab_Storage/test/Horde/Kolab/Storage/StorageTest.php +++ b/framework/Kolab_Storage/test/Horde/Kolab/Storage/StorageTest.php @@ -54,12 +54,12 @@ class Horde_Kolab_Storage_StorageTest extends Horde_Kolab_Storage_Scenario $folder = $this->prepareNewFolder($storage1, 'Contacts', 'contact', true); $perms = $folder->getPermission(); - $perms->addUserPermission('test@example.org', PERMS_SHOW); + $perms->addUserPermission('test@example.org', Horde_Perms::SHOW); $perms->save(); $folder = $this->prepareNewFolder($storage1, 'Calendar', 'event', true); $perms = $folder->getPermission(); - $perms->addUserPermission('test@example.org', PERMS_SHOW); + $perms->addUserPermission('test@example.org', Horde_Perms::SHOW); $perms->save(); /** Prepare a Kolab test storage */ diff --git a/framework/Notification/test/Horde/Notification/Class/Notification/Listener/MobileTest.php b/framework/Notification/test/Horde/Notification/Class/Notification/Listener/MobileTest.php index 9716ecd7c..03db317bc 100644 --- a/framework/Notification/test/Horde/Notification/Class/Notification/Listener/MobileTest.php +++ b/framework/Notification/test/Horde/Notification/Class/Notification/Listener/MobileTest.php @@ -42,8 +42,6 @@ class Horde_Notification_Class_Notification_Listener_MobileTest extends PHPUnit_ $this->markTestSkipped('The Horde_Mobile package is not installed!'); } - /** Loading Horde/Registry.php requires the PERMS_* constants */ - require_once 'Horde/Perms.php'; /** * The listener pulls the registry from global scope to get the image * directory. diff --git a/framework/Notification/test/Horde/Notification/Class/Notification/Listener/StatusTest.php b/framework/Notification/test/Horde/Notification/Class/Notification/Listener/StatusTest.php index 2d1b77fef..f7b3d446b 100644 --- a/framework/Notification/test/Horde/Notification/Class/Notification/Listener/StatusTest.php +++ b/framework/Notification/test/Horde/Notification/Class/Notification/Listener/StatusTest.php @@ -38,8 +38,6 @@ class Horde_Notification_Class_Notification_Listener_StatusTest extends PHPUnit_ $this->markTestSkipped('The Horde_Perms package is not installed!'); } - /** Loading Horde/Registry.php requires the PERMS_* constants */ - require_once 'Horde/Perms.php'; /** * The listener pulls the registry from global scope to get the image * directory. diff --git a/framework/Perms/lib/Horde/Perms.php b/framework/Perms/lib/Horde/Perms.php new file mode 100644 index 000000000..83e455509 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms.php @@ -0,0 +1,516 @@ + + * @author Jan Schneider + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms +{ + /* Existence of object is known - object is shown to user. */ + const SHOW = 2; + /* Contents of the object can be read. */ + const READ = 4; + /* Contents of the object can be edited. */ + const EDIT = 8; + /* The object can be deleted. */ + const DELETE = 16; + + /* A bitmask of all possible permission values. Useful for + * removeXxxPermission(), unsetPerm(), etc. + * 30 = SHOW | READ | EDIT | DELETE */ + const ALL = 30; + + /* The root permission. */ + const ROOT = -1; + + /** + * Caches information about application permissions. + * + * @var array + */ + protected $_appPerms; + + /** + * Singleton instance. + * + * @var array + */ + static protected $_instance = null; + + /** + * Cache for integerToArray(). + * + * @var array + */ + static protected $_itaCache = array(); + + /** + * Attempts to return a concrete instance based on $driver. + * + * @param string $driver The type of the concrete subclass to return. + * The class name is based on the perms driver + * ($driver). The code is dynamically included. + * @param array $params A hash containing any additional configuration + * or connection parameters a subclass might need. + * + * @return Horde_Perms The newly created concrete instance. + * @throws Horde_Perms_Exception + */ + static public function factory($driver = null, $params = null) + { + if (is_null($params)) { + $params = Horde::getDriverConfig('perms', $driver); + } + + if (is_null($driver)) { + $perms = new Perms($params); + } else { + $class = 'Horde_Perms_' . ucfirst(basename($driver)); + if (!class_exists($class)) { + throw new Horde_Perms_Exception('Bad permissions class name: ' . $class); + } + + $perms = new $class($params); + } + + return $perms; + } + + /** + * Attempts to return a reference to a concrete instance. + * It will only create a new instance if no instance currently exists. + * + * This method must be invoked as: $var = Horde_Perms::singleton() + * + * @return Horde_Perms The concrete reference. + * @throws Horde_Perms_Exception + */ + static public function singleton() + { + if (is_null(self::$_instance)) { + $perm_driver = $perm_params = null; + if (empty($GLOBALS['conf']['perms']['driver'])) { + $perm_driver = empty($GLOBALS['conf']['datatree']['driver']) + ? null + : 'datatree'; + } else { + $perm_driver = $GLOBALS['conf']['perms']['driver']; + $perm_params = Horde::getDriverConfig('perms', $perm_driver); + } + + self::$_instance = self::factory($perm_driver, $perm_params); + } + + return self::$_instance; + } + + /** + * Returns the available permissions for a given level. + * + * @param string $name The permission's name. + * + * @return array An array of available permissions and their titles or + * false if not sub permissions exist for this level. + * @throws Horde_Perms_Exception + */ + public function getAvailable($name) + { + if ($name == self::ROOT) { + $name = ''; + } + + if (empty($name)) { + /* No name passed, so top level permissions are requested. These + * can only be applications. */ + $apps = $GLOBALS['registry']->listApps(array('notoolbar', 'active', 'hidden'), true); + foreach (array_keys($apps) as $app) { + $apps[$app] = $GLOBALS['registry']->get('name', $app) . ' (' . $app . ')'; + } + asort($apps); + + return $apps; + } + + /* Name has been passed, explode the name to get all the levels in + * permission being requisted, with the app as the first level. */ + $levels = explode(':', $name); + + /* First level is always app. */ + $app = $levels[0]; + + /* Return empty if no app defined API method for providing + * permission information. */ + if (!$GLOBALS['registry']->hasAppMethod($app, 'perms')) { + return false; + } + + /* Call the app's permission function to return the permissions + * specific to this app. */ + $perms = $this->getApplicationPermissions($app); + + /* Get the part of the app's permissions based on the permission + * name requested. */ + $children = Horde_Array::getElement($perms['tree'], $levels); + if (($children === false) || + !is_array($children) || + !count($children)) { + /* No array of children available for this permission name. */ + return false; + } + + $perms_list = array(); + foreach ($children as $perm_key => $perm_val) { + $perms_list[$perm_key] = $perms['title'][$name . ':' . $perm_key]; + } + + return $perms_list; + } + + /** + * Returns the short name of an object, the last portion of the full name. + * + * @param string $name The name of the object. + * + * @return string The object's short name. + */ + static public function getShortName($name) + { + /* If there are several components to the name, explode and + * get the last one, otherwise just return the name. */ + if (strpos($name, ':') !== false) { + $tmp = explode(':', $name); + return array_pop($tmp); + } + + return $name; + } + + /** + * Given a permission name, returns the title for that permission by + * looking it up in the applications's permission api. + * + * @param string $name The permissions's name. + * + * @return string The title for the permission. + */ + public function getTitle($name) + { + if ($name === self::ROOT) { + return _("All Permissions"); + } + + $levels = explode(':', $name); + if (count($levels) == 1) { + return $GLOBALS['registry']->get('name', $name) . ' (' . $name . ')'; + } + $perm = array_pop($levels); + + /* First level is always app. */ + $app = $levels[0]; + + /* Return empty if no app defined API method for providing permission + * information. */ + if (!$GLOBALS['registry']->hasAppMethod($app, 'perms')) { + return $this->getShortName($name); + } + + $app_perms = $this->getApplicationPermissions($app); + + return isset($app_perms['title'][$name]) + ? $app_perms['title'][$name] . ' (' . $this->getShortName($name) . ')' + : $this->getShortName($name); + } + + /** + * Returns information about permissions implemented by an application. + * + * @param string $app An application name. + * + * @return array Hash with permissions information. + */ + public function getApplicationPermissions($app) + { + if (!isset($this->_appPerms[$app])) { + try { + $this->_appPerms[$app] = $GLOBALS['registry']->callAppMethod($app, 'perms'); + } catch (Horde_Exception $e) { + $this->_appPerms[$app] = array(); + } + } + + return $this->_appPerms[$app]; + } + + /** + * Returns a new permissions object. + * + * @param string $name The permission's name. + * + * @return Horde_Perms_Permission A new permissions object. + * @throws Horde_Perms_Exception + */ + public function newPermission($name) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Returns an object corresponding to the named permission, with the users + * and other data retrieved appropriately. + * + * @param string $name The name of the permission to retrieve. + * + * @return Horde_Perms_Permission A permissions object. + * @throws Horde_Perms_Exception + */ + public function getPermission($name) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Returns an object corresponding to the given unique ID, with the users + * and other data retrieved appropriately. + * + * @param integer $cid The unique ID of the permission to retrieve. + * + * @return Horde_Perms_Permission A permissions object. + * @throws Horde_Perms_Exception + */ + public function getPermissionById($cid) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Adds a permission to the permissions system. The permission must first + * be created with newPermission(), and have any initial users added to + * it, before this function is called. + * + * @param Horde_Perms_Permission $perm The permissions object. + * + * @throws Horde_Perms_Exception + */ + public function addPermission($perm) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Removes a permission from the permissions system permanently. + * + * @param Horde_Perms_Permission $perm The permission to remove. + * @param boolean $force Force to remove every child. + * + * @throws Horde_Perms_Exception + */ + public function removePermission($perm, $force = false) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Finds out what rights the given user has to this object. + * + * @param mixed $permission The full permission name of the object to + * check the permissions of, or the + * Horde_Permissions object. + * @param string $user The user to check for. Defaults to the current + * user. + * @param string $creator The user who created the event. + * + * @return mixed A bitmask of permissions the user has, false if there + * are none. + */ + public function getPermissions($permission, $user = null, $creator = null) + { + if (is_string($permission)) { + try { + $permission = $this->getPermission($permission); + } catch (Horde_Perms_Exception $e) { + Horde::logMessage($e, __FILE__, __LINE__, PEAR_LOG_DEBUG); + return false; + } + } + + if (is_null($user)) { + $user = Horde_Auth::getAuth(); + } + + // If this is a guest user, only check guest permissions. + if (empty($user)) { + return $permission->getGuestPermissions(); + } + + // If $creator was specified, check creator permissions. + // If the user is the creator of the event see if there are creator + // permissions. + if (!is_null($creator) && + strlen($user) && + ($user === $creator) && + (($perms = $permission->getCreatorPermissions()) !== null)) { + return $perms; + } + + // Check user-level permissions. + $userperms = $permission->getUserPermissions(); + if (isset($userperms[$user])) { + return $userperms[$user]; + } + + // If no user permissions are found, try group permissions. + if (isset($permission->data['groups']) && + is_array($permission->data['groups']) && + count($permission->data['groups'])) { + require_once 'Horde/Group.php'; + $groups = Group::singleton(); + + $composite_perm = null; + $type = $permission->get('type'); + foreach ($permission->data['groups'] as $group => $perm) { + if ($groups->userIsInGroup($user, $group)) { + if (is_null($composite_perm)) { + $composite_perm = ($type == 'matrix') ? 0 : array(); + } + + if ($type == 'matrix') { + $composite_perm |= $perm; + } else { + $composite_perm[] = $perm; + } + } + } + + if (!is_null($composite_perm)) { + return $composite_perm; + } + } + + // If there are default permissions, return them. + if (($perms = $permission->getDefaultPermissions()) !== null) { + return $perms; + } + + // Otherwise, deny all permissions to the object. + return false; + } + + /** + * Returns the unique identifier of this permission. + * + * @param Horde_Perms_Permission $permission The permission object to get + * the ID of. + * + * @return integer The unique id. + * @throws Horde_Perms_Exception + */ + public function getPermissionId($permission) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Finds out if the user has the specified rights to the given object. + * + * @param string $permission The permission to check. + * @param string $user The user to check for. + * @param integer $perm The permission level that needs to be checked + * for. + * @param string $creator The creator of the event + * + * @return boolean Whether the user has the specified permissions. + */ + public function hasPermission($permission, $user, $perm, $creator = null) + { + return ($this->getPermissions($permission, $user, $creator) & $perm); + } + + /** + * Checks if a permission exists in the system. + * + * @param string $permission The permission to check. + * + * @return boolean True if the permission exists. + */ + public function exists($permission) + { + return false; + } + + /** + * Returns a list of parent permissions. + * + * @param string $child The name of the child to retrieve parents for. + * + * @return array A hash with all parents in a tree format. + * @throws Horde_Perms_Exception + */ + public function getParents($child) + { + throw new Horde_Perms_Exception('The administrator needs to configure a permanent permissions backend.'); + } + + /** + * Returns all permissions of the system in a tree format. + * + * @return array A hash with all permissions in a tree format. + */ + public function getTree() + { + return array(); + } + + /** + * Returns an hash of the available permissions. + * + * @return array The available permissions as a hash. + */ + static public function getPermsArray() + { + return array( + self::SHOW => _("Show"), + self::READ => _("Read"), + self::EDIT => _("Edit"), + self::DELETE => _("Delete") + ); + } + + /** + * Given an integer value of permissions returns an array representation + * of the integer. + * + * @param integer $int The integer representation of permissions. + * + * @return TODO + */ + static public function integerToArray($int) + { + if (isset(self::$_itaCache[$int])) { + return self::$_itaCache[$int]; + } + + self::$_itaCache[$int] = array(); + + /* Get the available perms array. */ + $perms = self::getPermsArray(); + + /* Loop through each perm and check if its value is included in the + * integer representation. */ + foreach ($perms as $val => $label) { + if ($int & $val) { + self::$_itaCache[$int][$val] = true; + } + } + + return self::$_itaCache[$int]; + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Datatree.php b/framework/Perms/lib/Horde/Perms/Datatree.php new file mode 100644 index 000000000..e0c697bff --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Datatree.php @@ -0,0 +1,250 @@ + + * @author Jan Schneider + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Datatree extends Horde_Perms +{ + /** + * Pointer to a DataTree instance to manage the different permissions. + * + * @var DataTree + */ + protected $_datatree; + + /** + * Pointer to a Horde_Cache instance. + * + * @var Horde_Cache + */ + protected $_cache; + + /** + * Cache for getPermission(). + * + * @var array + */ + protected $_permsCache = array(); + + /** + * Constructor. + * + * @throws Horde_Exception + */ + public function __construct() + { + global $conf; + + if (empty($conf['datatree']['driver'])) { + throw new Horde_Exception('You must configure a DataTree backend.'); + } + + $driver = $conf['datatree']['driver']; + $this->_datatree = DataTree::singleton($driver, + array_merge(Horde::getDriverConfig('datatree', $driver), + array('group' => 'horde.perms'))); + + $this->_cache = Horde_Cache::singleton($GLOBALS['conf']['cache']['driver'], + Horde::getDriverConfig('cache', $GLOBALS['conf']['cache']['driver'])); + + parent::__construct(); + } + + /** + * Returns a new permissions object. + * + * @param string $name The permission's name. + * + * @return DataTreeObject_Permissions A new permissions object. + */ + public function newPermission($name) + { + $type = 'matrix'; + $params = null; + + if ($pos = strpos($name, ':')) { + try { + $info = $this->getApplicationPermissions(substr($name, 0, $pos)); + if (isset($info['type']) && isset($info['type'][$name])) { + $type = $info['type'][$name]; + } + + if (isset($info['params']) && isset($info['params'][$name])) { + $params = $info['params'][$name]; + } + } catch (Horde_Perms_Exception $e) {} + } + + $perm = new Horde_Perms_Permission_DataTreeObject($name, $type, $params); + $perm->setDataTree($this->_datatree); + + return $perm; + } + + /** + * Returns a permission object corresponding to the named permission, + * with the users and other data retrieved appropriately. + * + * @param string $name The name of the permission to retrieve. + * + * @return TODO + */ + public function getPermission($name) + { + if (isset($this->_permsCache[$name])) { + return $this->_permsCache[$name]; + } + + $perm = $this->_cache->get('perm_' . $name, $GLOBALS['conf']['cache']['default_lifetime']); + if ($perm === false) { + $perm = $this->_datatree->getObject($name, 'Horde_Perms_Permission_DataTreeObject'); + $this->_cache->set('perm_' . $name, serialize($perm), $GLOBALS['conf']['cache']['default_lifetime']); + $this->_permsCache[$name] = $perm; + } else { + $this->_permsCache[$name] = unserialize($perm); + } + + return $this->_permsCache[$name]; + } + + /** + * Returns a permission object corresponding to the given unique ID, + * with the users and other data retrieved appropriately. + * + * @param integer $cid The unique ID of the permission to retrieve. + */ + public function getPermissionById($cid) + { + return ($cid == Horde_Perms::ROOT) + ? $this->newPermission(Horde_Perms::ROOT) + : $this->_datatree->getObjectById($cid, 'Horde_Perms_Permission_DataTreeObject'); + } + + /** + * Adds a permission to the permissions system. The permission must first + * be created with newPermission(), and have any initial users added to + * it, before this function is called. + * + * @param Horde_Perms_Permission_DataTreeObject $perm The new perm + * object. + * @throws Horde_Perms_Exception + */ + public function addPermission($perm) + { + if (!($perm instanceof Horde_Perms_Permission_DataTreeObject)) { + throw Horde_Perms_Exception('Permissions must be Horde_Perms_Permission_DataTreeObject objects.'); + } + + $name = $perm->getName(); + if (empty($name)) { + throw Horde_Perms_Exception('Permission names must be non-empty.'); + } + $this->_cache->expire('perm_' . $name); + $this->_cache->expire('perm_exists_' . $name); + + return $this->_datatree->add($perm); + } + + /** + * Removes a permission from the permissions system permanently. + * + * @param Horde_Perms_Permission_DataTreeObject $perm The permission to + * remove. + * @param boolean $force Force to remove + * every child. + */ + public function removePermission($perm, $force = false) + { + if (!($perm instanceof Horde_Perms_Permission_DataTreeObject)) { + throw Horde_Perms_Exception('Permissions must be Horde_Perms_Permission_DataTreeObject objects.'); + } + + $keys = $this->_datatree->get(DATATREE_FORMAT_FLAT, $perm->name, true); + foreach ($keys as $key) { + $this->_cache->expire('perm_' . $key); + $this->_cache->expire('perm_exists_' . $key); + } + + return $this->_datatree->remove($perm->name, $force); + } + + /** + * Returns the unique identifier of this permission. + * + * @param Horde_Perms_Permission_DataTreeObject $perm The permission + * object to get the + * ID of. + * + * @return integer The unique id. + */ + public function getPermissionId($permission) + { + return $this->_datatree->getId($permission->getName()); + } + + /** + * Checks if a permission exists in the system. + * + * @param string $permission The permission to check. + * + * @return boolean True if the permission exists. + */ + public function exists($permission) + { + $key = 'perm_exists_' . $permission; + $exists = $this->_cache->get($key, $GLOBALS['conf']['cache']['default_lifetime']); + if ($exists === false) { + $exists = $this->_datatree->exists($permission); + $this->_cache->set($key, (string)$exists); + } + + return (bool)$exists; + } + + /** + * Returns a list of parent permissions. + * + * @param string $child The name of the child to retrieve parents for. + * + * @return array A hash with all parents in a tree format. + */ + public function getParents($child) + { + return $this->_datatree->getParents($child); + } + + /** + * Returns a child's direct parent ID. + * + * @param mixed $child Either the object, an array containing the + * path elements, or the object name for which + * to look up the parent's ID. + * + * @return mixed The unique ID of the parent or PEAR_Error on error. + */ + public function getParent($child) + { + return $this->_datatree->getParent($child); + } + + /** + * Returns all permissions of the system in a tree format. + * + * @return array A hash with all permissions in a tree format. + */ + public function getTree() + { + return $this->_datatree->get(DATATREE_FORMAT_FLAT, Horde_Perms::ROOT, true); + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Exception.php b/framework/Perms/lib/Horde/Perms/Exception.php new file mode 100644 index 000000000..39b532c27 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Exception.php @@ -0,0 +1,16 @@ + + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Exception extends Horde_Exception +{ +} diff --git a/framework/Perms/lib/Horde/Perms/Permission.php b/framework/Perms/lib/Horde/Perms/Permission.php new file mode 100644 index 000000000..8c1ad6902 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Permission.php @@ -0,0 +1,592 @@ + + * @author Jan Schneider + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Permission +{ + // TODO + public $data; + + // TODO + public $name; + + /** + * Constructor. + * + * @param string $name The name of the perm. + * @param string $type The permission type. + * @param array $params A hash with any parameters that the permission + * type needs. + */ + public function __construct($name, $type = 'matrix', $params = null) + { + $this->setName($name); + $this->data['type'] = $type; + if (is_array($params)) { + $this->data['params'] = $params; + } + } + + /** + * Gets one of the attributes of the object, or null if it isn't defined. + * + * @param string $attribute The attribute to get. + * + * @return mixed The value of the attribute, or null. + */ + public function get($attribute) + { + if (isset($this->data[$attribute])) { + return $this->data[$attribute]; + } + + return ($attribute == 'type') ? 'matrix' : null; + } + + /** + * Get permission name. + * + * @return string Permission name. + */ + public function getName() + { + return $this->name; + } + + /** + * Set permission name + * + * @param string $name Permission name. + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * Get permission details. + * + * @return array Permission details. + */ + public function getData() + { + return $this->data; + } + + /** + * Set permission details. + * + * @param string $data Permission details. + */ + public function setData($data) + { + $this->data = $data; + } + + /** + * Updates the permissions based on data passed in the array. + * + * @param array $perms An array containing the permissions which are to + * be updated. + */ + public function updatePermissions($perms) + { + $type = $this->get('type'); + + if ($type == 'matrix') { + /* Array of permission types to iterate through. */ + $perm_types = Horde_Perms::getPermsArray(); + } + + foreach ($perms as $perm_class => $perm_values) { + switch ($perm_class) { + case 'default': + case 'guest': + case 'creator': + if ($type == 'matrix') { + foreach ($perm_types as $val => $label) { + if (!empty($perm_values[$val])) { + $this->setPerm($perm_class, $val, false); + } else { + $this->unsetPerm($perm_class, $val, false); + } + } + } elseif (!empty($perm_values)) { + $this->setPerm($perm_class, $perm_values, false); + } else { + $this->unsetPerm($perm_class, null, false); + } + break; + + case 'u': + case 'g': + $permId = array('class' => $perm_class == 'u' ? 'users' : 'groups'); + /* Figure out what names that are stored in this permission + * class have not been submitted for an update, ie. have been + * removed entirely. */ + $current_names = isset($this->data[$permId['class']]) + ? array_keys($this->data[$permId['class']]) + : array(); + $updated_names = array_keys($perm_values); + $removed_names = array_diff($current_names, $updated_names); + + /* Remove any names that have been completely unset. */ + foreach ($removed_names as $name) { + unset($this->data[$permId['class']][$name]); + } + + /* If nothing to actually update finish with this case. */ + if (is_null($perm_values)) { + continue; + } + + /* Loop through the names and update permissions for each. */ + foreach ($perm_values as $name => $name_values) { + $permId['name'] = $name; + + if ($type == 'matrix') { + foreach ($perm_types as $val => $label) { + if (!empty($name_values[$val])) { + $this->setPerm($permId, $val, false); + } else { + $this->unsetPerm($permId, $val, false); + } + } + } elseif (!empty($name_values)) { + $this->setPerm($permId, $name_values, false); + } else { + $this->unsetPerm($permId, null, false); + } + } + break; + } + } + } + + /** + * TODO + */ + public function setPerm($permId, $permission, $update = true) + { + if (is_array($permId)) { + if (empty($permId['name'])) { + return; + } + if ($this->get('type') == 'matrix' && + isset($this->data[$permId['class']][$permId['name']])) { + $this->data[$permId['class']][$permId['name']] |= $permission; + } else { + $this->data[$permId['class']][$permId['name']] = $permission; + } + } else { + if ($this->get('type') == 'matrix' && + isset($this->data[$permId])) { + $this->data[$permId] |= $permission; + } else { + $this->data[$permId] = $permission; + } + } + + if ($update) { + $this->save(); + } + } + + /** + * TODO + */ + public function unsetPerm($permId, $permission, $update = true) + { + if (is_array($permId)) { + if (empty($permId['name'])) { + return; + } + + if ($this->get('type') == 'matrix') { + if (isset($this->data[$permId['class']][$permId['name']])) { + $this->data[$permId['class']][$permId['name']] &= ~$permission; + if (empty($this->data[$permId['class']][$permId['name']])) { + unset($this->data[$permId['class']][$permId['name']]); + } + } else { + $update = false; + } + } else { + unset($this->data[$permId['class']][$permId['name']]); + } + } else { + if ($this->get('type') == 'matrix') { + if (isset($this->data[$permId])) { + $this->data[$permId] &= ~$permission; + } else { + $update = false; + } + } else { + unset($this->data[$permId]); + } + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants a user additional permissions to this object. + * + * @param string $uer The user to grant additional permissions + * to. + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addUserPermission($user, $permission, $update = true) + { + if (empty($user)) { + return; + } + + if ($this->get('type') == 'matrix' && + isset($this->data['users'][$user])) { + $this->data['users'][$user] |= $permission; + } else { + $this->data['users'][$user] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants guests additional permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addGuestPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['guest'])) { + $this->data['guest'] |= $permission; + } else { + $this->data['guest'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants creators additional permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addCreatorPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['creator'])) { + $this->data['creator'] |= $permission; + } else { + $this->data['creator'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants additional default permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addDefaultPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['default'])) { + $this->data['default'] |= $permission; + } else { + $this->data['default'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants a group additional permissions to this object. + * + * @param integer $groupId The id of the group to grant additional + * permissions to. + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addGroupPermission($groupId, $permission, $update = true) + { + if (empty($groupId)) { + return; + } + + if ($this->get('type') == 'matrix' && + isset($this->data['groups'][$groupId])) { + $this->data['groups'][$groupId] |= $permission; + } else { + $this->data['groups'][$groupId] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that a user currently has on this object. + * + * @param string $user The user to remove the permission from. + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeUserPermission($user, $permission, $update = true) + { + if (empty($user) || !isset($this->data['users'][$user])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['users'][$user] &= ~$permission; + if (empty($this->data['users'][$user])) { + unset($this->data['users'][$user]); + } + } else { + unset($this->data['users'][$user]); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that guests currently have on this object. + * + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeGuestPermission($permission, $update = true) + { + if (!isset($this->data['guest'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['guest'] &= ~$permission; + } else { + unset($this->data['guest']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that creators currently have on this object. + * + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeCreatorPermission($permission, $update = true) + { + if (!isset($this->data['creator'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['creator'] &= ~$permission; + } else { + unset($this->data['creator']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a default permission on this object. + * + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeDefaultPermission($permission, $update = true) + { + if (!isset($this->data['default'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['default'] &= ~$permission; + } else { + unset($this->data['default']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that a group currently has on this object. + * + * @param integer $groupId The id of the group to remove the + * permission from. + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeGroupPermission($groupId, $permission, + $update = true) + { + if (empty($groupId) || !isset($this->data['groups'][$groupId])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['groups'][$groupId] &= ~$permission; + if (empty($this->data['groups'][$groupId])) { + unset($this->data['groups'][$groupId]); + } + } else { + unset($this->data['groups'][$groupId]); + } + + if ($update) { + $this->save(); + } + } + + /** + * Returns an array of all user permissions on this object. + * + * @param integer $perm List only users with this permission level. + * Defaults to all users. + * + * @return array All user permissions for this object, indexed by user. + */ + public function getUserPermissions($perm = null) + { + if (!isset($this->data['users']) || !is_array($this->data['users'])) { + return array(); + } elseif (!$perm) { + return $this->data['users']; + } + + $users = array(); + foreach ($this->data['users'] as $user => $uperm) { + if ($uperm & $perm) { + $users[$user] = $uperm; + } + } + + return $users; + } + + /** + * Returns the guest permissions on this object. + * + * @return integer The guest permissions on this object. + */ + public function getGuestPermissions() + { + return empty($this->data['guest']) + ? null + : $this->data['guest']; + } + + /** + * Returns the creator permissions on this object. + * + * @return integer The creator permissions on this object. + */ + public function getCreatorPermissions() + { + return empty($this->data['creator']) + ? null + : $this->data['creator']; + } + + /** + * Returns the default permissions on this object. + * + * @return integer The default permissions on this object. + */ + public function getDefaultPermissions() + { + return empty($this->data['default']) + ? null + : $this->data['default']; + } + + /** + * Returns an array of all group permissions on this object. + * + * @param integer $perm List only users with this permission level. + * Defaults to all users. + * + * @return array All group permissions for this object, indexed by group. + */ + public function getGroupPermissions($perm = null) + { + if (!isset($this->data['groups']) || + !is_array($this->data['groups'])) { + return array(); + } elseif (!$perm) { + return $this->data['groups']; + } + + $groups = array(); + foreach ($this->data['groups'] as $group => $gperm) { + if ($gperm & $perm) { + $groups[$group] = $gperm; + } + } + + return $groups; + } + + /** + * TODO + */ + public function save() + { + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php b/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php new file mode 100644 index 000000000..a81cd6c2f --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php @@ -0,0 +1,562 @@ + + * @author Jan Schneider + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Permission_DataTreeObject extends DataTreeObject +{ + /** + * Constructor. Just makes sure to call the parent constructor so that + * the perm's name is set properly. + * + * @param string $name The name of the perm. + * @param string $type The permission type. + * @param array $params A hash with any parameters that the permission + * type needs. + */ + public function __construct($name, $type = 'matrix', $params = null) + { + parent::DataTreeObject($name); + + $this->data['type'] = $type; + if (is_array($params)) { + $this->data['params'] = $params; + } + } + + /** + * Gets one of the attributes of the object, or null if it isn't defined. + * + * @param string $attribute The attribute to get. + * + * @return mixed The value of the attribute, or null. + */ + public function get($attribute) + { + $value = parent::get($attribute); + + return (is_null($value) && $attribute == 'type') + ? 'matrix' + : $value; + } + + /** + * Updates the permissions based on data passed in the array. + * + * @param array $perms An array containing the permissions which are to + * be updated. + */ + public function updatePermissions($perms) + { + $type = $this->get('type'); + + if ($type == 'matrix') { + /* Array of permission types to iterate through. */ + $perm_types = Horde_Perms::getPermsArray(); + } + + foreach ($perms as $perm_class => $perm_values) { + switch ($perm_class) { + case 'default': + case 'guest': + case 'creator': + if ($type == 'matrix') { + foreach ($perm_types as $val => $label) { + if (!empty($perm_values[$val])) { + $this->setPerm($perm_class, $val, false); + } else { + $this->unsetPerm($perm_class, $val, false); + } + } + } elseif (!empty($perm_values)) { + $this->setPerm($perm_class, $perm_values, false); + } else { + $this->unsetPerm($perm_class, null, false); + } + break; + + case 'u': + case 'g': + $permId = array('class' => $perm_class == 'u' ? 'users' : 'groups'); + /* Figure out what names that are stored in this permission + * class have not been submitted for an update, ie. have been + * removed entirely. */ + $current_names = isset($this->data[$permId['class']]) + ? array_keys($this->data[$permId['class']]) + : array(); + $updated_names = array_keys($perm_values); + $removed_names = array_diff($current_names, $updated_names); + + /* Remove any names that have been completely unset. */ + foreach ($removed_names as $name) { + unset($this->data[$permId['class']][$name]); + } + + /* If nothing to actually update finish with this case. */ + if (is_null($perm_values)) { + continue; + } + + /* Loop through the names and update permissions for each. */ + foreach ($perm_values as $name => $name_values) { + $permId['name'] = $name; + + if ($type == 'matrix') { + foreach ($perm_types as $val => $label) { + if (!empty($name_values[$val])) { + $this->setPerm($permId, $val, false); + } else { + $this->unsetPerm($permId, $val, false); + } + } + } elseif (!empty($name_values)) { + $this->setPerm($permId, $name_values, false); + } else { + $this->unsetPerm($permId, null, false); + } + } + break; + } + } + } + + /** + * TODO + */ + public function setPerm($permId, $permission, $update = true) + { + if (is_array($permId)) { + if (empty($permId['name'])) { + return; + } + if ($this->get('type') == 'matrix' && + isset($this->data[$permId['class']][$permId['name']])) { + $this->data[$permId['class']][$permId['name']] |= $permission; + } else { + $this->data[$permId['class']][$permId['name']] = $permission; + } + } else { + if ($this->get('type') == 'matrix' && + isset($this->data[$permId])) { + $this->data[$permId] |= $permission; + } else { + $this->data[$permId] = $permission; + } + } + + if ($update) { + $this->save(); + } + } + + /** + * TODO + */ + public function unsetPerm($permId, $permission, $update = true) + { + if (is_array($permId)) { + if (empty($permId['name'])) { + return; + } + if ($this->get('type') == 'matrix') { + if (isset($this->data[$permId['class']][$permId['name']])) { + $this->data[$permId['class']][$permId['name']] &= ~$permission; + if (empty($this->data[$permId['class']][$permId['name']])) { + unset($this->data[$permId['class']][$permId['name']]); + } + if ($update) { + $this->save(); + } + } + } else { + unset($this->data[$permId['class']][$permId['name']]); + if ($update) { + $this->save(); + } + } + } else { + if ($this->get('type') == 'matrix') { + if (isset($this->data[$permId])) { + $this->data[$permId] &= ~$permission; + if ($update) { + $this->save(); + } + } + } else { + unset($this->data[$permId]); + if ($update) { + $this->save(); + } + } + } + } + + /** + * Grants a user additional permissions to this object. + * + * @param string $user The user to grant additional permissions + * to. + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addUserPermission($user, $permission, $update = true) + { + if (empty($user)) { + return; + } + + if ($this->get('type') == 'matrix' && + isset($this->data['users'][$user])) { + $this->data['users'][$user] |= $permission; + } else { + $this->data['users'][$user] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants guests additional permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addGuestPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['guest'])) { + $this->data['guest'] |= $permission; + } else { + $this->data['guest'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants creators additional permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addCreatorPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['creator'])) { + $this->data['creator'] |= $permission; + } else { + $this->data['creator'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants additional default permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addDefaultPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['default'])) { + $this->data['default'] |= $permission; + } else { + $this->data['default'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants a group additional permissions to this object. + * + * @param integer $groupId The id of the group to grant additional + * permissions to. + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addGroupPermission($groupId, $permission, $update = true) + { + if (empty($groupId)) { + return; + } + + if ($this->get('type') == 'matrix' && + isset($this->data['groups'][$groupId])) { + $this->data['groups'][$groupId] |= $permission; + } else { + $this->data['groups'][$groupId] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that a user currently has on this object. + * + * @param string $user The user to remove the permission from. + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeUserPermission($user, $permission, $update = true) + { + if (empty($user) || !isset($this->data['users'][$user])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['users'][$user] &= ~$permission; + if (empty($this->data['users'][$user])) { + unset($this->data['users'][$user]); + } + } else { + unset($this->data['users'][$user]); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that guests currently have on this object. + * + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeGuestPermission($permission, $update = true) + { + if (!isset($this->data['guest'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['guest'] &= ~$permission; + } else { + unset($this->data['guest']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that creators currently have on this object. + * + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeCreatorPermission($permission, $update = true) + { + if (!isset($this->data['creator'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['creator'] &= ~$permission; + } else { + unset($this->data['creator']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a default permission on this object. + * + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeDefaultPermission($permission, $update = true) + { + if (!isset($this->data['default'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['default'] &= ~$permission; + } else { + unset($this->data['default']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that a group currently has on this object. + * + * @param integer $groupId The id of the group to remove the + * permission from. + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeGroupPermission($groupId, $permission, + $update = true) + { + if (empty($groupId) || !isset($this->data['groups'][$groupId])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['groups'][$groupId] &= ~$permission; + if (empty($this->data['groups'][$groupId])) { + unset($this->data['groups'][$groupId]); + } + } else { + unset($this->data['groups'][$groupId]); + } + + if ($update) { + $this->save(); + } + } + + /** + * Returns an array of all user permissions on this object. + * + * @param integer $perm List only users with this permission level. + * Defaults to all users. + * + * @return array All user permissions for this object, indexed by user. + */ + public function getUserPermissions($perm = null) + { + if (!isset($this->data['users']) || !is_array($this->data['users'])) { + return array(); + } elseif (!$perm) { + return $this->data['users']; + } + + $users = array(); + foreach ($this->data['users'] as $user => $uperm) { + if ($uperm & $perm) { + $users[$user] = $uperm; + } + } + + return $users; + } + + /** + * Returns the guest permissions on this object. + * + * @return integer The guest permissions on this object. + */ + public function getGuestPermissions() + { + return empty($this->data['guest']) + ? null + : $this->data['guest']; + } + + /** + * Returns the creator permissions on this object. + * + * @return integer The creator permissions on this object. + */ + public function getCreatorPermissions() + { + return empty($this->data['creator']) + ? null + : $this->data['creator']; + } + + /** + * Returns the default permissions on this object. + * + * @return integer The default permissions on this object. + */ + public function getDefaultPermissions() + { + return empty($this->data['default']) + ? null + : $this->data['default']; + } + + /** + * Returns an array of all group permissions on this object. + * + * @param integer $perm List only users with this permission level. + * Defaults to all users. + * + * @return array All group permissions for this object, indexed by group. + */ + public function getGroupPermissions($perm = null) + { + if (!isset($this->data['groups']) || + !is_array($this->data['groups'])) { + return array(); + } elseif (!$perm) { + return $this->data['groups']; + } + + $groups = array(); + foreach ($this->data['groups'] as $group => $gperm) { + if ($gperm & $perm) { + $groups[$group] = $gperm; + } + } + + return $groups; + } + + /** + * Saves any changes to this object to the backend permanently. New + * objects are added instead. + * + * @throws Horde_Perms_Exception + */ + public function save() + { + $name = $this->getName(); + if (empty($name)) { + throw new Horde_Perms_Exception('Permission names must be non-empty'); + } + + parent::save(); + + $cache = Horde_Cache::singleton($GLOBALS['conf']['cache']['driver'], Horde::getDriverConfig('cache', $GLOBALS['conf']['cache']['driver'])); + $cache->expire('perm_' . $name); + $cache->expire('perm_exists_' . $name); + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Permission/SqlObject.php b/framework/Perms/lib/Horde/Perms/Permission/SqlObject.php new file mode 100644 index 000000000..0a5045636 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Permission/SqlObject.php @@ -0,0 +1,85 @@ + + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Permission_SqlObject extends Horde_Permission +{ + /** + * The string permission id. + * + * @var string + */ + protected $_id; + + /** + * Database handle for saving changes. + * + * @var DB + */ + protected $_write_db; + + /** + * Associates a DB object with this share. + * + * @param DB $write_db The DB object. + */ + public function setSqlOb($write_db) + { + $this->_write_db = $write_db; + } + + /** + * Get permission ID. + * + * @return TODO + */ + public function getId() + { + return $this->_id; + } + + /** + * Set permission id. + * + * @param string $id Permission ID. + */ + public function setId($id) + { + $this->_id = $id; + } + + /** + * Saves any changes to this object to the backend permanently. New + * objects are added instead. + * + * @throws Horde_Perms_Exception + */ + public function save() + { + $name = $this->getName(); + if (empty($name)) { + throw new Horde_Perms_Exception('Permission names must be non-empty'); + } + $query = 'UPDATE horde_perms SET perm_data = ? WHERE perm_id = ?'; + $params = array(serialize($this->data), $this->getId()); + $result = $this->_write_db->query($query, $params); + if ($result instanceof PEAR_Error) { + throw new Horde_Perms_Exception($result); + } + + $cache = Horde_Cache::singleton($GLOBALS['conf']['cache']['driver'], Horde::getDriverConfig('cache', $GLOBALS['conf']['cache']['driver'])); + $cache->expire('perm_sql_' . $name); + $cache->expire('perm_sql_exists_' . $name); + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Sql.php b/framework/Perms/lib/Horde/Perms/Sql.php new file mode 100644 index 000000000..f04e25149 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Sql.php @@ -0,0 +1,455 @@ + + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Sql extends Horde_Perms +{ + /** + * Boolean indicating whether or not we're connected to the SQL server. + * + * @var boolean + */ + protected $_connected = false; + + /** + * Handle for the current database connection. + * + * @var DB + */ + protected $_db; + + /** + * Handle for the current database connection, used for writing. Defaults + * to the same handle as $db if a separate write database is not required. + * + * @var DB + */ + protected $_write_db; + + /** + * Pointer to a Horde_Cache instance + * + * @var Horde_Cache + */ + protected $_cache; + + /** + * Cache of previously retrieved permissions. + * + * @var array + */ + protected $_permsCache = array(); + + /** + * Constructor. + */ + public function __construct() + { + $this->_cache = Horde_Cache::singleton($GLOBALS['conf']['cache']['driver'], Horde::getDriverConfig('cache', $GLOBALS['conf']['cache']['driver'])); + } + + /** + * Returns a new permissions object. + * + * @param string $name The permission's name. + * + * @return Horde_Perms_Permission_SqlObject A new permissions object. + */ + public function newPermission($name) + { + $type = 'matrix'; + $params = null; + + if ($pos = strpos($name, ':')) { + try { + $info = $this->getApplicationPermissions(substr($name, 0, $pos)); + if (isset($info['type']) && isset($info['type'][$name])) { + $type = $info['type'][$name]; + } + + if (isset($info['params']) && isset($info['params'][$name])) { + $params = $info['params'][$name]; + } + } catch (Horde_Perms_Exception $e) {} + } + + return new Horde_Perms_Permission_SqlObject($name, $type, $params); + } + + /** + * Returns an object corresponding to the named permission, with the + * users and other data retrieved appropriately. + * + * @param string $name The name of the permission to retrieve. + * + * @return Horde_Perms_Permission_SqlObject TODO + * @throw Horde_Perms_Exception + */ + public function getPermission($name) + { + if (isset($this->_permsCache[$name])) { + return $this->_permsCache[$name]; + } + + $this->_connect(); + + $perm = $this->_cache->get('perm_sql' . $name, $GLOBALS['conf']['cache']['default_lifetime']); + if (empty($perm)) { + $query = 'SELECT perm_id, perm_data FROM horde_perms WHERE perm_name = ?'; + $result = $this->_db->getRow($query, array($name), DB_FETCHMODE_ASSOC); + + if ($result instanceof PEAR_Error) { + throw new Horde_Perms_Exception($result); + } elseif (empty($result)) { + throw new Horde_Perms_Exception('Does not exist'); + } + + $object = new Horde_Perms_Permission_SqlObject($name); + $object->setId($result['perm_id']); + $object->setData(unserialize($result['perm_data'])); + + $this->_cache->set('perm_sql' . $name, serialize($object)); + + $this->_permsCache[$name] = $object; + } else { + $this->_permsCache[$name] = unserialize($perm); + } + + $this->_permsCache[$name]->setSQLOb($this->_write_db); + + return $this->_permsCache[$name]; + } + + /** + * Returns a permission object corresponding to the given unique ID, + * with the users and other data retrieved appropriately. + * + * @param integer $id The unique ID of the permission to retrieve. + * + * @return Horde_Perms_Permission_SqlObject TODO + * @throws Horde_Perms_Exception + */ + public function getPermissionById($id) + { + $this->_connect(); + + if ($id == Horde_Perms::ROOT || empty($id)) { + $object = $this->newPermission(Horde_Perms::ROOT); + } else { + $query = 'SELECT perm_name, perm_data FROM horde_perms WHERE perm_id = ?'; + $result = $this->_db->getRow($query, array($id), DB_FETCHMODE_ASSOC); + + if ($result instanceof PEAR_Error) { + throw new Horde_Perms_Exception($result); + } elseif (empty($result)) { + throw new Horde_Perms_Exception('Does not exist'); + } + + $object = new Horde_Perms_Permission_SqlObject($result['perm_name']); + $object->setId($id); + $object->setData(unserialize($result['perm_data'])); + $object->setSQLOb($this->_write_db); + } + + return $object; + } + + /** + * Adds a permission to the permissions system. The permission must first + * be created with newPermission(), and have any initial users added to + * it, before this function is called. + * + * @param Horde_Perms_Permission_SqlObject $perm The perm object. + * + * @return TODO + * @throws Horde_Perms_Exception + */ + public function addPermission($perm) + { + if (!($perm instanceof Horde_Perms_Permission_SqlObject)) { + throw new Horde_Perms_Exception('Permissions must be a Horde_Perms_Permission_SqlObject object.'); + } + + $name = $perm->getName(); + if (empty($name)) { + throw new Horde_Perms_Exception('Permission name must be non-empty.'); + } + + $this->_cache->expire('perm_sql' . $name); + $this->_cache->expire('perm_sql_exists_' . $name); + + $this->_connect(); + $id = $this->_write_db->nextId('horde_perms'); + + // remove root from the name + if (substr($name, 0, 3) == (Horde_Perms::ROOT . ':')) { + $name = substr($name, 3); + } + + // build parents + $parents = ''; + if (($pos = strrpos($name, ':')) !== false) { + $parent_name = substr($name, 0, $pos); + $query = 'SELECT perm_id, perm_parents FROM horde_perms WHERE perm_name = ?'; + $result = $this->_db->getRow($query, array($parent_name), DB_FETCHMODE_ASSOC); + if (!empty($result)) { + $parents = $result['perm_parents'] . ':' . $result['perm_id']; + } + } + + $query = 'INSERT INTO horde_perms (perm_id, perm_name, perm_parents) VALUES (?, ?, ?)'; + $perm->setId($id); + + $result = $this->_write_db->query($query, array($id, $name, $parents)); + if ($result instanceof PEAR_Error) { + throw new Horde_Perms_Exception($result); + } + + $perm->setSQLOb($this->_write_db); + $perm->save(); + + return $id; + } + + /** + * Removes a permission from the permissions system permanently. + * + * @param Horde_Perms_Permission_SqlObject $perm The permission to + * remove. + * @param boolean $force Force to remove ever + * child. + * + * @return TODO + * @throws Horde_Perms_Exception + */ + public function removePermission($perm, $force = false) + { + if (!($perm instanceof Horde_Perms_Permissions_SqlObject)) { + throw new Horde_Perms_Exception('Permissions must be Horde_Perms_Permission_SqlObject objects.'); + } + + $name = $perm->getName(); + $this->_cache->expire('perm_sql' . $name); + $this->_cache->expire('perm_sql_exists_' . $name); + + $this->_connect(); + $query = 'DELETE FROM horde_perms WHERE perm_name = ?'; + $result = $this->_write_db->query($query, array($name)); + if ($result instanceof PEAR_Error) { + throw new Horde_Perms_Exception($result); + } elseif ($force) { + return $result; + } + + $query = 'DELETE FROM horde_perms WHERE perm_name LIKE ?'; + return $this->_write_db->query($query, array($name . ':%')); + } + + /** + * Returns the unique identifier of this permission. + * + * @param Horde_Perms_Permission_SqlObject $perm The permission object to + * get the ID of. + * + * @return integer The unique id. + */ + public function getPermissionId($permission) + { + if ($permission->getName() == Horde_Perms::ROOT) { + return Horde_Perms::ROOT; + } + + $this->_connect(); + $query = 'SELECT perm_id FROM horde_perms WHERE perm_name = ?'; + return $this->_db->getOne($query, array($permission->getName())); + } + + /** + * Checks if a permission exists in the system. + * + * @param string $permission The permission to check. + * + * @return boolean True if the permission exists. + * @throws Horde_Perms_Exception + */ + public function exists($permission) + { + $key = 'perm_sql_exists_' . $permission; + $exists = $this->_cache->get($key, $GLOBALS['conf']['cache']['default_lifetime']); + if ($exists === false) { + $this->_connect(); + $query = 'SELECT COUNT(*) FROM horde_perms WHERE perm_name = ?'; + $exists = $this->_db->getOne($query, array($permission)); + if ($exists instanceof PEAR_Error) { + throw new Horde_Perms_Exception($exists); + } + + $this->_cache->set($key, (string)$exists); + } + + return (bool)$exists; + } + + /** + * Returns a child's direct parent ID. + * + * @param mixed $child The object name for which to look up the parent's + * ID. + * + * @return integer The unique ID of the parent. + * @throws Horde_Perms_Exception + */ + public function getParent($child) + { + $this->_connect(); + $query = 'SELECT perm_parents FROM horde_perms WHERE perm_name = ?'; + $parents = $this->_db->getOne($query, array($child)); + + if ($parents instanceof PEAR_Error) { + throw new Horde_Perms_Exception($parents); + } + + if (empty($parents)) { + return Horde_Perms::ROOT; + } + + $parents = explode(':', $parents); + return array_pop($parents); + } + + /** + * Returns a list of parent permissions. + * + * @param string $child The name of the child to retrieve parents for. + * + * @return array A hash with all parents in a tree format. + * @throws Horde_Perms_Exception + */ + public function getParents($child) + { + $this->_connect(); + $query = 'SELECT perm_parents FROM horde_perms WHERE perm_name = ?'; + $result = $this->_db->getOne($query, array($child)); + if ($result instanceof PEAR_Error) { + throw new Horde_Perms_Exception($result); + } elseif (empty($result)) { + throw new Horde_Perms_Exception('Does not exist'); + } + + return $this->_getParents($result); + } + + /** + * TODO + */ + protected function _getParents($parents) + { + if (empty($parents)) { + return array(Horde_Perms::ROOT => true); + } + + $pname = $parents; + $parents = substr($parents, 0, strrpos($parents, ':')); + + return array($pname => $this->_getParents($parents)); + } + + /** + * Returns all permissions of the system in a tree format. + * + * @return array A hash with all permissions in a tree format. + * @throws Horde_Perms_Exception + */ + public function getTree() + { + $this->_connect(); + $query = 'SELECT perm_id, perm_name FROM horde_perms ORDER BY perm_name ASC'; + $tree = $this->_db->getAssoc($query); + if ($tree instanceof PEAR_Error) { + throw new Horde_Perms_Exception($tree); + } + + $tree[Horde_Perms::ROOT] = Horde_Perms::ROOT; + return $tree; + } + + /** + * Attempts to open a connection to the sql server. + * + * @throws Horde_Perms_Exception + */ + protected function _connect() + { + if ($this->_connected) { + return; + } + + $_params = $GLOBALS['conf']['sql']; + if (!isset($_params['database'])) { + $_params['database'] = ''; + } + if (!isset($_params['username'])) { + $_params['username'] = ''; + } + if (!isset($_params['hostspec'])) { + $_params['hostspec'] = ''; + } + + /* Connect to the sql server using the supplied parameters. */ + $this->_write_db = DB::connect($_params, + array('persistent' => !empty($_params['persistent']), + 'ssl' => !empty($this->_params['ssl']))); + if ($this->_write_db instanceof PEAR_Error) { + throw new Horde_Perms_Exception($this->_write_db); + } + + /* Set DB portability options. */ + switch ($this->_write_db->phptype) { + case 'mssql': + $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); + break; + + default: + $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); + break; + } + + /* Check if we need to set up the read DB connection seperately. */ + if (!empty($_params['splitread'])) { + $params = array_merge($_params, $_params['read']); + $this->_db = DB::connect($params, + array('persistent' => !empty($params['persistent']), + 'ssl' => !empty($params['ssl']))); + if ($this->_db instanceof PEAR_Error) { + throw new Horde_Perms_Exception($this->_db); + } + + /* Set DB portability options. */ + switch ($this->_db->phptype) { + case 'mssql': + $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); + break; + + default: + $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); + break; + } + } else { + /* Default to the same DB handle for the writer too. */ + $this->_db = $this->_write_db; + } + + $this->_connected = true; + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Ui.php b/framework/Perms/lib/Horde/Perms/Ui.php new file mode 100644 index 000000000..35cb12372 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Ui.php @@ -0,0 +1,538 @@ + + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Ui +{ + /** + * The Horde_Perms object we're displaying UI stuff for. + * + * @var Horde_Perms + */ + protected $_perms; + + /** + * The Horde_Form object that will be used for displaying the edit form. + * + * @var Horde_Form + */ + protected $_form = null; + + /** + * The Horde_Variables object used in Horde_Form. + * + * @var Horde_Variables + */ + protected $_vars = null; + + /** + * The permission type. + * + * @var string + */ + protected $_type = 'matrix'; + + /** + * Constructor. + * + * @param Horde_Perms $perms The object to display UI stuff for. + */ + public function __construct($perms) + { + $this->_perms = $perms; + } + + /** + * Return a Horde_Tree representation of the permissions tree. + * + * @return string The html showing the permissions as a Horde_Tree. + * @throws Horde_Perms_Exception + */ + public function renderTree($current = Horde_Perms::ROOT) + { + global $registry; + + /* Get the perms tree. */ + $nodes = $this->_perms->getTree(); + + $icondir = array('icondir' => $GLOBALS['registry']->getImageDir()); + $perms_node = $icondir + array('icon' => 'perms.png'); + $add = Horde::applicationUrl('admin/perms/addchild.php'); + $add_img = Horde::img('add_perm.png', _("Add Permission")); + $edit = Horde::applicationUrl('admin/perms/edit.php'); + $delete = Horde::applicationUrl('admin/perms/delete.php'); + $edit_img = Horde::img('edit.png', _("Edit Permission")); + $delete_img = Horde::img('delete.png', _("Delete Permission")); + $blank_img = Horde::img('blank.gif', '', array('width' => 16, 'height' => 16)); + + /* Set up the tree. */ + $tree = Horde_Tree::singleton('perms_ui', 'javascript'); + $tree->setOption(array('alternate' => true, 'hideHeaders' => true)); + $tree->setHeader(array(array('width' => '50%'))); + + foreach ($nodes as $perm_id => $node) { + $node_class = ($current == $perm_id) + ? array('class' => 'selected') + : array(); + if ($perm_id == Horde_Perms::ROOT) { + $add_link = Horde::link( + Horde_Util::addParameter($add, 'perm_id', $perm_id), + _("Add New Permission")) + . $add_img . ''; + $base_node_params = $icondir + + array('icon' => 'administration.png'); + + $tree->addNode($perm_id, null, _("All Permissions"), 0, true, + $base_node_params + $node_class, + array($add_link)); + } else { + $parent_id = $this->_perms->getParent($node); + + $perms_extra = array(); + $parents = explode(':', $node); + + if (!in_array($parents[0], $GLOBALS['registry']->listApps())) { + // This backend has permissions for an application that is + // not installed. Perhaps the application has been removed + // or the backend is shared with other Horde installations. + // Skip this app and do not include it in the tree. + continue; + } + + try { + $app_perms = $this->_perms->getApplicationPermissions($parents[0]); + } catch (Horde_Perms_Exception $e) { + $GLOBALS['notification']->push($e); + continue; + } + + if (isset($app_perms['tree']) && + is_array(Horde_Array::getElement($app_perms['tree'], $parents))) { + $add_link = Horde::link( + Horde_Util::addParameter($add, 'perm_id', $perm_id), + _("Add Child Permission")) + . $add_img . ''; + $perms_extra[] = $add_link; + } else { + $perms_extra[] = $blank_img; + } + + $edit_link = Horde::link( + Horde_Util::addParameter($edit, 'perm_id', $perm_id), + _("Edit Permission")) + . $edit_img . ''; + $perms_extra[] = $edit_link; + $delete_link = Horde::link( + Horde_Util::addParameter($delete, 'perm_id', $perm_id), + _("Delete Permission")) + . $delete_img . ''; + $perms_extra[] = $delete_link; + $name = $this->_perms->getTitle($node); + + $expanded = isset($nodes[$current]) && + strpos($nodes[$current], $node) === 0 && + $nodes[$current] != $node; + $tree->addNode($perm_id, $parent_id, $name, + substr_count($node, ':') + 1, $expanded, + $perms_node + $node_class, $perms_extra); + } + } + + $tree->sort('label'); + + return $tree->renderTree(); + } + + /** + * Set an existing form object to use for the edit form. + * + * @param Horde_Form $form An existing Horde_Form object to use. + */ + public function setForm(&$form) + { + $this->_form = $form; + } + + /** + * Set an existing vars object to use for the edit form. + * + * @param Horde_Variables $vars An existing Horde_Variables object to + * use. + */ + public function setVars($vars) + { + $this->_vars = $vars; + } + + /** + * Create a form to add a permission. + * + * @param Horde_Perms_Permission $permission Permission + * @param string $force_choice If the permission to be + * added can be one of many, + * setting this will force the + * choice to one particular. + */ + public function setupAddForm($permission, $force_choice = null) + { + /* Initialise form if required. */ + $this->_formInit(); + + $this->_form->setTitle(sprintf(_("Add a child permission to \"%s\""), $this->_perms->getTitle($permission->getName()))); + $this->_form->setButtons(_("Add")); + $this->_vars->set('perm_id', $this->_perms->getPermissionId($permission)); + $this->_form->addHidden('', 'perm_id', 'text', false); + + /* Set up the actual child adding field. */ + $child_perms = $this->_perms->getAvailable($permission->getName()); + if ($child_perms === false) { + /* False, so no childs are to be added below this level. */ + $this->_form->addVariable(_("Permission"), 'child', 'invalid', true, false, null, array(_("No children can be added to this permission."))); + } elseif (is_array($child_perms)) { + if (!empty($force_choice)) { + /* Choice array available, but choice being forced. */ + $this->_vars->set('child', $force_choice); + $this->_form->addVariable(_("Permissions"), 'child', 'enum', true, true, null, array($child_perms)); + } else { + /* Choice array available, so set up enum field. */ + $this->_form->addVariable(_("Permissions"), 'child', 'enum', true, false, null, array($child_perms)); + } + } + } + + /** + * Function to validate any add form input. + * + * @param TODO $info TODO + * + * @return mixed Either false if the form does not validate correctly or + * an array with all the form values. + */ + public function validateAddForm($info) + { + if (!$this->_form->validate($this->_vars)) { + return false; + } + + $this->_form->getInfo($this->_vars, $info); + return true; + } + + /** + * Create a permission editing form. + * + * @param Horde_Perms_Permission $permission TODO + */ + public function setupEditForm($permission) + { + global $registry; + + /* Initialise form if required. */ + $this->_formInit(); + + $this->_form->setButtons(_("Update"), true); + $perm_id = $this->_perms->getPermissionId($permission); + $this->_form->addHidden('', 'perm_id', 'text', false); + + /* Get permission configuration. */ + $this->_type = $permission->get('type'); + $params = $permission->get('params'); + + /* Default permissions. */ + $perm_val = $permission->getDefaultPermissions(); + $this->_form->setSection('default', _("All Authenticated Users"), Horde::img('perms.png', '', '', $registry->getImageDir('horde')), false); + + /* We MUST use 'deflt' for the variable name because 'default' is a + * reserved word in JavaScript. */ + if ($this->_type == 'matrix') { + /* Set up the columns for the permissions matrix. */ + $cols = Horde_Perms::getPermsArray(); + + /* Define a single matrix row for default perms. */ + $matrix = array(Horde_Perms::integerToArray($perm_val)); + $this->_form->addVariable('', 'deflt', 'matrix', false, false, null, array($cols, array(0 => ''), $matrix)); + } else { + $var = $this->_form->addVariable('', 'deflt', $this->_type, false, false, null, $params); + $var->setDefault($perm_val); + } + + /* Guest permissions. */ + $perm_val = $permission->getGuestPermissions(); + $this->_form->setSection('guest', _("Guest Permissions"), '', false); + + if ($this->_type == 'matrix') { + /* Define a single matrix row for guest perms. */ + $matrix = array(Horde_Perms::integerToArray($perm_val)); + $this->_form->addVariable('', 'guest', 'matrix', false, false, null, array($cols, array(0 => ''), $matrix)); + } else { + $var = $this->_form->addVariable('', 'guest', $this->_type, false, false, null, $params); + $var->setDefault($perm_val); + } + + /* Object creator permissions. */ + $perm_val = $permission->getCreatorPermissions(); + $this->_form->setSection('creator', _("Creator Permissions"), Horde::img('user.png', '', '', $registry->getImageDir('horde')), false); + + if ($this->_type == 'matrix') { + /* Define a single matrix row for creator perms. */ + $matrix = array(Horde_Perms::integerToArray($perm_val)); + $this->_form->addVariable('', 'creator', 'matrix', false, false, null, array($cols, array(0 => ''), $matrix)); + } else { + $var = $this->_form->addVariable('', 'creator', $this->_type, false, false, null, $params); + $var->setDefault($perm_val); + } + + /* Users permissions. */ + $perm_val = $permission->getUserPermissions(); + $this->_form->setSection('users', _("Individual Users"), Horde::img('user.png', '', '', $registry->getImageDir('horde')), false); + $auth = Horde_Auth::singleton($GLOBALS['conf']['auth']['driver']); + if ($auth->hasCapability('list')) { + /* The auth driver has list capabilities so set up an array which + * the matrix field type will recognise to set up an enum box for + * adding new users to the permissions matrix. */ + $new_users = array(); + + try { + $user_list = $auth->listUsers(); + sort($user_list); + foreach ($user_list as $user) { + if (!isset($perm_val[$user])) { + $new_users[$user] = $user; + } + } + } catch (Horde_Auth_Exception $e) { + $new_users = true; + } + } else { + /* No list capabilities, setting to true so that the matrix field + * type will offer a text input box for adding new users. */ + $new_users = true; + } + + if ($this->_type == 'matrix') { + /* Set up the matrix array, breaking up each permission integer + * into an array. The keys of this array will be the row + * headers. */ + $rows = array(); + $matrix = array(); + foreach ($perm_val as $u_id => $u_perms) { + $rows[$u_id] = $u_id; + $matrix[$u_id] = Horde_Perms::integerToArray($u_perms); + } + $this->_form->addVariable('', 'u', 'matrix', false, false, null, array($cols, $rows, $matrix, $new_users)); + } else { + if ($new_users) { + if (is_array($new_users)) { + $u_n = Horde_Util::getFormData('u_n'); + $u_n = empty($u_n['u']) ? null : $u_n['u']; + $user_html = ''; + } else { + $user_html = ''; + } + $this->_form->addVariable($user_html, 'u_n[v]', $this->_type, false, false, null, $params); + } + foreach ($perm_val as $u_id => $u_perms) { + $var = $this->_form->addVariable($u_id, 'u_v[' . $u_id . ']', $this->_type, false, false, null, $params); + $var->setDefault($u_perms); + } + } + + /* Groups permissions. */ + $perm_val = $permission->getGroupPermissions(); + $this->_form->setSection('groups', _("Groups"), Horde::img('group.png', '', '', $registry->getImageDir('horde')), false); + require_once 'Horde/Group.php'; + $groups = Group::singleton(); + $group_list = $groups->listGroups(); + if ($group_list instanceof PEAR_Error) { + $GLOBALS['notification']->push($group_list); + $group_list = array(); + } + + if (!empty($group_list)) { + /* There is an available list of groups so set up an array which + * the matrix field type will recognise to set up an enum box for + * adding new groups to the permissions matrix. */ + $new_groups = array(); + foreach ($group_list as $groupId => $group) { + if (!isset($perm_val[$groupId])) { + $new_groups[$groupId] = $group; + } + } + } else { + /* Do not offer a text box to add new groups. */ + $new_groups = false; + } + + if ($this->_type == 'matrix') { + /* Set up the matrix array, break up each permission integer into + * an array. The keys of this array will be the row headers. */ + $rows = array(); + $matrix = array(); + foreach ($perm_val as $g_id => $g_perms) { + $rows[$g_id] = isset($group_list[$g_id]) ? $group_list[$g_id] : $g_id; + $matrix[$g_id] = Horde_Perms::integerToArray($g_perms); + } + $this->_form->addVariable('', 'g', 'matrix', false, false, null, array($cols, $rows, $matrix, $new_groups)); + } else { + if ($new_groups) { + if (is_array($new_groups)) { + $g_n = Horde_Util::getFormData('g_n'); + $g_n = empty($g_n['g']) ? null : $g_n['g']; + $group_html = ''; + } else { + $group_html = ''; + } + $this->_form->addVariable($group_html, 'g_n[v]', $this->_type, false, false, null, $params); + } + foreach ($perm_val as $g_id => $g_perms) { + $var = &$this->_form->addVariable(isset($group_list[$g_id]) ? $group_list[$g_id] : $g_id, 'g_v[' . $g_id . ']', $this->_type, false, false, null, $params); + $var->setDefault($g_perms); + } + } + + /* Set form title. */ + $this->_form->setTitle(sprintf(_("Edit permissions for \"%s\""), $this->_perms->getTitle($permission->getName()))); + } + + /** + * Function to validate any edit form input. + * + * @return mixed Either false if the form does not validate correctly or + * an array with all the form values. + */ + public function validateEditForm(&$info) + { + if (!$this->_form->validate($this->_vars)) { + return false; + } + + $this->_form->getInfo($this->_vars, $info); + + if ($this->_type == 'matrix') { + /* Collapse the array for default/guest/creator. */ + $info['deflt'] = isset($info['deflt'][0]) + ? $info['deflt'][0] + : null; + $info['guest'] = isset($info['guest'][0]) + ? $info['guest'][0] + : null; + $info['creator'] = isset($info['creator'][0]) + ? $info['creator'][0] + : null; + } else { + $u_n = $this->_vars->get('u_n'); + $info['u'] = array(); + if (!empty($u_n['u'])) { + $info['u'][$u_n['u']] = $info['u_n']['v']; + } + unset($info['u_n']); + if (isset($info['u_v'])) { + $info['u'] += $info['u_v']; + unset($info['u_v']); + } + $g_n = $this->_vars->get('g_n'); + $info['g'] = array(); + if (!empty($g_n['g'])) { + $info['g'][$g_n['g']] = $info['g_n']['v']; + } + unset($info['g_n']); + if (isset($info['g_v'])) { + $info['g'] += $info['g_v']; + unset($info['g_v']); + } + } + $info['default'] = $info['deflt']; + unset($info['deflt']); + + return true; + } + + /** + * Create a permission deleting form. + * + * @param Horde_Perms_Permission $permission A permissions object. + */ + public function setupDeleteForm($permission) + { + /* Initialise form if required. */ + $this->_formInit(); + + $this->_form->setTitle(sprintf(_("Delete permissions for \"%s\""), $this->_perms->getTitle($permission->getName()))); + $this->_form->setButtons(array(_("Delete"), _("Do not delete"))); + $this->_form->addHidden('', 'perm_id', 'text', false); + $this->_form->addVariable(sprintf(_("Delete permissions for \"%s\" and any sub-permissions?"), $this->_perms->getTitle($permission->getName())), 'prompt', 'description', false); + } + + /** + * Function to validate any delete form input. + * + * @param TODO $info TODO + * + * @return mixed If the delete button confirmation has been pressed return + * true, if any other submit button has been pressed return + * false. If form did not validate return null. + */ + public function validateDeleteForm($info) + { + $form_submit = $this->_vars->get('submitbutton'); + + if ($form_submit == _("Delete")) { + if ($this->_form->validate($this->_vars)) { + $this->_form->getInfo($this->_vars, $info); + return true; + } + } elseif (!empty($form_submit)) { + return false; + } + + return null; + } + + /** + * Renders the edit form. + */ + public function renderForm($form_script = 'edit.php') + { + $renderer = new Horde_Form_Renderer(); + $this->_form->renderActive($renderer, $this->_vars, $form_script, 'post'); + } + + /** + * Creates any form objects if they have not been initialised yet. + */ + protected function _formInit() + { + if (is_null($this->_vars)) { + /* No existing vars set, get them now. */ + $this->_vars = Horde_Variables::getDefaultVariables(); + } + + if (!($this->_form instanceof Horde_Form)) { + /* No existing valid form object set so set up a new one. */ + $this->_form = new Horde_Form($this->_vars); + } + } + +} diff --git a/framework/Perms/package.xml b/framework/Perms/package.xml new file mode 100644 index 000000000..96bdf93f6 --- /dev/null +++ b/framework/Perms/package.xml @@ -0,0 +1,149 @@ + + + Perms + pear.horde.org + Horde_Perms + Horde Permissions System + The Perms package provides an interface to the Horde permissions system. + + Chuck Hagenbuch + chuck + chuck@horde.org + yes + + + Jan Schneider + jan + jan@horde.org + yes + + 2009-11-20 + + 0.2.0 + 0.2.0 + + + beta + beta + + LGPL + * Initial Horde 4 package. + + + + + + + + + + + + + + + + + + + + + + + + + 5.2.0 + + + 1.7.0 + + + Group + pear.horde.org + + + Util + pear.horde.org + + + gettext + + + + + Horde_DataTree + pear.horde.org + + + Horde_Tree + pear.horde.org + + + + + + + + + + + + + + + + + + + 0.1.0 + 0.1.0 + + + beta + beta + + 2008-08-20 + LGPL + * Cache permissions with Horde_Cache (duck@obala.net). + * Fixed special permissions with more than one user or group (Bug #2058). + * Added a getParent() call instead of accessing the _datatree member directly. (duck@obala.net, Request #6150). + * Added beta SQL Permissions driver (duck@obala.net, Request #6150). + * Automatically expand the node of the currently open permission. + * Only show Add Permission icons if there are sub-permissions to add. + * Make sure Horde_Array is available. + * Handle and display errors if they occur in the Perms backend. + + + + + 0.0.2 + 0.0.2 + + + alpha + alpha + + 2006-05-08 + LGPL + Converted to package.xml 2.0 for pear.horde.org + + + + + 0.0.1 + 0.0.1 + + + alpha + alpha + + 2003-07-05 + LGPL + Initial release as a PEAR package + + + + diff --git a/framework/Rpc/lib/Horde/Rpc/Webdav.php b/framework/Rpc/lib/Horde/Rpc/Webdav.php index 55c7fa97e..9f1c4fa7c 100644 --- a/framework/Rpc/lib/Horde/Rpc/Webdav.php +++ b/framework/Rpc/lib/Horde/Rpc/Webdav.php @@ -509,7 +509,7 @@ class Horde_Rpc_Webdav extends Horde_Rpc $list[] = array('path' => $path, 'props' => $this->_getProps($options['props'], $root)); - $apps = $registry->listApps(null, false, PERMS_READ); + $apps = $registry->listApps(null, false, Horde_Perms::READ); if (is_a($apps, 'PEAR_Error')) { Horde::logMessage($apps, __FILE__, __LINE__, PEAR_LOG_ERR); return $apps;