diff options
author | icewind1991 <icewind1991@gmail.com> | 2013-06-03 08:13:40 -0700 |
---|---|---|
committer | icewind1991 <icewind1991@gmail.com> | 2013-06-03 08:13:40 -0700 |
commit | 8c991d97aa8d2199d157ba9bc366af126b7764e3 (patch) | |
tree | 2c075b41a216065548b1791d11a62a66eb140417 /lib | |
parent | 2572c9a6b732d5304b69632942de16cfca3a88a3 (diff) | |
parent | 0ce2b2708c7d587e51fdf0bdb5b852863d2b0424 (diff) | |
download | nextcloud-server-8c991d97aa8d2199d157ba9bc366af126b7764e3.tar.gz nextcloud-server-8c991d97aa8d2199d157ba9bc366af126b7764e3.zip |
Merge pull request #3561 from owncloud/user
Refactor of user management
Diffstat (limited to 'lib')
-rw-r--r-- | lib/user.php | 546 | ||||
-rw-r--r-- | lib/user/backend.php | 22 | ||||
-rw-r--r-- | lib/user/dummy.php | 144 | ||||
-rw-r--r-- | lib/user/manager.php | 228 | ||||
-rw-r--r-- | lib/user/session.php | 173 | ||||
-rw-r--r-- | lib/user/user.php | 197 |
6 files changed, 899 insertions, 411 deletions
diff --git a/lib/user.php b/lib/user.php index 1dde87a1339..503ac3f7493 100644 --- a/lib/user.php +++ b/lib/user.php @@ -30,35 +30,85 @@ * post_createUser(uid, password) * pre_deleteUser(&run, uid) * post_deleteUser(uid) - * pre_setPassword(&run, uid, password) - * post_setPassword(uid, password) + * pre_setPassword(&run, uid, password, recoveryPassword) + * post_setPassword(uid, password, recoveryPassword) * pre_login(&run, uid, password) * post_login(uid) * logout() */ class OC_User { - // The backend used for user management - private static $_usedBackends = array(); + public static $userSession = null; + + private static function getUserSession() { + if (!self::$userSession) { + $manager = new \OC\User\Manager(); + self::$userSession = new \OC\User\Session($manager, \OC::$session); + self::$userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) { + \OC_Hook::emit('OC_User', 'pre_createUser', array('run' => true, 'uid' => $uid, 'password' => $password)); + }); + self::$userSession->listen('\OC\User', 'postCreateUser', function ($user, $password) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_createUser', array('uid' => $user->getUID(), 'password' => $password)); + }); + self::$userSession->listen('\OC\User', 'preDelete', function ($user) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'pre_deleteUser', array('run' => true, 'uid' => $user->getUID())); + }); + self::$userSession->listen('\OC\User', 'postDelete', function ($user) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_deleteUser', array('uid' => $user->getUID())); + }); + self::$userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) { + /** @var $user \OC\User\User */ + OC_Hook::emit('OC_User', 'pre_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); + }); + self::$userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) { + /** @var $user \OC\User\User */ + OC_Hook::emit('OC_User', 'post_setPassword', array('run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword)); + }); + self::$userSession->listen('\OC\User', 'preLogin', function ($uid, $password) { + \OC_Hook::emit('OC_User', 'pre_login', array('run' => true, 'uid' => $uid, 'password' => $password)); + }); + self::$userSession->listen('\OC\User', 'postLogin', function ($user, $password) { + /** @var $user \OC\User\User */ + \OC_Hook::emit('OC_User', 'post_login', array('run' => true, 'uid' => $user->getUID(), 'password' => $password)); + }); + self::$userSession->listen('\OC\User', 'logout', function () { + \OC_Hook::emit('OC_User', 'logout', array()); + }); + } + return self::$userSession; + } - private static $_setupedBackends = array(); + /** + * @return \OC\User\Manager + */ + private static function getManager() { + return self::getUserSession()->getManager(); + } - // Backends available (except database) private static $_backends = array(); + private static $_usedBackends = array(); + + private static $_setupedBackends = array(); + /** * @brief registers backend - * @param $name name of the backend - * @returns true/false + * @param string $backend name of the backend + * @deprecated Add classes by calling useBackend with a class instance instead + * @return bool * * Makes a list of backends that can be used by other modules */ - public static function registerBackend( $backend ) { + public static function registerBackend($backend) { self::$_backends[] = $backend; return true; } /** * @brief gets available backends + * @deprecated * @returns array of backends * * Returns the names of all backends. @@ -69,6 +119,7 @@ class OC_User { /** * @brief gets used backends + * @deprecated * @returns array of backends * * Returns the names of all used backends. @@ -79,33 +130,36 @@ class OC_User { /** * @brief Adds the backend to the list of used backends - * @param $backend default: database The backend to use for user managment - * @returns true/false + * @param string | OC_User_Backend $backend default: database The backend to use for user management + * @return bool * * Set the User Authentication Module */ - public static function useBackend( $backend = 'database' ) { - if($backend instanceof OC_User_Interface) { - OC_Log::write('core', 'Adding user backend instance of '.get_class($backend).'.', OC_Log::DEBUG); - self::$_usedBackends[get_class($backend)]=$backend; + public static function useBackend($backend = 'database') { + if ($backend instanceof OC_User_Interface) { + OC_Log::write('core', 'Adding user backend instance of ' . get_class($backend) . '.', OC_Log::DEBUG); + self::$_usedBackends[get_class($backend)] = $backend; + self::getManager()->registerBackend($backend); } else { // You'll never know what happens - if( null === $backend OR !is_string( $backend )) { + if (null === $backend OR !is_string($backend)) { $backend = 'database'; } // Load backend - switch( $backend ) { + switch ($backend) { case 'database': case 'mysql': case 'sqlite': - OC_Log::write('core', 'Adding user backend '.$backend.'.', OC_Log::DEBUG); + OC_Log::write('core', 'Adding user backend ' . $backend . '.', OC_Log::DEBUG); self::$_usedBackends[$backend] = new OC_User_Database(); + self::getManager()->registerBackend(self::$_usedBackends[$backend]); break; default: - OC_Log::write('core', 'Adding default user backend '.$backend.'.', OC_Log::DEBUG); + OC_Log::write('core', 'Adding default user backend ' . $backend . '.', OC_Log::DEBUG); $className = 'OC_USER_' . strToUpper($backend); self::$_usedBackends[$backend] = new $className(); + self::getManager()->registerBackend(self::$_usedBackends[$backend]); break; } } @@ -116,121 +170,73 @@ class OC_User { * remove all used backends */ public static function clearBackends() { - self::$_usedBackends=array(); + self::$_usedBackends = array(); + self::getManager()->clearBackends(); } /** * setup the configured backends in config.php */ public static function setupBackends() { - $backends=OC_Config::getValue('user_backends', array()); - foreach($backends as $i=>$config) { - $class=$config['class']; - $arguments=$config['arguments']; - if(class_exists($class)) { - if(array_search($i, self::$_setupedBackends)===false) { + $backends = OC_Config::getValue('user_backends', array()); + foreach ($backends as $i => $config) { + $class = $config['class']; + $arguments = $config['arguments']; + if (class_exists($class)) { + if (array_search($i, self::$_setupedBackends) === false) { // make a reflection object $reflectionObj = new ReflectionClass($class); // use Reflection to create a new instance, using the $args $backend = $reflectionObj->newInstanceArgs($arguments); self::useBackend($backend); - $_setupedBackends[]=$i; + $_setupedBackends[] = $i; } else { - OC_Log::write('core', 'User backend '.$class.' already initialized.', OC_Log::DEBUG); + OC_Log::write('core', 'User backend ' . $class . ' already initialized.', OC_Log::DEBUG); } } else { - OC_Log::write('core', 'User backend '.$class.' not found.', OC_Log::ERROR); + OC_Log::write('core', 'User backend ' . $class . ' not found.', OC_Log::ERROR); } } } /** * @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 + * @param string $uid The username of the user to create + * @param string $password The password of the new user + * @throws Exception + * @return bool true/false * * Creates a new user. Basic checking of username is done in OC_User * itself, not in its subclasses. * * Allowed characters in the username are: "a-z", "A-Z", "0-9" and "_.@-" */ - public static 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( self::userExistsForCreation($uid) ) { - throw new Exception('The username is already being used'); - } - - - $run = true; - OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => $uid, "password" => $password )); - - if( $run ) { - //create the user in the first backend that supports creating users - foreach(self::$_usedBackends as $backend) { - if(!$backend->implementsActions(OC_USER_BACKEND_CREATE_USER)) - continue; - - $backend->createUser($uid, $password); - OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => $uid, "password" => $password )); - - return self::userExists($uid); - } - } - return false; + public static function createUser($uid, $password) { + self::getManager()->createUser($uid, $password); } /** * @brief delete a user - * @param $uid The username of the user to delete - * @returns true/false + * @param string $uid The username of the user to delete + * @return bool * * Deletes a user */ - public static function deleteUser( $uid ) { - $run = true; - OC_Hook::emit( "OC_User", "pre_deleteUser", array( "run" => &$run, "uid" => $uid )); - - if( $run ) { - //delete the user from all backends - foreach(self::$_usedBackends as $backend) { - $backend->deleteUser($uid); - } - if (self::userExists($uid)) { - return false; - } + public static function deleteUser($uid) { + $user = self::getManager()->get($uid); + if ($user) { + $user->delete(); + // We have to delete the user from all groups - foreach( OC_Group::getUserGroups( $uid ) as $i ) { - OC_Group::removeFromGroup( $uid, $i ); + foreach (OC_Group::getUserGroups($uid) as $i) { + OC_Group::removeFromGroup($uid, $i); } // Delete the user's keys in preferences OC_Preferences::deleteUser($uid); // Delete user files in /data/ - OC_Helper::rmdirr(OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/'.$uid.'/'); - - // Emit and exit - OC_Hook::emit( "OC_User", "post_deleteUser", array( "uid" => $uid )); - return true; - } - else{ - return false; + OC_Helper::rmdirr(OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid . '/'); } } @@ -238,75 +244,34 @@ class OC_User { * @brief Try to login a user * @param $uid The username of the user to log in * @param $password The password of the user - * @returns true/false + * @return bool * * Log in a user and regenerate a new session - if the password is ok */ - public static function login( $uid, $password ) { - $run = true; - OC_Hook::emit( "OC_User", "pre_login", array( "run" => &$run, "uid" => $uid, "password" => $password)); - - if( $run ) { - $uid = self::checkPassword( $uid, $password ); - $enabled = self::isEnabled($uid); - if($uid && $enabled) { - session_regenerate_id(true); - self::setUserId($uid); - self::setDisplayName($uid); - OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password )); - return true; - } - } - return false; + public static function login($uid, $password) { + return self::getUserSession()->login($uid, $password); } /** * @brief Sets user id for session and triggers emit */ public static function setUserId($uid) { - \OC::$session->set('user_id', $uid); + OC::$session->set('user_id', $uid); } /** * @brief Sets user display name for session */ public static function setDisplayName($uid, $displayName = null) { - $result = false; - if ($displayName ) { - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) { - if($backend->userExists($uid)) { - $result |= $backend->setDisplayName($uid, $displayName); - } - } - } - } else { - $displayName = self::determineDisplayName($uid); - $result = true; - } - if (OC_User::getUser() === $uid) { - \OC::$session->set('display_name', $displayName); + if (is_null($displayName)) { + $displayName = $uid; } - return $result; - } - - - /** - * @brief get display name - * @param $uid The username - * @returns string display name or uid if no display name is defined - * - */ - private static function determineDisplayName( $uid ) { - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_GET_DISPLAYNAME)) { - $result=$backend->getDisplayName( $uid ); - if($result) { - return $result; - } - } + $user = self::getManager()->get($uid); + if ($user) { + return $user->setDisplayName($displayName); + } else { + return false; } - return $uid; } /** @@ -315,36 +280,31 @@ class OC_User { * Logout, destroys session */ public static function logout() { - OC_Hook::emit( "OC_User", "logout", array()); - session_unset(); - session_destroy(); - OC_User::unsetMagicInCookie(); + self::getUserSession()->logout(); } /** * @brief Check if the user is logged in - * @returns true/false + * @returns bool * * Checks if the user is logged in */ public static function isLoggedIn() { - if( \OC::$session->get('user_id')) { + if (\OC::$session->get('user_id')) { OC_App::loadApps(array('authentication')); self::setupBackends(); - if (self::userExists(\OC::$session->get('user_id')) ) { - return true; - } + return self::userExists(\OC::$session->get('user_id')); } return false; } /** * @brief Check if the user is an admin user - * @param $uid uid of the admin - * @returns bool + * @param string $uid uid of the admin + * @return bool */ public static function isAdminUser($uid) { - if(OC_Group::inGroup($uid, 'admin' )) { + if (OC_Group::inGroup($uid, 'admin')) { return true; } return false; @@ -356,32 +316,40 @@ class OC_User { * @return string uid or false */ public static function getUser() { - if( \OC::$session->get('user_id') ) { - return \OC::$session->get('user_id'); - } - else{ + $uid = OC::$session->get('user_id'); + if (!is_null($uid)) { + return $uid; + } else { return false; } } /** * @brief get the display name of the user currently logged in. + * @param string $uid * @return string uid or false */ - public static function getDisplayName($user=null) { - if ( $user ) { - return self::determineDisplayName($user); - } else if( \OC::$session->get('display_name') ) { - return \OC::$session->get('display_name'); - } - else{ - return false; + public static function getDisplayName($uid = null) { + if ($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->getDisplayName(); + } else { + return $uid; + } + } else { + $user = self::getUserSession()->getUser(); + if ($user) { + return $user->getDisplayName(); + } else { + return false; + } } } /** * @brief Autogenerate a password - * @returns string + * @return string * * generates a password */ @@ -391,112 +359,89 @@ class OC_User { /** * @brief Set password - * @param $uid The username - * @param $password The new password - * @param $recoveryPassword for the encryption app to reset encryption keys - * @returns true/false + * @param string $uid The username + * @param string $password The new password + * @param string $recoveryPassword for the encryption app to reset encryption keys + * @return bool * * Change the password of a user */ - public static function setPassword( $uid, $password, $recoveryPassword = null ) { - $run = true; - OC_Hook::emit( "OC_User", "pre_setPassword", array( "run" => &$run, "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); - - if( $run ) { - $success = false; - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) { - if($backend->userExists($uid)) { - $success |= $backend->setPassword($uid, $password); - } - } - } - // invalidate all login cookies - OC_Preferences::deleteApp($uid, 'login_token'); - OC_Hook::emit( "OC_User", "post_setPassword", array( "uid" => $uid, "password" => $password, "recoveryPassword" => $recoveryPassword )); - return $success; - } - else{ + public static function setPassword($uid, $password, $recoveryPassword = null) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->setPassword($password, $recoveryPassword); + } else { return false; } } /** * @brief Check whether user can change his password - * @param $uid The username - * @returns true/false + * @param string $uid The username + * @return bool * * Check whether a specified user can change his password */ public static function canUserChangePassword($uid) { - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_SET_PASSWORD)) { - if($backend->userExists($uid)) { - return true; - } - } + $user = self::getManager()->get($uid); + if ($user) { + return $user->canChangePassword(); + } else { + return false; } - return false; } /** * @brief Check whether user can change his display name - * @param $uid The username - * @returns true/false + * @param string $uid The username + * @return bool * * Check whether a specified user can change his display name */ public static function canUserChangeDisplayName($uid) { - if (OC_Config::getValue('allow_user_to_change_display_name', true)) { - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_SET_DISPLAYNAME)) { - if($backend->userExists($uid)) { - return true; - } - } - } + $user = self::getManager()->get($uid); + if ($user) { + return $user->canChangeDisplayName(); + } else { + return false; } - return false; } /** * @brief Check if the password is correct - * @param $uid The username - * @param $password The password - * @returns string + * @param string $uid The username + * @param string $password The password + * @return bool * * Check if the password is correct without logging in the user * returns the user id or false */ - public static function checkPassword( $uid, $password ) { - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_CHECK_PASSWORD)) { - $result=$backend->checkPassword( $uid, $password ); - if($result) { - return $result; - } + public static function checkPassword($uid, $password) { + $user = self::getManager()->get($uid); + if ($user) { + if ($user->checkPassword($password)) { + return $user->getUID(); + } else { + return false; } + } else { + return false; } } /** - * @brief Check if the password is correct * @param string $uid The username - * @param string $password The password - * @returns string + * @return string * * returns the path to the users home directory */ public static function getHome($uid) { - foreach(self::$_usedBackends as $backend) { - if($backend->implementsActions(OC_USER_BACKEND_GET_HOME) && $backend->userExists($uid)) { - $result=$backend->getHome($uid); - if($result) { - return $result; - } - } + $user = self::getManager()->get($uid); + if ($user) { + return $user->getHome(); + } else { + return OC_Config::getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid; } - return OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ) . '/' . $uid; } /** @@ -506,152 +451,93 @@ class OC_User { * Get a list of all users. */ public static function getUsers($search = '', $limit = null, $offset = null) { - $users = array(); - foreach (self::$_usedBackends as $backend) { - $backendUsers = $backend->getUsers($search, $limit, $offset); - if (is_array($backendUsers)) { - $users = array_merge($users, $backendUsers); - } + $users = self::getManager()->search($search, $limit, $offset); + $uids = array(); + foreach ($users as $user) { + $uids[] = $user->getUID(); } - asort($users); - return $users; + return $uids; } /** * @brief Get a list of all users display name - * @returns associative array with all display names (value) and corresponding uids (key) + * @param string $search + * @param int $limit + * @param int $offset + * @return array associative array with all display names (value) and corresponding uids (key) * * Get a list of all display names and user ids. */ public static function getDisplayNames($search = '', $limit = null, $offset = null) { $displayNames = array(); - foreach (self::$_usedBackends as $backend) { - $backendDisplayNames = $backend->getDisplayNames($search, $limit, $offset); - if (is_array($backendDisplayNames)) { - $displayNames = $displayNames + $backendDisplayNames; - } + $users = self::getManager()->searchDisplayName($search, $limit, $offset); + foreach ($users as $user) { + $displayNames[$user->getUID()] = $user->getDisplayName(); } - asort($displayNames); return $displayNames; } /** * @brief check if a user exists * @param string $uid the username - * @param string $excludingBackend (default none) * @return boolean */ - public static function userExists($uid, $excludingBackend=null) { - foreach(self::$_usedBackends as $backend) { - if (!is_null($excludingBackend) && !strcmp(get_class($backend), $excludingBackend)) { - OC_Log::write('OC_User', $excludingBackend . 'excluded from user existance check.', OC_Log::DEBUG); - continue; - } - $result=$backend->userExists($uid); - if($result===true) { - return true; - } - } - return false; + public static function userExists($uid) { + return self::getManager()->userExists($uid); } - public static function userExistsForCreation($uid) { - foreach(self::$_usedBackends as $backend) { - if(!$backend->hasUserListings()) - continue; - - $result=$backend->userExists($uid); - if($result===true) { - return true; - } - } - return false; - } - /** * disables a user - * @param string $userid the user to disable + * + * @param string $uid the user to disable */ - public static function disableUser($userid) { - $sql = "INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, `configkey`, `configvalue`) VALUES(?, ?, ?, ?)"; - $stmt = OC_DB::prepare($sql); - if ( ! OC_DB::isError($stmt) ) { - $result = $stmt->execute(array($userid, 'core', 'enabled', 'false')); - if ( OC_DB::isError($result) ) { - OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } else { - OC_Log::write('OC_User', 'could not disable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR); + public static function disableUser($uid) { + $user = self::getManager()->get($uid); + if ($user) { + $user->setEnabled(false); } } /** * enable a user - * @param string $userid + * + * @param string $uid */ - public static function enableUser($userid) { - $sql = 'DELETE FROM `*PREFIX*preferences`' - ." WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?"; - $stmt = OC_DB::prepare($sql); - if ( ! OC_DB::isError($stmt) ) { - $result = $stmt->execute(array($userid, 'core', 'enabled', 'false')); - if ( OC_DB::isError($result) ) { - OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($result), OC_Log::ERROR); - } - } else { - OC_Log::write('OC_User', 'could not enable user: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR); + public static function enableUser($uid) { + $user = self::getManager()->get($uid); + if ($user) { + $user->setEnabled(true); } } /** * checks if a user is enabled - * @param string $userid + * + * @param string $uid * @return bool */ - public static function isEnabled($userid) { - $sql = 'SELECT `userid` FROM `*PREFIX*preferences`' - .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND `configvalue` = ?'; - if (OC_Config::getValue( 'dbtype', 'sqlite' ) === 'oci') { //FIXME oracle hack - $sql = 'SELECT `userid` FROM `*PREFIX*preferences`' - .' WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? AND to_char(`configvalue`) = ?'; - } - $stmt = OC_DB::prepare($sql); - if ( ! OC_DB::isError($stmt) ) { - $result = $stmt->execute(array($userid, 'core', 'enabled', 'false')); - if ( ! OC_DB::isError($result) ) { - return $result->numRows() ? false : true; - } else { - OC_Log::write('OC_User', - 'could not check if enabled: '. OC_DB::getErrorMessage($result), - OC_Log::ERROR); - } + public static function isEnabled($uid) { + $user = self::getManager()->get($uid); + if ($user) { + return $user->isEnabled(); } else { - OC_Log::write('OC_User', 'could not check if enabled: '. OC_DB::getErrorMessage($stmt), OC_Log::ERROR); + return false; } - return false; } /** * @brief Set cookie value to use in next page load * @param string $username username to be set + * @param string $token */ public static function setMagicInCookie($username, $token) { - $secure_cookie = OC_Config::getValue("forcessl", false); - $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); + self::getUserSession()->setMagicInCookie($username, $token); } /** * @brief Remove cookie for "remember username" */ public static function unsetMagicInCookie() { - unset($_COOKIE["oc_username"]); - 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); + self::getUserSession()->unsetMagicInCookie(); } } 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..d17cdf1a200 --- /dev/null +++ b/lib/user/manager.php @@ -0,0 +1,228 @@ +<?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, string $password) + * + * @package OC\User + */ +class Manager extends PublicEmitter { + /** + * @var \OC_User_Backend[] $backends + */ + private $backends = array(); + + private $cachedUsers = array(); + + public function __construct() { + $cachedUsers = $this->cachedUsers; + $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { + $i = array_search($user, $cachedUsers); + if ($i !== false) { + unset($cachedUsers[$i]); + } + }); + } + + /** + * register a user backend + * + * @param \OC_User_Backend $backend + */ + public function registerBackend($backend) { + $this->backends[] = $backend; + } + + /** + * remove a user backend + * + * @param \OC_User_Backend $backend + */ + public function removeBackend($backend) { + $this->cachedUsers = array(); + if (($i = array_search($backend, $this->backends)) !== false) { + unset($this->backends[$i]); + } + } + + /** + * remove all user backends + */ + public function clearBackends() { + $this->cachedUsers = array(); + $this->backends = array(); + } + + /** + * get a user by user id + * + * @param string $uid + * @return \OC\User\User + */ + public function get($uid) { + if (isset($this->cachedUsers[$uid])) { //check the cache first to prevent having to loop over the backends + return $this->cachedUsers[$uid]; + } + foreach ($this->backends as $backend) { + if ($backend->userExists($uid)) { + return $this->getUserObject($uid, $backend); + } + } + return null; + } + + /** + * get or construct the user object + * + * @param string $uid + * @param \OC_User_Backend $backend + * @return \OC\User\User + */ + protected function getUserObject($uid, $backend) { + if (isset($this->cachedUsers[$uid])) { + return $this->cachedUsers[$uid]; + } + $this->cachedUsers[$uid] = new User($uid, $backend, $this); + return $this->cachedUsers[$uid]; + } + + /** + * check if a user exists + * + * @param string $uid + * @return bool + */ + public function userExists($uid) { + $user = $this->get($uid); + return ($user !== null); + } + + /** + * 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[] = $this->getUserObject($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[] = $this->getUserObject($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 = $this->getUserObject($uid, $backend); + $this->emit('\OC\User', 'postCreateUser', array($user, $password)); + return $user; + } + } + return false; + } +} diff --git a/lib/user/session.php b/lib/user/session.php new file mode 100644 index 00000000000..cf93d9593af --- /dev/null +++ b/lib/user/session.php @@ -0,0 +1,173 @@ +<?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); + } + + /** + * get the manager object + * + * @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; + } + } + } + + /** + * try to login with the provided credentials + * + * @param string $uid + * @param string $password + * @return bool + */ + 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->setUser($user); + $this->manager->emit('\OC\User', 'postLogin', array($user, $password)); + return true; + } else { + return false; + } + } else { + return false; + } + } + + /** + * logout the user from the session + */ + 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); + } + + /** + * 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..f9466b71499 --- /dev/null +++ b/lib/user/user.php @@ -0,0 +1,197 @@ +<?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'); + } + + /** + * get the user id + * + * @return string + */ + public function getUID() { + return $this->uid; + } + + /** + * get the displayname for the user, if no specific displayname is set it will fallback to the user id + * + * @return string + */ + public function getDisplayName() { + return $this->displayName; + } + + /** + * set the displayname for the user + * + * @param string $displayName + * @return bool + */ + public function setDisplayName($displayName) { + if ($this->canChangeDisplayName()) { + $this->displayName = $displayName; + $result = $this->backend->setDisplayName($this->uid, $displayName); + return $result !== false; + } else { + return false; + } + } + + /** + * Delete the user + * + * @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); + } + + /** + * Check if the password is valid for the user + * + * @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; + } + } + + /** + * Set the password of the user + * + * @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) and $home = $this->backend->getHome($this->uid)) { + return $home; + } + return \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $this->uid; //TODO switch to Config object once implemented + } + + /** + * check if the backend supports changing passwords + * + * @return bool + */ + public function canChangePassword() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_PASSWORD); + } + + /** + * check if the backend supports changing display names + * + * @return bool + */ + public function canChangeDisplayName() { + return $this->backend->implementsActions(\OC_USER_BACKEND_SET_DISPLAYNAME); + } + + /** + * check if the user is enabled + * + * @return bool + */ + public function isEnabled() { + return $this->enabled; + } + + /** + * set the enabled status for the user + * + * @param bool $enabled + */ + public function setEnabled($enabled) { + $this->enabled = $enabled; + $enabled = ($enabled) ? 'true' : 'false'; + \OC_Preferences::setValue($this->uid, 'core', 'enabled', $enabled); + } +} |