diff options
author | Robin Appelman <icewind@owncloud.com> | 2013-05-28 23:46:57 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2013-05-29 00:31:55 +0200 |
commit | 955bda1842986a6737c8d3b575b0cd3bb5a0e17d (patch) | |
tree | 23713e8a21ea4c50574a8610b6262ef92fa9a9cb /lib/user | |
parent | fee43ec506ee423f67ddae0a9ef29a3135b99ab6 (diff) | |
download | nextcloud-server-955bda1842986a6737c8d3b575b0cd3bb5a0e17d.tar.gz nextcloud-server-955bda1842986a6737c8d3b575b0cd3bb5a0e17d.zip |
New user management classes
Diffstat (limited to 'lib/user')
-rw-r--r-- | lib/user/backend.php | 22 | ||||
-rw-r--r-- | lib/user/dummy.php | 144 | ||||
-rw-r--r-- | lib/user/manager.php | 189 | ||||
-rw-r--r-- | lib/user/session.php | 161 | ||||
-rw-r--r-- | lib/user/user.php | 177 |
5 files changed, 612 insertions, 81 deletions
diff --git a/lib/user/backend.php b/lib/user/backend.php index 93e8f17ca98..e9be08e429c 100644 --- a/lib/user/backend.php +++ b/lib/user/backend.php @@ -58,7 +58,7 @@ abstract class OC_User_Backend implements OC_User_Interface { /** * @brief Get all supported actions - * @returns bitwise-or'ed actions + * @return int bitwise-or'ed actions * * Returns the supported actions as int to be * compared with OC_USER_BACKEND_CREATE_USER etc. @@ -76,8 +76,8 @@ abstract class OC_User_Backend implements OC_User_Interface { /** * @brief Check if backend implements actions - * @param $actions bitwise-or'ed actions - * @returns boolean + * @param int $actions bitwise-or'ed actions + * @return boolean * * Returns the supported actions as int to be * compared with OC_USER_BACKEND_CREATE_USER etc. @@ -87,12 +87,12 @@ abstract class OC_User_Backend implements OC_User_Interface { } /** - * @brief delete a user - * @param $uid The username of the user to delete - * @returns true/false - * - * Deletes a user - */ + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ public function deleteUser( $uid ) { return false; } @@ -127,8 +127,8 @@ abstract class OC_User_Backend implements OC_User_Interface { /** * @brief get display name of the user - * @param $uid user ID of the user - * @return display name + * @param string $uid user ID of the user + * @return string display name */ public function getDisplayName($uid) { return $uid; diff --git a/lib/user/dummy.php b/lib/user/dummy.php index d63f60efbeb..b5b7a6c3c7a 100644 --- a/lib/user/dummy.php +++ b/lib/user/dummy.php @@ -1,114 +1,118 @@ <?php /** -* ownCloud -* -* @author Frank Karlitschek -* @copyright 2012 Frank Karlitschek frank@owncloud.org -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see <http://www.gnu.org/licenses/>. -* -*/ + * ownCloud + * + * @author Frank Karlitschek + * @copyright 2012 Frank Karlitschek frank@owncloud.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ /** * dummy user backend, does not keep state, only for testing use */ class OC_User_Dummy extends OC_User_Backend { - private $users=array(); + private $users = array(); + /** - * @brief Create a new user - * @param $uid The username of the user to create - * @param $password The password of the new user - * @returns true/false - * - * Creates a new user. Basic checking of username is done in OC_User - * itself, not in its subclasses. - */ + * @brief Create a new user + * @param string $uid The username of the user to create + * @param string $password The password of the new user + * @return bool + * + * Creates a new user. Basic checking of username is done in OC_User + * itself, not in its subclasses. + */ public function createUser($uid, $password) { - if(isset($this->users[$uid])) { + if (isset($this->users[$uid])) { return false; - }else{ - $this->users[$uid]=$password; + } else { + $this->users[$uid] = $password; return true; } } /** - * @brief delete a user - * @param $uid The username of the user to delete - * @returns true/false - * - * Deletes a user - */ - public function deleteUser( $uid ) { - if(isset($this->users[$uid])) { + * @brief delete a user + * @param string $uid The username of the user to delete + * @return bool + * + * Deletes a user + */ + public function deleteUser($uid) { + if (isset($this->users[$uid])) { unset($this->users[$uid]); return true; - }else{ + } else { return false; } } /** - * @brief Set password - * @param $uid The username - * @param $password The new password - * @returns true/false - * - * Change the password of a user - */ + * @brief Set password + * @param string $uid The username + * @param string $password The new password + * @return bool + * + * Change the password of a user + */ public function setPassword($uid, $password) { - if(isset($this->users[$uid])) { - $this->users[$uid]=$password; + if (isset($this->users[$uid])) { + $this->users[$uid] = $password; return true; - }else{ + } else { return false; } } /** - * @brief Check if the password is correct - * @param $uid The username - * @param $password The password - * @returns string - * - * Check if the password is correct without logging in the user - * returns the user id or false - */ + * @brief Check if the password is correct + * @param string $uid The username + * @param string $password The password + * @return string + * + * Check if the password is correct without logging in the user + * returns the user id or false + */ public function checkPassword($uid, $password) { - if(isset($this->users[$uid])) { - return ($this->users[$uid]==$password); - }else{ + if (isset($this->users[$uid])) { + return ($this->users[$uid] == $password); + } else { return false; } } /** - * @brief Get a list of all users - * @returns array with all uids - * - * Get a list of all users. - */ + * @brief Get a list of all users + * @param string $search + * @param int $limit + * @param int $offset + * @return array with all uids + * + * Get a list of all users. + */ public function getUsers($search = '', $limit = null, $offset = null) { return array_keys($this->users); } /** - * @brief check if a user exists - * @param string $uid the username - * @return boolean - */ + * @brief check if a user exists + * @param string $uid the username + * @return boolean + */ public function userExists($uid) { return isset($this->users[$uid]); } diff --git a/lib/user/manager.php b/lib/user/manager.php new file mode 100644 index 00000000000..25e67ca36b5 --- /dev/null +++ b/lib/user/manager.php @@ -0,0 +1,189 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\PublicEmitter; + +/** + * Class Manager + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user) + * + * @package OC\User + */ +class Manager extends PublicEmitter { + /** + * @var \OC_User_Backend[] $backends + */ + private $backends = array(); + + /** + * @param \OC_User_Backend $backend + */ + public function registerBackend($backend) { + $this->backends[] = $backend; + } + + /** + * @param \OC_User_Backend $backend + */ + public function removeBackend($backend) { + if (($i = array_search($backend, $this->backends)) !== false) { + unset($this->backends[$i]); + } + } + + public function clearBackends() { + $this->backends = array(); + } + + /** + * @param string $uid + * @return \OC\User\User + */ + public function get($uid) { + foreach ($this->backends as $backend) { + if ($backend->userExists($uid)) { + return new User($uid, $backend); + } + } + return null; + } + + /** + * @param string $uid + * @return bool + */ + public function userExists($uid) { + foreach ($this->backends as $backend) { + if ($backend->userExists($uid)) { + return true; + } + } + return false; + } + + /** + * search by user id + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function search($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getUsers($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid) { + $users[] = new User($uid, $backend); + if (!is_null($limit)) { + $limit--; + } + if (!is_null($offset) and $offset > 0) { + $offset--; + } + + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getUID(), $b->getUID()); + }); + return $users; + } + + /** + * search by displayName + * + * @param string $pattern + * @param int $limit + * @param int $offset + * @return \OC\User\User[] + */ + public function searchDisplayName($pattern, $limit = null, $offset = null) { + $users = array(); + foreach ($this->backends as $backend) { + $backendUsers = $backend->getDisplayNames($pattern, $limit, $offset); + if (is_array($backendUsers)) { + foreach ($backendUsers as $uid => $displayName) { + $users[] = new User($uid, $backend); + if (!is_null($limit)) { + $limit--; + } + if (!is_null($offset) and $offset > 0) { + $offset--; + } + + } + } + } + + usort($users, function ($a, $b) { + /** + * @var \OC\User\User $a + * @var \OC\User\User $b + */ + return strcmp($a->getDisplayName(), $b->getDisplayName()); + }); + return $users; + } + + /** + * @param string $uid + * @param string $password + * @throws \Exception + * @return bool | \OC\User\User the created user of false + */ + public function createUser($uid, $password) { + // Check the name for bad characters + // Allowed are: "a-z", "A-Z", "0-9" and "_.@-" + if (preg_match('/[^a-zA-Z0-9 _\.@\-]/', $uid)) { + throw new \Exception('Only the following characters are allowed in a username:' + . ' "a-z", "A-Z", "0-9", and "_.@-"'); + } + // No empty username + if (trim($uid) == '') { + throw new \Exception('A valid username must be provided'); + } + // No empty password + if (trim($password) == '') { + throw new \Exception('A valid password must be provided'); + } + + // Check if user already exists + if ($this->userExists($uid)) { + throw new \Exception('The username is already being used'); + } + + $this->emit('\OC\User', 'preCreateUser', array($uid, $password)); + foreach ($this->backends as $backend) { + if ($backend->implementsActions(\OC_USER_BACKEND_CREATE_USER)) { + $backend->createUser($uid, $password); + $user = new User($uid, $backend); + $this->emit('\OC\User', 'postCreateUser', array($user)); + return $user; + } + } + return false; + } +} diff --git a/lib/user/session.php b/lib/user/session.php new file mode 100644 index 00000000000..b0fdcd3e850 --- /dev/null +++ b/lib/user/session.php @@ -0,0 +1,161 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\Emitter; + +/** + * Class Session + * + * Hooks available in scope \OC\User: + * - preSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - postSetPassword(\OC\User\User $user, string $password, string $recoverPassword) + * - preDelete(\OC\User\User $user) + * - postDelete(\OC\User\User $user) + * - preCreateUser(string $uid, string $password) + * - postCreateUser(\OC\User\User $user) + * - preLogin(string $user, string $password) + * - postLogin(\OC\User\User $user) + * - logout() + * + * @package OC\User + */ +class Session implements Emitter { + /** + * @var \OC\User\Manager $manager + */ + private $manager; + + /** + * @var \OC\Session\Session $session + */ + private $session; + + /** + * @var \OC\User\User $activeUser + */ + protected $activeUser; + + /** + * @param \OC\User\Manager $manager + * @param \OC\Session\Session $session + */ + public function __construct($manager, $session) { + $this->manager = $manager; + $this->session = $session; + } + + /** + * @param string $scope + * @param string $method + * @param callable $callback + */ + public function listen($scope, $method, $callback) { + $this->manager->listen($scope, $method, $callback); + } + + /** + * @param string $scope optional + * @param string $method optional + * @param callable $callback optional + */ + public function removeListener($scope = null, $method = null, $callback = null) { + $this->manager->removeListener($scope, $method, $callback); + } + + /** + * @return \OC\User\Manager + */ + public function getManager() { + return $this->manager; + } + + /** + * set the currently active user + * + * @param \OC\User\User $user + */ + public function setUser($user) { + if (is_null($user)) { + $this->session->remove('user_id'); + } else { + $this->session->set('user_id', $user->getUID()); + } + $this->activeUser = $user; + } + + /** + * get the current active user + * + * @return \OC\User\User + */ + public function getUser() { + if ($this->activeUser) { + return $this->activeUser; + } else { + $uid = $this->session->get('user_id'); + if ($uid) { + $this->activeUser = $this->manager->get($uid); + return $this->activeUser; + } else { + return null; + } + } + } + + public function login($uid, $password) { + $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); + $user = $this->manager->get($uid); + if ($user) { + $result = $user->checkPassword($password); + if ($result and $user->isEnabled()) { + $this->manager->emit('\OC\User', 'postLogin', array($user)); + $this->setUser($user); + return true; + } else { + return false; + } + } else { + return false; + } + } + + public function logout() { + $this->manager->emit('\OC\User', 'logout'); + $this->setUser(null); + $this->unsetMagicInCookie(); + } + + /** + * Set cookie value to use in next page load + * + * @param string $username username to be set + * @param string $token + */ + public function setMagicInCookie($username, $token) { + $secure_cookie = \OC_Config::getValue("forcessl", false); //TODO: DI for cookies and OC_Config + $expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); + setcookie("oc_username", $username, $expires, OC::$WEBROOT, '', $secure_cookie); + setcookie("oc_token", $token, $expires, OC::$WEBROOT, '', $secure_cookie, true); + setcookie("oc_remember_login", true, $expires, OC::$WEBROOT, '', $secure_cookie); + } + + /** + * @brief Remove cookie for "remember username" + */ + public function unsetMagicInCookie() { + unset($_COOKIE["oc_username"]); //TODO: DI + unset($_COOKIE["oc_token"]); + unset($_COOKIE["oc_remember_login"]); + setcookie("oc_username", null, -1); + setcookie("oc_token", null, -1); + setcookie("oc_remember_login", null, -1); + } +} diff --git a/lib/user/user.php b/lib/user/user.php new file mode 100644 index 00000000000..095c37939a7 --- /dev/null +++ b/lib/user/user.php @@ -0,0 +1,177 @@ +<?php + +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\User; + +use OC\Hooks\Emitter; + +class User { + /** + * @var string $uid + */ + private $uid; + + /** + * @var string $displayName + */ + private $displayName; + + /** + * @var \OC_User_Backend $backend + */ + private $backend; + + /** + * @var bool $enabled + */ + private $enabled; + + /** + * @var Emitter | Manager $emitter + */ + private $emitter; + + /** + * @param string $uid + * @param \OC_User_Backend $backend + * @param Emitter $emitter + */ + public function __construct($uid, $backend, $emitter = null) { + $this->uid = $uid; + if ($backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { + $this->displayName = $backend->getDisplayName($uid); + } else { + $this->displayName = $uid; + } + $this->backend = $backend; + $this->emitter = $emitter; + $enabled = \OC_Preferences::getValue($uid, 'core', 'enabled', 'true'); //TODO: DI for OC_Preferences + $this->enabled = ($enabled === 'true'); + } + + /** + * @return string + */ + public function getUID() { + return $this->uid; + } + + /** + * @return string + */ + public function getDisplayName() { + return $this->displayName; + } + + /** + * @param string $displayName + * @return bool + */ + public function setDisplayName($displayName) { + if ($this->canChangeDisplayName()) { + $this->displayName = $displayName; + $this->backend->setDisplayName($this->uid, $displayName); + return true; + } else { + return false; + } + } + + /** + * @return bool + */ + public function delete() { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preDelete', array($this)); + } + $result = $this->backend->deleteUser($this->uid); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postDelete', array($this)); + } + return !($result === false); + } + + /** + * @param $password + * @return bool + */ + public function checkPassword($password) { + if ($this->backend->implementsActions(\OC_USER_BACKEND_CHECK_PASSWORD)) { + $result = $this->backend->checkPassword($this->uid, $password); + if ($result !== false) { + $this->uid = $result; + } + return !($result === false); + } else { + return false; + } + } + + /** + * @param string $password + * @param string $recoveryPassword for the encryption app to reset encryption keys + * @return bool + */ + public function setPassword($password, $recoveryPassword) { + if ($this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD)) { + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); + } + $result = $this->backend->setPassword($this->uid, $password); + if ($this->emitter) { + $this->emitter->emit('\OC\User', 'postSetPassword', array($this, $password, $recoveryPassword)); + } + return !($result === false); + } else { + return false; + } + } + + /** + * get the users home folder to mount + * + * @return string + */ + public function getHome() { + if ($this->backend->implementsActions(\OC_USER_BACKEND_GET_HOME)) { + return $this->backend->getHome($this->uid); + } + return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented + } + + /** + * @return bool + */ + public function canChangePassword() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD); + } + + /** + * @return bool + */ + public function canChangeDisplayName() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME); + } + + /** + * @return bool + */ + public function isEnabled() { + return $this->enabled; + } + + /** + * @param bool $enabled + */ + public function setEnabled($enabled) { + $this->enabled = $enabled; + $enabled = ($enabled) ? 'true' : 'false'; + \OC_Preferences::setValue($this->uid, 'core', 'enabled', $enabled); + } +} |