File manager - Edit - /home/jardides/www/Jardi-design/images/administrator/User.tar
Back
User.php 0000604 00000027617 15247162313 0006210 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Bart Visscher <bartv@thisnet.nl> * @author Björn Schießle <bjoern@schiessle.org> * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\User; use OC\Accounts\AccountManager; use OC\Files\Cache\Storage; use OC\Hooks\Emitter; use OC_Helper; use OCP\IAvatarManager; use OCP\IImage; use OCP\IURLGenerator; use OCP\IUser; use OCP\IConfig; use OCP\UserInterface; use \OCP\IUserBackend; class User implements IUser { /** @var string $uid */ private $uid; /** @var string $displayName */ private $displayName; /** @var UserInterface $backend */ private $backend; /** @var bool $enabled */ private $enabled; /** @var Emitter|Manager $emitter */ private $emitter; /** @var string $home */ private $home; /** @var int $lastLogin */ private $lastLogin; /** @var \OCP\IConfig $config */ private $config; /** @var IAvatarManager */ private $avatarManager; /** @var IURLGenerator */ private $urlGenerator; /** * @param string $uid * @param UserInterface $backend * @param \OC\Hooks\Emitter $emitter * @param IConfig|null $config * @param IURLGenerator $urlGenerator */ public function __construct($uid, $backend, $emitter = null, IConfig $config = null, $urlGenerator = null) { $this->uid = $uid; $this->backend = $backend; $this->emitter = $emitter; if(is_null($config)) { $config = \OC::$server->getConfig(); } $this->config = $config; $this->urlGenerator = $urlGenerator; $enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true'); $this->enabled = ($enabled === 'true'); $this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0); if (is_null($this->urlGenerator)) { $this->urlGenerator = \OC::$server->getURLGenerator(); } } /** * get the user id * * @return string */ public function getUID() { return $this->uid; } /** * get the display name for the user, if no specific display name is set it will fallback to the user id * * @return string */ public function getDisplayName() { if (!isset($this->displayName)) { $displayName = ''; if ($this->backend and $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) { // get display name and strip whitespace from the beginning and end of it $backendDisplayName = $this->backend->getDisplayName($this->uid); if (is_string($backendDisplayName)) { $displayName = trim($backendDisplayName); } } if (!empty($displayName)) { $this->displayName = $displayName; } else { $this->displayName = $this->uid; } } return $this->displayName; } /** * set the displayname for the user * * @param string $displayName * @return bool */ public function setDisplayName($displayName) { $displayName = trim($displayName); if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName)) { $result = $this->backend->setDisplayName($this->uid, $displayName); if ($result) { $this->displayName = $displayName; $this->triggerChange('displayName', $displayName); } return $result !== false; } else { return false; } } /** * set the email address of the user * * @param string|null $mailAddress * @return void * @since 9.0.0 */ public function setEMailAddress($mailAddress) { $oldMailAddress = $this->getEMailAddress(); if($mailAddress === '') { $this->config->deleteUserValue($this->uid, 'settings', 'email'); } else { $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress); } if($oldMailAddress !== $mailAddress) { $this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress); } } /** * returns the timestamp of the user's last login or 0 if the user did never * login * * @return int */ public function getLastLogin() { return $this->lastLogin; } /** * updates the timestamp of the most recent login of this user */ public function updateLastLoginTimestamp() { $firstTimeLogin = ($this->lastLogin === 0); $this->lastLogin = time(); $this->config->setUserValue( $this->uid, 'login', 'lastLogin', $this->lastLogin); return $firstTimeLogin; } /** * Delete the user * * @return bool */ public function delete() { if ($this->emitter) { $this->emitter->emit('\OC\User', 'preDelete', array($this)); } // get the home now because it won't return it after user deletion $homePath = $this->getHome(); $result = $this->backend->deleteUser($this->uid); if ($result) { // FIXME: Feels like an hack - suggestions? $groupManager = \OC::$server->getGroupManager(); // We have to delete the user from all groups foreach ($groupManager->getUserGroupIds($this) as $groupId) { $group = $groupManager->get($groupId); if ($group) { \OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]); $group->removeUser($this); \OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]); } } // Delete the user's keys in preferences \OC::$server->getConfig()->deleteAllUserValues($this->uid); // Delete user files in /data/ if ($homePath !== false) { // FIXME: this operates directly on FS, should use View instead... // also this is not testable/mockable... \OC_Helper::rmdirr($homePath); } // Delete the users entry in the storage table Storage::remove('home::' . $this->uid); \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid); \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this); $notification = \OC::$server->getNotificationManager()->createNotification(); $notification->setUser($this->uid); \OC::$server->getNotificationManager()->markProcessed($notification); /** @var AccountManager $accountManager */ $accountManager = \OC::$server->query(AccountManager::class); $accountManager->deleteUser($this); if ($this->emitter) { $this->emitter->emit('\OC\User', 'postDelete', array($this)); } } return !($result === 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 = null) { if ($this->emitter) { $this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword)); } if ($this->backend->implementsActions(Backend::SET_PASSWORD)) { $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->home) { if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) { $this->home = $home; } elseif ($this->config) { $this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid; } else { $this->home = \OC::$SERVERROOT . '/data/' . $this->uid; } } return $this->home; } /** * Get the name of the backend class the user is connected with * * @return string */ public function getBackendClassName() { if($this->backend instanceof IUserBackend) { return $this->backend->getBackendName(); } return get_class($this->backend); } /** * check if the backend allows the user to change his avatar on Personal page * * @return bool */ public function canChangeAvatar() { if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) { return $this->backend->canChangeAvatar($this->uid); } return true; } /** * check if the backend supports changing passwords * * @return bool */ public function canChangePassword() { return $this->backend->implementsActions(Backend::SET_PASSWORD); } /** * check if the backend supports changing display names * * @return bool */ public function canChangeDisplayName() { if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) { return false; } return $this->backend->implementsActions(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) { $oldStatus = $this->isEnabled(); $this->enabled = $enabled; $enabled = ($enabled) ? 'true' : 'false'; if ($oldStatus !== $this->enabled) { $this->triggerChange('enabled', $enabled); $this->config->setUserValue($this->uid, 'core', 'enabled', $enabled); } } /** * get the users email address * * @return string|null * @since 9.0.0 */ public function getEMailAddress() { return $this->config->getUserValue($this->uid, 'settings', 'email', null); } /** * get the users' quota * * @return string * @since 9.0.0 */ public function getQuota() { $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default'); if($quota === 'default') { $quota = $this->config->getAppValue('files', 'default_quota', 'none'); } return $quota; } /** * set the users' quota * * @param string $quota * @return void * @since 9.0.0 */ public function setQuota($quota) { $oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', ''); if($quota !== 'none' and $quota !== 'default') { $quota = OC_Helper::computerFileSize($quota); $quota = OC_Helper::humanFileSize($quota); } $this->config->setUserValue($this->uid, 'files', 'quota', $quota); if($quota !== $oldQuota) { $this->triggerChange('quota', $quota); } } /** * get the avatar image if it exists * * @param int $size * @return IImage|null * @since 9.0.0 */ public function getAvatarImage($size) { // delay the initialization if (is_null($this->avatarManager)) { $this->avatarManager = \OC::$server->getAvatarManager(); } $avatar = $this->avatarManager->getAvatar($this->uid); $image = $avatar->get(-1); if ($image) { return $image; } return null; } /** * get the federation cloud id * * @return string * @since 9.0.0 */ public function getCloudId() { $uid = $this->getUID(); $server = $this->urlGenerator->getAbsoluteURL('/'); $server = rtrim( $this->removeProtocolFromUrl($server), '/'); return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId(); } /** * @param string $url * @return string */ private function removeProtocolFromUrl($url) { if (strpos($url, 'https://') === 0) { return substr($url, strlen('https://')); } else if (strpos($url, 'http://') === 0) { return substr($url, strlen('http://')); } return $url; } public function triggerChange($feature, $value = null, $oldValue = null) { if ($this->emitter) { $this->emitter->emit('\OC\User', 'changeUser', array($this, $feature, $value, $oldValue)); } } } UserWrapper.php 0000644 00000020065 15247162313 0007543 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2014 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\User; defined('JPATH_PLATFORM') or die; /** * Wrapper class for UserHelper * * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ class UserWrapper { /** * Helper wrapper method for addUserToGroup * * @param integer $userId The id of the user. * @param integer $groupId The id of the group. * * @return boolean True on success * * @see UserHelper::addUserToGroup() * @since 3.4 * @throws \RuntimeException * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function addUserToGroup($userId, $groupId) { return UserHelper::addUserToGroup($userId, $groupId); } /** * Helper wrapper method for getUserGroups * * @param integer $userId The id of the user. * * @return array List of groups * * @see UserHelper::addUserToGroup() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function getUserGroups($userId) { return UserHelper::getUserGroups($userId); } /** * Helper wrapper method for removeUserFromGroup * * @param integer $userId The id of the user. * @param integer $groupId The id of the group. * * @return boolean True on success * * @see UserHelper::removeUserFromGroup() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function removeUserFromGroup($userId, $groupId) { return UserHelper::removeUserFromGroup($userId, $groupId); } /** * Helper wrapper method for setUserGroups * * @param integer $userId The id of the user. * @param array $groups An array of group ids to put the user in. * * @return boolean True on success * * @see UserHelper::setUserGroups() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function setUserGroups($userId, $groups) { return UserHelper::setUserGroups($userId, $groups); } /** * Helper wrapper method for getProfile * * @param integer $userId The id of the user. * * @return object * * @see UserHelper::getProfile() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function getProfile($userId = 0) { return UserHelper::getProfile($userId); } /** * Helper wrapper method for activateUser * * @param string $activation Activation string * * @return boolean True on success * * @see UserHelper::activateUser() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function activateUser($activation) { return UserHelper::activateUser($activation); } /** * Helper wrapper method for getUserId * * @param string $username The username to search on. * * @return integer The user id or 0 if not found. * * @see UserHelper::getUserId() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function getUserId($username) { return UserHelper::getUserId($username); } /** * Helper wrapper method for hashPassword * * @param string $password The plaintext password to encrypt. * @param integer $algorithm The hashing algorithm to use, represented by `PASSWORD_*` constants. * @param array $options The options for the algorithm to use. * * @return string The encrypted password. * * @see UserHelper::hashPassword() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function hashPassword($password, $algorithm = PASSWORD_BCRYPT, array $options = array()) { return UserHelper::hashPassword($password, $algorithm, $options); } /** * Helper wrapper method for verifyPassword * * @param string $password The plaintext password to check. * @param string $hash The hash to verify against. * @param integer $userId ID of the user if the password hash should be updated * * @return boolean True if the password and hash match, false otherwise * * @see UserHelper::verifyPassword() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function verifyPassword($password, $hash, $userId = 0) { return UserHelper::verifyPassword($password, $hash, $userId); } /** * Helper wrapper method for getCryptedPassword * * @param string $plaintext The plaintext password to encrypt. * @param string $salt The salt to use to encrypt the password. [] * If not present, a new salt will be * generated. * @param string $encryption The kind of password encryption to use. * Defaults to md5-hex. * @param boolean $showEncrypt Some password systems prepend the kind of * encryption to the crypted password ({SHA}, * etc). Defaults to false. * * @return string The encrypted password. * * @see UserHelper::getCryptedPassword() * @since 3.4 * @deprecated 4.0 */ public function getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $showEncrypt = false) { return UserHelper::getCryptedPassword($plaintext, $salt, $encryption, $showEncrypt); } /** * Helper wrapper method for getSalt * * @param string $encryption The kind of password encryption to use. * Defaults to md5-hex. * @param string $seed The seed to get the salt from (probably a * previously generated password). Defaults to * generating a new seed. * @param string $plaintext The plaintext password that we're generating * a salt for. Defaults to none. * * @return string The generated or extracted salt. * * @see UserHelper::getSalt() * @since 3.4 * @deprecated 4.0 */ public function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '') { return UserHelper::getSalt($encryption, $seed, $plaintext); } /** * Helper wrapper method for genRandomPassword * * @param integer $length Length of the password to generate * * @return string Random Password * * @see UserHelper::genRandomPassword() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function genRandomPassword($length = 8) { return UserHelper::genRandomPassword($length); } /** * Helper wrapper method for invalidateCookie * * @param string $userId User ID for this user * @param string $cookieName Series id (cookie name decoded) * * @return boolean True on success * * @see UserHelper::invalidateCookie() * @since 3.4 * @deprecated 4.0 */ public function invalidateCookie($userId, $cookieName) { return UserHelper::invalidateCookie($userId, $cookieName); } /** * Helper wrapper method for clearExpiredTokens * * @return mixed Database query result * * @see UserHelper::clearExpiredTokens() * @since 3.4 * @deprecated 4.0 */ public function clearExpiredTokens() { return UserHelper::clearExpiredTokens(); } /** * Helper wrapper method for getRememberCookieData * * @return mixed An array of information from an authentication cookie or false if there is no cookie * * @see UserHelper::getRememberCookieData() * @since 3.4 * @deprecated 4.0 */ public function getRememberCookieData() { return UserHelper::getRememberCookieData(); } /** * Helper wrapper method for getShortHashedUserAgent * * @return string A hashed user agent string with version replaced by 'abcd' * * @see UserHelper::getShortHashedUserAgent() * @since 3.4 * @deprecated 4.0 Use `Joomla\CMS\User\UserHelper` directly */ public function getShortHashedUserAgent() { return UserHelper::getShortHashedUserAgent(); } } UserFactoryInterface.php 0000644 00000001670 15247162313 0011354 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\User; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface defining a factory which can create User objects * * @since 4.0.0 */ interface UserFactoryInterface { /** * Method to get an instance of a user for the given id. * * @param int $id The id * * @return User * * @since 4.0.0 */ public function loadUserById(int $id): User; /** * Method to get an instance of a user for the given username. * * @param string $username The username * * @return User * * @since 4.0.0 */ public function loadUserByUsername(string $username): User; } CurrentUserTrait.php 0000644 00000003005 15247162313 0010544 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE */ namespace Joomla\CMS\User; use Joomla\CMS\Factory; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Trait for classes which require a user to work with. * * @since 4.2.0 */ trait CurrentUserTrait { /** * The current user object. * * @var User * @since 4.2.0 */ private $currentUser; /** * Returns the current user, if none is set the identity of the global app * is returned. This will change in 5.0 and an empty user will be returned. * * @return User * * @since 4.2.0 */ protected function getCurrentUser(): User { if (!$this->currentUser) { @trigger_error( sprintf('User must be set in %s. This will not be caught anymore in 5.0', __METHOD__), E_USER_DEPRECATED ); $this->currentUser = Factory::getApplication()->getIdentity() ?: Factory::getUser(); } return $this->currentUser; } /** * Sets the current user. * * @param User $currentUser The current user object * * @return void * * @since 4.2.0 */ public function setCurrentUser(User $currentUser): void { $this->currentUser = $currentUser; } } UserFactory.php 0000644 00000003350 15247162313 0007530 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\User; use Joomla\Database\DatabaseInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Default factory for creating User objects * * @since 4.0.0 */ class UserFactory implements UserFactoryInterface { /** * The database. * * @var DatabaseInterface */ private $db; /** * UserFactory constructor. * * @param DatabaseInterface $db The database */ public function __construct(DatabaseInterface $db) { $this->db = $db; } /** * Method to get an instance of a user for the given id. * * @param int $id The id * * @return User * * @since 4.0.0 */ public function loadUserById(int $id): User { return new User($id); } /** * Method to get an instance of a user for the given username. * * @param string $username The username * * @return User * * @since 4.0.0 */ public function loadUserByUsername(string $username): User { // Initialise some variables $query = $this->db->getQuery(true) ->select($this->db->quoteName('id')) ->from($this->db->quoteName('#__users')) ->where($this->db->quoteName('username') . ' = :username') ->bind(':username', $username) ->setLimit(1); $this->db->setQuery($query); return $this->loadUserById((int) $this->db->loadResult()); } } UserHelper.php 0000644 00000055703 15247162313 0007351 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2007 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\User; defined('JPATH_PLATFORM') or die; use Joomla\CMS\Access\Access; use Joomla\CMS\Plugin\PluginHelper; use Joomla\Utilities\ArrayHelper; /** * Authorisation helper class, provides static methods to perform various tasks relevant * to the Joomla user and authorisation classes * * This class has influences and some method logic from the Horde Auth package * * @since 1.7.0 */ abstract class UserHelper { /** * Method to add a user to a group. * * @param integer $userId The id of the user. * @param integer $groupId The id of the group. * * @return boolean True on success * * @since 1.7.0 * @throws \RuntimeException */ public static function addUserToGroup($userId, $groupId) { // Get the user object. $user = new User((int) $userId); // Add the user to the group if necessary. if (!in_array($groupId, $user->groups)) { // Check whether the group exists. $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__usergroups')) ->where($db->quoteName('id') . ' = ' . (int) $groupId); $db->setQuery($query); // If the group does not exist, return an exception. if ($db->loadResult() === null) { throw new \RuntimeException('Access Usergroup Invalid'); } // Add the group data to the user object. $user->groups[$groupId] = $groupId; // Store the user object. $user->save(); } // Set the group data for any preloaded user objects. $temp = User::getInstance((int) $userId); $temp->groups = $user->groups; if (\JFactory::getSession()->getId()) { // Set the group data for the user object in the session. $temp = \JFactory::getUser(); if ($temp->id == $userId) { $temp->groups = $user->groups; } } return true; } /** * Method to get a list of groups a user is in. * * @param integer $userId The id of the user. * * @return array List of groups * * @since 1.7.0 */ public static function getUserGroups($userId) { // Get the user object. $user = User::getInstance((int) $userId); return isset($user->groups) ? $user->groups : array(); } /** * Method to remove a user from a group. * * @param integer $userId The id of the user. * @param integer $groupId The id of the group. * * @return boolean True on success * * @since 1.7.0 */ public static function removeUserFromGroup($userId, $groupId) { // Get the user object. $user = User::getInstance((int) $userId); // Remove the user from the group if necessary. $key = array_search($groupId, $user->groups); if ($key !== false) { // Remove the user from the group. unset($user->groups[$key]); // Store the user object. $user->save(); } // Set the group data for any preloaded user objects. $temp = \JFactory::getUser((int) $userId); $temp->groups = $user->groups; // Set the group data for the user object in the session. $temp = \JFactory::getUser(); if ($temp->id == $userId) { $temp->groups = $user->groups; } return true; } /** * Method to set the groups for a user. * * @param integer $userId The id of the user. * @param array $groups An array of group ids to put the user in. * * @return boolean True on success * * @since 1.7.0 */ public static function setUserGroups($userId, $groups) { // Get the user object. $user = User::getInstance((int) $userId); // Set the group ids. $groups = ArrayHelper::toInteger($groups); $user->groups = $groups; // Get the titles for the user groups. $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('id') . ', ' . $db->quoteName('title')) ->from($db->quoteName('#__usergroups')) ->where($db->quoteName('id') . ' = ' . implode(' OR ' . $db->quoteName('id') . ' = ', $user->groups)); $db->setQuery($query); $results = $db->loadObjectList(); // Set the titles for the user groups. for ($i = 0, $n = count($results); $i < $n; $i++) { $user->groups[$results[$i]->id] = $results[$i]->id; } // Store the user object. $user->save(); if (session_id()) { // Set the group data for any preloaded user objects. $temp = \JFactory::getUser((int) $userId); $temp->groups = $user->groups; // Set the group data for the user object in the session. $temp = \JFactory::getUser(); if ($temp->id == $userId) { $temp->groups = $user->groups; } } return true; } /** * Gets the user profile information * * @param integer $userId The id of the user. * * @return object * * @since 1.7.0 */ public static function getProfile($userId = 0) { if ($userId == 0) { $user = \JFactory::getUser(); $userId = $user->id; } // Get the dispatcher and load the user's plugins. $dispatcher = \JEventDispatcher::getInstance(); PluginHelper::importPlugin('user'); $data = new \JObject; $data->id = $userId; // Trigger the data preparation event. $dispatcher->trigger('onContentPrepareData', array('com_users.profile', &$data)); return $data; } /** * Method to activate a user * * @param string $activation Activation string * * @return boolean True on success * * @since 1.7.0 */ public static function activateUser($activation) { $db = \JFactory::getDbo(); // Let's get the id of the user we want to activate $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__users')) ->where($db->quoteName('activation') . ' = ' . $db->quote($activation)) ->where($db->quoteName('block') . ' = 1') ->where($db->quoteName('lastvisitDate') . ' = ' . $db->quote($db->getNullDate())); $db->setQuery($query); $id = (int) $db->loadResult(); // Is it a valid user to activate? if ($id) { $user = User::getInstance((int) $id); $user->set('block', '0'); $user->set('activation', ''); // Time to take care of business.... store the user. if (!$user->save()) { \JLog::add($user->getError(), \JLog::WARNING, 'jerror'); return false; } } else { \JLog::add(\JText::_('JLIB_USER_ERROR_UNABLE_TO_FIND_USER'), \JLog::WARNING, 'jerror'); return false; } return true; } /** * Returns userid if a user exists * * @param string $username The username to search on. * * @return integer The user id or 0 if not found. * * @since 1.7.0 */ public static function getUserId($username) { // Initialise some variables $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__users')) ->where($db->quoteName('username') . ' = ' . $db->quote($username)); $db->setQuery($query, 0, 1); return $db->loadResult(); } /** * Hashes a password using the current encryption. * * @param string $password The plaintext password to encrypt. * @param integer $algorithm The hashing algorithm to use, represented by `PASSWORD_*` constants. * @param array $options The options for the algorithm to use. * * @return string The encrypted password. * * @since 3.2.1 */ public static function hashPassword($password, $algorithm = PASSWORD_BCRYPT, array $options = array()) { // \JCrypt::hasStrongPasswordSupport() includes a fallback for us in the worst case \JCrypt::hasStrongPasswordSupport(); return password_hash($password, $algorithm, $options); } /** * Formats a password using the current encryption. If the user ID is given * and the hash does not fit the current hashing algorithm, it automatically * updates the hash. * * @param string $password The plaintext password to check. * @param string $hash The hash to verify against. * @param integer $userId ID of the user if the password hash should be updated * * @return boolean True if the password and hash match, false otherwise * * @since 3.2.1 */ public static function verifyPassword($password, $hash, $userId = 0) { $passwordAlgorithm = PASSWORD_BCRYPT; // If we are using phpass if (strpos($hash, '$P$') === 0) { // Use PHPass's portable hashes with a cost of 10. $phpass = new \PasswordHash(10, true); $match = $phpass->CheckPassword($password, $hash); $rehash = true; } // Check for Argon2id hashes elseif (strpos($hash, '$argon2id') === 0) { // This implementation is not supported through any existing polyfills $match = password_verify($password, $hash); $rehash = password_needs_rehash($hash, PASSWORD_ARGON2ID); $passwordAlgorithm = PASSWORD_ARGON2ID; } // Check for Argon2i hashes elseif (strpos($hash, '$argon2i') === 0) { // This implementation is not supported through any existing polyfills $match = password_verify($password, $hash); $rehash = password_needs_rehash($hash, PASSWORD_ARGON2I); $passwordAlgorithm = PASSWORD_ARGON2I; } // Check for bcrypt hashes elseif (strpos($hash, '$2') === 0) { // \JCrypt::hasStrongPasswordSupport() includes a fallback for us in the worst case \JCrypt::hasStrongPasswordSupport(); $match = password_verify($password, $hash); $rehash = password_needs_rehash($hash, PASSWORD_BCRYPT); } elseif (substr($hash, 0, 8) == '{SHA256}') { // Check the password $parts = explode(':', $hash); $salt = @$parts[1]; $testcrypt = static::getCryptedPassword($password, $salt, 'sha256', true); $match = \JCrypt::timingSafeCompare($hash, $testcrypt); $rehash = true; } else { // Check the password $parts = explode(':', $hash); $salt = @$parts[1]; $rehash = true; // Compile the hash to compare // If the salt is empty AND there is a ':' in the original hash, we must append ':' at the end $testcrypt = md5($password . $salt) . ($salt ? ':' . $salt : (strpos($hash, ':') !== false ? ':' : '')); $match = \JCrypt::timingSafeCompare($hash, $testcrypt); } // If we have a match and rehash = true, rehash the password with the current algorithm. if ((int) $userId > 0 && $match && $rehash) { $user = new User($userId); $user->password = static::hashPassword($password, $passwordAlgorithm); $user->save(); } return $match; } /** * Formats a password using the old encryption methods. * * @param string $plaintext The plaintext password to encrypt. * @param string $salt The salt to use to encrypt the password. [] * If not present, a new salt will be * generated. * @param string $encryption The kind of password encryption to use. * Defaults to md5-hex. * @param boolean $showEncrypt Some password systems prepend the kind of * encryption to the crypted password ({SHA}, * etc). Defaults to false. * * @return string The encrypted password. * * @since 1.7.0 * @deprecated 4.0 */ public static function getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $showEncrypt = false) { // Get the salt to use. $salt = static::getSalt($encryption, $salt, $plaintext); // Encrypt the password. switch ($encryption) { case 'plain': return $plaintext; case 'sha': $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext)); return ($showEncrypt) ? '{SHA}' . $encrypted : $encrypted; case 'crypt': case 'crypt-des': case 'crypt-md5': case 'crypt-blowfish': return ($showEncrypt ? '{crypt}' : '') . crypt($plaintext, $salt); case 'md5-base64': $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext)); return ($showEncrypt) ? '{MD5}' . $encrypted : $encrypted; case 'ssha': $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext . $salt) . $salt); return ($showEncrypt) ? '{SSHA}' . $encrypted : $encrypted; case 'smd5': $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext . $salt) . $salt); return ($showEncrypt) ? '{SMD5}' . $encrypted : $encrypted; case 'aprmd5': $length = strlen($plaintext); $context = $plaintext . '$apr1$' . $salt; $binary = static::_bin(md5($plaintext . $salt . $plaintext)); for ($i = $length; $i > 0; $i -= 16) { $context .= substr($binary, 0, ($i > 16 ? 16 : $i)); } for ($i = $length; $i > 0; $i >>= 1) { $context .= ($i & 1) ? chr(0) : $plaintext[0]; } $binary = static::_bin(md5($context)); for ($i = 0; $i < 1000; $i++) { $new = ($i & 1) ? $plaintext : substr($binary, 0, 16); if ($i % 3) { $new .= $salt; } if ($i % 7) { $new .= $plaintext; } $new .= ($i & 1) ? substr($binary, 0, 16) : $plaintext; $binary = static::_bin(md5($new)); } $p = array(); for ($i = 0; $i < 5; $i++) { $k = $i + 6; $j = $i + 12; if ($j == 16) { $j = 5; } $p[] = static::_toAPRMD5((ord($binary[$i]) << 16) | (ord($binary[$k]) << 8) | (ord($binary[$j])), 5); } return '$apr1$' . $salt . '$' . implode('', $p) . static::_toAPRMD5(ord($binary[11]), 3); case 'sha256': $encrypted = ($salt) ? hash('sha256', $plaintext . $salt) . ':' . $salt : hash('sha256', $plaintext); return ($showEncrypt) ? '{SHA256}' . $encrypted : '{SHA256}' . $encrypted; case 'md5-hex': default: $encrypted = ($salt) ? md5($plaintext . $salt) : md5($plaintext); return ($showEncrypt) ? '{MD5}' . $encrypted : $encrypted; } } /** * Returns a salt for the appropriate kind of password encryption using the old encryption methods. * Optionally takes a seed and a plaintext password, to extract the seed * of an existing password, or for encryption types that use the plaintext * in the generation of the salt. * * @param string $encryption The kind of password encryption to use. * Defaults to md5-hex. * @param string $seed The seed to get the salt from (probably a * previously generated password). Defaults to * generating a new seed. * @param string $plaintext The plaintext password that we're generating * a salt for. Defaults to none. * * @return string The generated or extracted salt. * * @since 1.7.0 * @deprecated 4.0 */ public static function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '') { // Encrypt the password. switch ($encryption) { case 'crypt': case 'crypt-des': if ($seed) { return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 2); } else { return substr(md5(mt_rand()), 0, 2); } break; case 'sha256': if ($seed) { return preg_replace('|^{sha256}|i', '', $seed); } else { return static::genRandomPassword(16); } break; case 'crypt-md5': if ($seed) { return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 12); } else { return '$1$' . substr(md5(\JCrypt::genRandomBytes()), 0, 8) . '$'; } break; case 'crypt-blowfish': if ($seed) { return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 30); } else { return '$2y$10$' . substr(md5(\JCrypt::genRandomBytes()), 0, 22) . '$'; } break; case 'ssha': if ($seed) { return substr(preg_replace('|^{SSHA}|', '', $seed), -20); } else { return mhash_keygen_s2k(MHASH_SHA1, $plaintext, substr(pack('h*', md5(\JCrypt::genRandomBytes())), 0, 8), 4); } break; case 'smd5': if ($seed) { return substr(preg_replace('|^{SMD5}|', '', $seed), -16); } else { return mhash_keygen_s2k(MHASH_MD5, $plaintext, substr(pack('h*', md5(\JCrypt::genRandomBytes())), 0, 8), 4); } break; case 'aprmd5': // 64 characters that are valid for APRMD5 passwords. $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; if ($seed) { return substr(preg_replace('/^\$apr1\$(.{8}).*/', '\\1', $seed), 0, 8); } else { $salt = ''; for ($i = 0; $i < 8; $i++) { $salt .= $APRMD5[mt_rand(0, 63)]; } return $salt; } break; default: $salt = ''; if ($seed) { $salt = $seed; } return $salt; break; } } /** * Generate a random password * * @param integer $length Length of the password to generate * * @return string Random Password * * @since 1.7.0 */ public static function genRandomPassword($length = 8) { $salt = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $base = strlen($salt); $makepass = ''; /* * Start with a cryptographic strength random string, then convert it to * a string with the numeric base of the salt. * Shift the base conversion on each character so the character * distribution is even, and randomize the start shift so it's not * predictable. */ $random = \JCrypt::genRandomBytes($length + 1); $shift = ord($random[0]); for ($i = 1; $i <= $length; ++$i) { $makepass .= $salt[($shift + ord($random[$i])) % $base]; $shift += ord($random[$i]); } return $makepass; } /** * Converts to allowed 64 characters for APRMD5 passwords. * * @param string $value The value to convert. * @param integer $count The number of characters to convert. * * @return string $value converted to the 64 MD5 characters. * * @since 1.7.0 */ protected static function _toAPRMD5($value, $count) { // 64 characters that are valid for APRMD5 passwords. $APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; $aprmd5 = ''; $count = abs($count); while (--$count) { $aprmd5 .= $APRMD5[$value & 0x3f]; $value >>= 6; } return $aprmd5; } /** * Converts hexadecimal string to binary data. * * @param string $hex Hex data. * * @return string Binary data. * * @since 1.7.0 */ private static function _bin($hex) { $bin = ''; $length = strlen($hex); for ($i = 0; $i < $length; $i += 2) { $tmp = sscanf(substr($hex, $i, 2), '%x'); $bin .= chr(array_shift($tmp)); } return $bin; } /** * Method to remove a cookie record from the database and the browser * * @param string $userId User ID for this user * @param string $cookieName Series id (cookie name decoded) * * @return boolean True on success * * @since 3.2 * @deprecated 4.0 This is handled in the authentication plugin itself. The 'invalid' column in the db should be removed as well */ public static function invalidateCookie($userId, $cookieName) { $db = \JFactory::getDbo(); $query = $db->getQuery(true); // Invalidate cookie in the database $query ->update($db->quoteName('#__user_keys')) ->set($db->quoteName('invalid') . ' = 1') ->where($db->quoteName('user_id') . ' = ' . $db->quote($userId)); $db->setQuery($query)->execute(); // Destroy the cookie in the browser. $app = \JFactory::getApplication(); $app->input->cookie->set($cookieName, '', 1, $app->get('cookie_path', '/'), $app->get('cookie_domain', '')); return true; } /** * Clear all expired tokens for all users. * * @return mixed Database query result * * @since 3.2 * @deprecated 4.0 This is handled in the authentication plugin itself */ public static function clearExpiredTokens() { $now = time(); $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->delete('#__user_keys') ->where($db->quoteName('time') . ' < ' . $db->quote($now)); return $db->setQuery($query)->execute(); } /** * Method to get the remember me cookie data * * @return mixed An array of information from an authentication cookie or false if there is no cookie * * @since 3.2 * @deprecated 4.0 This is handled in the authentication plugin itself */ public static function getRememberCookieData() { // Create the cookie name $cookieName = static::getShortHashedUserAgent(); // Fetch the cookie value $app = \JFactory::getApplication(); $cookieValue = $app->input->cookie->get($cookieName); if (!empty($cookieValue)) { return explode('.', $cookieValue); } else { return false; } } /** * Method to get a hashed user agent string that does not include browser version. * Used when frequent version changes cause problems. * * @return string A hashed user agent string with version replaced by 'abcd' * * @since 3.2 */ public static function getShortHashedUserAgent() { $ua = \JFactory::getApplication()->client; $uaString = $ua->userAgent; $browserVersion = $ua->browserVersion; if ($browserVersion) { $uaShort = str_replace($browserVersion, 'abcd', $uaString); } else { $uaShort = $uaString; } return md5(\JUri::base() . $uaShort); } /** * Check if there is a super user in the user ids. * * @param array $userIds An array of user IDs on which to operate * * @return boolean True on success, false on failure * * @since 3.6.5 */ public static function checkSuperUserInUsers(array $userIds) { foreach ($userIds as $userId) { foreach (static::getUserGroups($userId) as $userGroupId) { if (Access::checkGroup($userGroupId, 'core.admin')) { return true; } } } return false; } /** * Destroy all active session for a given user id * * @param int $userId Id of user * @param boolean $keepCurrent Keep the session of the currently acting user * @param int $clientId Application client id * * @return boolean * * @since 3.9.28 */ public static function destroyUserSessions($userId, $keepCurrent = false, $clientId = null) { $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select($db->quoteName('session_id')) ->from($db->quoteName('#__session')) ->where($db->quoteName('userid') . ' = ' . (int) $userId); if ($clientId !== null) { $query->where($db->quoteName('client_id') . ' = ' . (int) $clientId); } // Destroy all sessions for the user account $sessionIds = $db->setQuery( $query )->loadColumn(); // If true, removes the current session id from the purge list if ($keepCurrent) { $sessionIds = array_diff($sessionIds, array(\JFactory::getSession()->getId())); } // If there aren't any active sessions then there's nothing to do here if (empty($sessionIds)) { return false; } $storeName = \JFactory::getConfig()->get('session_handler', 'none'); $store = \JSessionStorage::getInstance($storeName); $quotedIds = array(); // Destroy the sessions and quote the IDs to purge the session table foreach ($sessionIds as $sessionId) { $store->destroy($sessionId); $quotedIds[] = $db->quoteBinary($sessionId); } $db->setQuery( $db->getQuery(true) ->delete($db->quoteName('#__session')) ->where($db->quoteName('session_id') . ' IN (' . implode(', ', $quotedIds) . ')') )->execute(); return true; } } CurrentUserInterface.php 0000644 00000001305 15247162313 0011362 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\User; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface to be implemented by classes depending on a current user. * * @since 4.2.0 */ interface CurrentUserInterface { /** * Sets the current user. * * @param User $currentUser The current user object * * @return void * * @since 4.2.0 */ public function setCurrentUser(User $currentUser): void; } Manager.php 0000604 00000035516 15247172772 0006653 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Joas Schilling <coding@schilljs.com> * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author Lukas Reschke <lukas@statuscode.ch> * @author Michael U <mdusher@users.noreply.github.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Chan <plus.vincchan@gmail.com> * @author Volkan Gezer <volkangezer@gmail.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\User; use OC\Hooks\PublicEmitter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IUser; use OCP\IUserBackend; use OCP\IUserManager; use OCP\IConfig; use OCP\UserInterface; /** * 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) * - change(\OC\User\User $user) * * @package OC\User */ class Manager extends PublicEmitter implements IUserManager { /** * @var \OCP\UserInterface[] $backends */ private $backends = array(); /** * @var \OC\User\User[] $cachedUsers */ private $cachedUsers = array(); /** * @var \OCP\IConfig $config */ private $config; /** * @param \OCP\IConfig $config */ public function __construct(IConfig $config) { $this->config = $config; $cachedUsers = &$this->cachedUsers; $this->listen('\OC\User', 'postDelete', function ($user) use (&$cachedUsers) { /** @var \OC\User\User $user */ unset($cachedUsers[$user->getUID()]); }); } /** * Get the active backends * @return \OCP\UserInterface[] */ public function getBackends() { return $this->backends; } /** * register a user backend * * @param \OCP\UserInterface $backend */ public function registerBackend($backend) { $this->backends[] = $backend; } /** * remove a user backend * * @param \OCP\UserInterface $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|null Either the user or null if the specified user does not exist */ public function get($uid) { if (is_null($uid) || $uid === '' || $uid === false) { return null; } 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 \OCP\UserInterface $backend * @param bool $cacheUser If false the newly created user object will not be cached * @return \OC\User\User */ protected function getUserObject($uid, $backend, $cacheUser = true) { if (isset($this->cachedUsers[$uid])) { return $this->cachedUsers[$uid]; } if (method_exists($backend, 'loginName2UserName')) { $loginName = $backend->loginName2UserName($uid); if ($loginName !== false) { $uid = $loginName; } if (isset($this->cachedUsers[$uid])) { return $this->cachedUsers[$uid]; } } $user = new User($uid, $backend, $this, $this->config); if ($cacheUser) { $this->cachedUsers[$uid] = $user; } return $user; } /** * check if a user exists * * @param string $uid * @return bool */ public function userExists($uid) { $user = $this->get($uid); return ($user !== null); } /** * Check if the password is valid for the user * * @param string $loginName * @param string $password * @return mixed the User object on success, false otherwise */ public function checkPassword($loginName, $password) { $result = $this->checkPasswordNoLogging($loginName, $password); if ($result === false) { \OC::$server->getLogger()->warning('Login failed: \''. $loginName .'\' (Remote IP: \''. \OC::$server->getRequest()->getRemoteAddress(). '\')', ['app' => 'core']); } return $result; } /** * Check if the password is valid for the user * * @internal * @param string $loginName * @param string $password * @return mixed the User object on success, false otherwise */ public function checkPasswordNoLogging($loginName, $password) { $loginName = str_replace("\0", '', $loginName); $password = str_replace("\0", '', $password); foreach ($this->backends as $backend) { if ($backend->implementsActions(Backend::CHECK_PASSWORD)) { $uid = $backend->checkPassword($loginName, $password); if ($uid !== false) { return $this->getUserObject($uid, $backend); } } } 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[$uid] = $this->getUserObject($uid, $backend); } } } uasort($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); } } } usort($users, function ($a, $b) { /** * @var \OC\User\User $a * @var \OC\User\User $b */ return strcmp(strtolower($a->getDisplayName()), strtolower($b->getDisplayName())); }); return $users; } /** * @param string $uid * @param string $password * @throws \InvalidArgumentException * @return bool|IUser the created user or false */ public function createUser($uid, $password) { $localBackends = []; foreach ($this->backends as $backend) { if ($backend instanceof Database) { // First check if there is another user backend $localBackends[] = $backend; continue; } if ($backend->implementsActions(Backend::CREATE_USER)) { return $this->createUserFromBackend($uid, $password, $backend); } } foreach ($localBackends as $backend) { if ($backend->implementsActions(Backend::CREATE_USER)) { return $this->createUserFromBackend($uid, $password, $backend); } } return false; } /** * @param string $uid * @param string $password * @param UserInterface $backend * @return IUser|null * @throws \InvalidArgumentException */ public function createUserFromBackend($uid, $password, UserInterface $backend) { $l = \OC::$server->getL10N('lib'); // 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 \InvalidArgumentException($l->t('Only the following characters are allowed in a username:' . ' "a-z", "A-Z", "0-9", and "_.@-\'"')); } // No empty username if (trim($uid) === '') { throw new \InvalidArgumentException($l->t('A valid username must be provided')); } // No whitespace at the beginning or at the end if (trim($uid) !== $uid) { throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end')); } // Username only consists of 1 or 2 dots (directory traversal) if ($uid === '.' || $uid === '..') { throw new \InvalidArgumentException($l->t('Username must not consist of dots only')); } // No empty password if (trim($password) === '') { throw new \InvalidArgumentException($l->t('A valid password must be provided')); } // Check if user already exists if ($this->userExists($uid)) { throw new \InvalidArgumentException($l->t('The username is already being used')); } $this->emit('\OC\User', 'preCreateUser', [$uid, $password]); $backend->createUser($uid, $password); $user = $this->getUserObject($uid, $backend); if ($user instanceof IUser) { $this->emit('\OC\User', 'postCreateUser', [$user, $password]); } return $user; } /** * returns how many users per backend exist (if supported by backend) * * @param boolean $hasLoggedIn when true only users that have a lastLogin * entry in the preferences table will be affected * @return array|int an array of backend class as key and count number as value * if $hasLoggedIn is true only an int is returned */ public function countUsers($hasLoggedIn = false) { if ($hasLoggedIn) { return $this->countSeenUsers(); } $userCountStatistics = []; foreach ($this->backends as $backend) { if ($backend->implementsActions(Backend::COUNT_USERS)) { $backendUsers = $backend->countUsers(); if($backendUsers !== false) { if($backend instanceof IUserBackend) { $name = $backend->getBackendName(); } else { $name = get_class($backend); } if(isset($userCountStatistics[$name])) { $userCountStatistics[$name] += $backendUsers; } else { $userCountStatistics[$name] = $backendUsers; } } } } return $userCountStatistics; } /** * The callback is executed for each user on each backend. * If the callback returns false no further users will be retrieved. * * @param \Closure $callback * @param string $search * @param boolean $onlySeen when true only users that have a lastLogin entry * in the preferences table will be affected * @since 9.0.0 */ public function callForAllUsers(\Closure $callback, $search = '', $onlySeen = false) { if ($onlySeen) { $this->callForSeenUsers($callback); } else { foreach ($this->getBackends() as $backend) { $limit = 500; $offset = 0; do { $users = $backend->getUsers($search, $limit, $offset); foreach ($users as $uid) { if (!$backend->userExists($uid)) { continue; } $user = $this->getUserObject($uid, $backend, false); $return = $callback($user); if ($return === false) { break; } } $offset += $limit; } while (count($users) >= $limit); } } } /** * returns how many users have logged in once * * @return int * @since 12.0.0 */ public function countDisabledUsers() { $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); $queryBuilder->select($queryBuilder->createFunction('COUNT(*)')) ->from('preferences') ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('core'))) ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('enabled'))) ->andWhere($queryBuilder->expr()->eq('configvalue', $queryBuilder->createNamedParameter('false'), IQueryBuilder::PARAM_STR)); $query = $queryBuilder->execute(); $result = (int)$query->fetchColumn(); $query->closeCursor(); return $result; } /** * returns how many users have logged in once * * @return int * @since 11.0.0 */ public function countSeenUsers() { $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); $queryBuilder->select($queryBuilder->createFunction('COUNT(*)')) ->from('preferences') ->where($queryBuilder->expr()->eq('appid', $queryBuilder->createNamedParameter('login'))) ->andWhere($queryBuilder->expr()->eq('configkey', $queryBuilder->createNamedParameter('lastLogin'))) ->andWhere($queryBuilder->expr()->isNotNull('configvalue')); $query = $queryBuilder->execute(); $result = (int)$query->fetchColumn(); $query->closeCursor(); return $result; } /** * @param \Closure $callback * @since 11.0.0 */ public function callForSeenUsers(\Closure $callback) { $limit = 1000; $offset = 0; do { $userIds = $this->getSeenUserIds($limit, $offset); $offset += $limit; foreach ($userIds as $userId) { foreach ($this->backends as $backend) { if ($backend->userExists($userId)) { $user = $this->getUserObject($userId, $backend, false); $return = $callback($user); if ($return === false) { return; } } } } } while (count($userIds) >= $limit); } /** * Getting all userIds that have a listLogin value requires checking the * value in php because on oracle you cannot use a clob in a where clause, * preventing us from doing a not null or length(value) > 0 check. * * @param int $limit * @param int $offset * @return string[] with user ids */ private function getSeenUserIds($limit = null, $offset = null) { $queryBuilder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); $queryBuilder->select(['userid']) ->from('preferences') ->where($queryBuilder->expr()->eq( 'appid', $queryBuilder->createNamedParameter('login')) ) ->andWhere($queryBuilder->expr()->eq( 'configkey', $queryBuilder->createNamedParameter('lastLogin')) ) ->andWhere($queryBuilder->expr()->isNotNull('configvalue') ); if ($limit !== null) { $queryBuilder->setMaxResults($limit); } if ($offset !== null) { $queryBuilder->setFirstResult($offset); } $query = $queryBuilder->execute(); $result = []; while ($row = $query->fetch()) { $result[] = $row['userid']; } $query->closeCursor(); return $result; } /** * @param string $email * @return IUser[] * @since 9.1.0 */ public function getByEmail($email) { $userIds = $this->config->getUsersForUserValue('settings', 'email', $email); return array_map(function($uid) { return $this->get($uid); }, $userIds); } } Database.php 0000604 00000024674 15247172772 0007010 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author adrien <adrien.waksberg@believedigital.com> * @author Aldo "xoen" Giambelluca <xoen@xoen.org> * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Bart Visscher <bartv@thisnet.nl> * @author Bjoern Schiessle <bjoern@schiessle.org> * @author Björn Schießle <bjoern@schiessle.org> * @author fabian <fabian@web2.0-apps.de> * @author Georg Ehrke <georg@owncloud.com> * @author Jakob Sack <mail@jakobsack.de> * @author Joas Schilling <coding@schilljs.com> * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author Lukas Reschke <lukas@statuscode.ch> * @author Michael Gapczynski <GapczynskiM@gmail.com> * @author Morris Jobke <hey@morrisjobke.de> * @author nishiki <nishiki@yaegashi.fr> * @author Robin Appelman <robin@icewind.nl> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ /* * * The following SQL statement is just a help for developers and will not be * executed! * * CREATE TABLE `users` ( * `uid` varchar(64) COLLATE utf8_unicode_ci NOT NULL, * `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL, * PRIMARY KEY (`uid`) * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; * */ namespace OC\User; use OC\Cache\CappedMemoryCache; use OCP\IUserBackend; use OCP\Util; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\GenericEvent; /** * Class for user management in a SQL Database (e.g. MySQL, SQLite) */ class Database extends Backend implements IUserBackend { /** @var CappedMemoryCache */ private $cache; /** @var EventDispatcher */ private $eventDispatcher; /** * \OC\User\Database constructor. * * @param EventDispatcher $eventDispatcher */ public function __construct($eventDispatcher = null) { $this->cache = new CappedMemoryCache(); $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->getEventDispatcher(); } /** * 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 (!$this->userExists($uid)) { $event = new GenericEvent($password); $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); $query = \OC_DB::prepare('INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )'); $result = $query->execute(array($uid, \OC::$server->getHasher()->hash($password))); // Clear cache unset($this->cache[$uid]); return $result ? true : false; } return false; } /** * delete a user * @param string $uid The username of the user to delete * @return bool * * Deletes a user */ public function deleteUser($uid) { // Delete user-group-relation $query = \OC_DB::prepare('DELETE FROM `*PREFIX*users` WHERE `uid` = ?'); $result = $query->execute(array($uid)); if (isset($this->cache[$uid])) { unset($this->cache[$uid]); } return $result ? true : false; } /** * 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 ($this->userExists($uid)) { $event = new GenericEvent($password); $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); $query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?'); $result = $query->execute(array(\OC::$server->getHasher()->hash($password), $uid)); return $result ? true : false; } return false; } /** * Set display name * @param string $uid The username * @param string $displayName The new display name * @return bool * * Change the display name of a user */ public function setDisplayName($uid, $displayName) { if ($this->userExists($uid)) { $query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `displayname` = ? WHERE LOWER(`uid`) = LOWER(?)'); $query->execute(array($displayName, $uid)); $this->cache[$uid]['displayname'] = $displayName; return true; } return false; } /** * get display name of the user * @param string $uid user ID of the user * @return string display name */ public function getDisplayName($uid) { $this->loadUser($uid); return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname']; } /** * Get a list of all display names and user ids. * * @param string $search * @param string|null $limit * @param string|null $offset * @return array an array of all displayNames (value) and the corresponding uids (key) */ public function getDisplayNames($search = '', $limit = null, $offset = null) { $parameters = []; $searchLike = ''; if ($search !== '') { $parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%'; $parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%'; $searchLike = ' WHERE LOWER(`displayname`) LIKE LOWER(?) OR ' . 'LOWER(`uid`) LIKE LOWER(?)'; } $displayNames = array(); $query = \OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users`' . $searchLike .' ORDER BY LOWER(`displayname`), LOWER(`uid`) ASC', $limit, $offset); $result = $query->execute($parameters); while ($row = $result->fetchRow()) { $displayNames[$row['uid']] = $row['displayname']; } return $displayNames; } /** * 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) { $query = \OC_DB::prepare('SELECT `uid`, `password` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)'); $result = $query->execute(array($uid)); $row = $result->fetchRow(); if ($row) { $storedHash = $row['password']; $newHash = ''; if(\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) { if(!empty($newHash)) { $this->setPassword($uid, $password); } return $row['uid']; } } return false; } /** * Load an user in the cache * @param string $uid the username * @return boolean true if user was found, false otherwise */ private function loadUser($uid) { $uid = (string) $uid; if (!isset($this->cache[$uid])) { //guests $uid could be NULL or '' if ($uid === '') { $this->cache[$uid]=false; return true; } $query = \OC_DB::prepare('SELECT `uid`, `displayname` FROM `*PREFIX*users` WHERE LOWER(`uid`) = LOWER(?)'); $result = $query->execute(array($uid)); if ($result === false) { Util::writeLog('core', \OC_DB::getErrorMessage(), Util::ERROR); return false; } $this->cache[$uid] = false; // "uid" is primary key, so there can only be a single result if ($row = $result->fetchRow()) { $this->cache[$uid]['uid'] = $row['uid']; $this->cache[$uid]['displayname'] = $row['displayname']; $result->closeCursor(); } else { $result->closeCursor(); return false; } } return true; } /** * Get a list of all users * * @param string $search * @param null|int $limit * @param null|int $offset * @return string[] an array of all uids */ public function getUsers($search = '', $limit = null, $offset = null) { $parameters = []; $searchLike = ''; if ($search !== '') { $parameters[] = '%' . \OC::$server->getDatabaseConnection()->escapeLikeParameter($search) . '%'; $searchLike = ' WHERE LOWER(`uid`) LIKE LOWER(?)'; } $query = \OC_DB::prepare('SELECT `uid` FROM `*PREFIX*users`' . $searchLike . ' ORDER BY LOWER(`uid`) ASC', $limit, $offset); $result = $query->execute($parameters); $users = array(); while ($row = $result->fetchRow()) { $users[] = $row['uid']; } return $users; } /** * check if a user exists * @param string $uid the username * @return boolean */ public function userExists($uid) { $this->loadUser($uid); return $this->cache[$uid] !== false; } /** * get the user's home directory * @param string $uid the username * @return string|false */ public function getHome($uid) { if ($this->userExists($uid)) { return \OC::$server->getConfig()->getSystemValue("datadirectory", \OC::$SERVERROOT . "/data") . '/' . $uid; } return false; } /** * @return bool */ public function hasUserListings() { return true; } /** * counts the users in the database * * @return int|bool */ public function countUsers() { $query = \OC_DB::prepare('SELECT COUNT(*) FROM `*PREFIX*users`'); $result = $query->execute(); if ($result === false) { Util::writeLog('core', \OC_DB::getErrorMessage(), Util::ERROR); return false; } return $result->fetchOne(); } /** * returns the username for the given login name in the correct casing * * @param string $loginName * @return string|false */ public function loginName2UserName($loginName) { if ($this->userExists($loginName)) { return $this->cache[$loginName]['uid']; } return false; } /** * Backend name to be shown in user management * @return string the name of the backend to be shown */ public function getBackendName(){ return 'Database'; } public static function preLoginNameUsedAsUserName($param) { if(!isset($param['uid'])) { throw new \Exception('key uid is expected to be set in $param'); } $backends = \OC::$server->getUserManager()->getBackends(); foreach ($backends as $backend) { if ($backend instanceof Database) { /** @var \OC\User\Database $backend */ $uid = $backend->loginName2UserName($param['uid']); if ($uid !== false) { $param['uid'] = $uid; return; } } } } } Session.php 0000604 00000062050 15247172772 0006715 0 ustar 00 <?php /** * @copyright Copyright (c) 2017, Sandro Lutz <sandro.lutz@temparus.ch> * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Sandro Lutz <sandro.lutz@temparus.ch> * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Bernhard Posselt <dev@bernhard-posselt.com> * @author Christoph Wurst <christoph@owncloud.com> * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Petry <pvince81@owncloud.com> * @author Felix Rupp <kontakt@felixrupp.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\User; use OC; use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\PasswordLoginForbiddenException; use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IToken; use OC\Hooks\Emitter; use OC\Hooks\PublicEmitter; use OC_User; use OC_Util; use OCA\DAV\Connector\Sabre\Auth; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Files\NotPermittedException; use OCP\IConfig; use OCP\IRequest; use OCP\ISession; use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; use OCP\Lockdown\ILockdownManager; use OCP\Security\ISecureRandom; use OCP\Session\Exceptions\SessionNotAvailableException; use OCP\Util; use Symfony\Component\EventDispatcher\GenericEvent; /** * 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, string $password) * - preRememberedLogin(string $uid) * - postRememberedLogin(\OC\User\User $user) * - logout() * - postLogout() * * @package OC\User */ class Session implements IUserSession, Emitter { /** @var IUserManager|PublicEmitter $manager */ private $manager; /** @var ISession $session */ private $session; /** @var ITimeFactory */ private $timeFactory; /** @var IProvider */ private $tokenProvider; /** @var IConfig */ private $config; /** @var User $activeUser */ protected $activeUser; /** @var ISecureRandom */ private $random; /** @var ILockdownManager */ private $lockdownManager; /** * @param IUserManager $manager * @param ISession $session * @param ITimeFactory $timeFactory * @param IProvider $tokenProvider * @param IConfig $config * @param ISecureRandom $random * @param ILockdownManager $lockdownManager */ public function __construct(IUserManager $manager, ISession $session, ITimeFactory $timeFactory, $tokenProvider, IConfig $config, ISecureRandom $random, ILockdownManager $lockdownManager ) { $this->manager = $manager; $this->session = $session; $this->timeFactory = $timeFactory; $this->tokenProvider = $tokenProvider; $this->config = $config; $this->random = $random; $this->lockdownManager = $lockdownManager; } /** * @param IProvider $provider */ public function setTokenProvider(IProvider $provider) { $this->tokenProvider = $provider; } /** * @param string $scope * @param string $method * @param callable $callback */ public function listen($scope, $method, callable $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, callable $callback = null) { $this->manager->removeListener($scope, $method, $callback); } /** * get the manager object * * @return Manager|PublicEmitter */ public function getManager() { return $this->manager; } /** * get the session object * * @return ISession */ public function getSession() { return $this->session; } /** * set the session object * * @param ISession $session */ public function setSession(ISession $session) { if ($this->session instanceof ISession) { $this->session->close(); } $this->session = $session; $this->activeUser = null; } /** * set the currently active user * * @param IUser|null $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 IUser|null Current user, otherwise null */ public function getUser() { // FIXME: This is a quick'n dirty work-around for the incognito mode as // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155 if (OC_User::isIncognitoMode()) { return null; } if (is_null($this->activeUser)) { $uid = $this->session->get('user_id'); if (is_null($uid)) { return null; } $this->activeUser = $this->manager->get($uid); if (is_null($this->activeUser)) { return null; } $this->validateSession(); } return $this->activeUser; } /** * Validate whether the current session is valid * * - For token-authenticated clients, the token validity is checked * - For browsers, the session token validity is checked */ protected function validateSession() { $token = null; $appPassword = $this->session->get('app_password'); if (is_null($appPassword)) { try { $token = $this->session->getId(); } catch (SessionNotAvailableException $ex) { return; } } else { $token = $appPassword; } if (!$this->validateToken($token)) { // Session was invalidated $this->logout(); } } /** * Checks whether the user is logged in * * @return bool if logged in */ public function isLoggedIn() { $user = $this->getUser(); if (is_null($user)) { return false; } return $user->isEnabled(); } /** * set the login name * * @param string|null $loginName for the logged in user */ public function setLoginName($loginName) { if (is_null($loginName)) { $this->session->remove('loginname'); } else { $this->session->set('loginname', $loginName); } } /** * get the login name of the current user * * @return string */ public function getLoginName() { if ($this->activeUser) { return $this->session->get('loginname'); } else { $uid = $this->session->get('user_id'); if ($uid) { $this->activeUser = $this->manager->get($uid); return $this->session->get('loginname'); } else { return null; } } } /** * set the token id * * @param int|null $token that was used to log in */ protected function setToken($token) { if ($token === null) { $this->session->remove('token-id'); } else { $this->session->set('token-id', $token); } } /** * try to log in with the provided credentials * * @param string $uid * @param string $password * @return boolean|null * @throws LoginException */ public function login($uid, $password) { $this->session->regenerateId(); if ($this->validateToken($password, $uid)) { return $this->loginWithToken($password); } return $this->loginWithPassword($uid, $password); } /** * @param IUser $user * @param array $loginDetails * @param bool $regenerateSessionId * @return true returns true if login successful or an exception otherwise * @throws LoginException */ public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) { if (!$user->isEnabled()) { // disabled users can not log in // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory $message = \OC::$server->getL10N('lib')->t('User disabled'); throw new LoginException($message); } if($regenerateSessionId) { $this->session->regenerateId(); } $this->setUser($user); $this->setLoginName($loginDetails['loginName']); if(isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken) { $this->setToken($loginDetails['token']->getId()); $this->lockdownManager->setToken($loginDetails['token']); $firstTimeLogin = false; } else { $this->setToken(null); $firstTimeLogin = $user->updateLastLoginTimestamp(); } $this->manager->emit('\OC\User', 'postLogin', [$user, $loginDetails['password']]); if($this->isLoggedIn()) { $this->prepareUserLogin($firstTimeLogin, $regenerateSessionId); return true; } else { $message = \OC::$server->getL10N('lib')->t('Login canceled by app'); throw new LoginException($message); } } /** * Tries to log in a client * * Checks token auth enforced * Checks 2FA enabled * * @param string $user * @param string $password * @param IRequest $request * @param OC\Security\Bruteforce\Throttler $throttler * @throws LoginException * @throws PasswordLoginForbiddenException * @return boolean */ public function logClientIn($user, $password, IRequest $request, OC\Security\Bruteforce\Throttler $throttler) { $currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login'); if ($this->manager instanceof PublicEmitter) { $this->manager->emit('\OC\User', 'preLogin', array($user, $password)); } $isTokenPassword = $this->isTokenPassword($password); if (!$isTokenPassword && $this->isTokenAuthEnforced()) { throw new PasswordLoginForbiddenException(); } if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) { throw new PasswordLoginForbiddenException(); } if (!$this->login($user, $password) ) { $users = $this->manager->getByEmail($user); if (count($users) === 1) { return $this->login($users[0]->getUID(), $password); } $throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]); if($currentDelay === 0) { $throttler->sleepDelay($request->getRemoteAddress(), 'login'); } return false; } if ($isTokenPassword) { $this->session->set('app_password', $password); } else if($this->supportsCookies($request)) { // Password login, but cookies supported -> create (browser) session token $this->createSessionToken($request, $this->getUser()->getUID(), $user, $password); } return true; } protected function supportsCookies(IRequest $request) { if (!is_null($request->getCookie('cookie_test'))) { return true; } setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600); return false; } private function isTokenAuthEnforced() { return $this->config->getSystemValue('token_auth_enforced', false); } protected function isTwoFactorEnforced($username) { Util::emitHook( '\OCA\Files_Sharing\API\Server2Server', 'preLoginNameUsedAsUserName', array('uid' => &$username) ); $user = $this->manager->get($username); if (is_null($user)) { $users = $this->manager->getByEmail($username); if (empty($users)) { return false; } if (count($users) !== 1) { return true; } $user = $users[0]; } // DI not possible due to cyclic dependencies :'-/ return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user); } /** * Check if the given 'password' is actually a device token * * @param string $password * @return boolean */ public function isTokenPassword($password) { try { $this->tokenProvider->getToken($password); return true; } catch (InvalidTokenException $ex) { return false; } } protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) { if ($refreshCsrfToken) { // TODO: mock/inject/use non-static // Refresh the token \OC::$server->getCsrfTokenManager()->refreshToken(); } //we need to pass the user name, which may differ from login name $user = $this->getUser()->getUID(); OC_Util::setupFS($user); if ($firstTimeLogin) { // TODO: lock necessary? //trigger creation of user home and /files folder $userFolder = \OC::$server->getUserFolder($user); try { // copy skeleton \OC_Util::copySkeleton($user, $userFolder); } catch (NotPermittedException $ex) { // read only uses } // trigger any other initialization \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser())); } } /** * Tries to login the user with HTTP Basic Authentication * * @todo do not allow basic auth if the user is 2FA enforced * @param IRequest $request * @param OC\Security\Bruteforce\Throttler $throttler * @return boolean if the login was successful */ public function tryBasicAuthLogin(IRequest $request, OC\Security\Bruteforce\Throttler $throttler) { if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) { try { if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) { /** * Add DAV authenticated. This should in an ideal world not be * necessary but the iOS App reads cookies from anywhere instead * only the DAV endpoint. * This makes sure that the cookies will be valid for the whole scope * @see https://github.com/owncloud/core/issues/22893 */ $this->session->set( Auth::DAV_AUTHENTICATED, $this->getUser()->getUID() ); // Set the last-password-confirm session to make the sudo mode work $this->session->set('last-password-confirm', $this->timeFactory->getTime()); return true; } } catch (PasswordLoginForbiddenException $ex) { // Nothing to do } } return false; } /** * Log an user in via login name and password * * @param string $uid * @param string $password * @return boolean * @throws LoginException if an app canceld the login process or the user is not enabled */ private function loginWithPassword($uid, $password) { $user = $this->manager->checkPassword($uid, $password); if ($user === false) { // Password check failed return false; } return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false); } /** * Log an user in with a given token (id) * * @param string $token * @return boolean * @throws LoginException if an app canceled the login process or the user is not enabled */ private function loginWithToken($token) { try { $dbToken = $this->tokenProvider->getToken($token); } catch (InvalidTokenException $ex) { return false; } $uid = $dbToken->getUID(); // When logging in with token, the password must be decrypted first before passing to login hook $password = ''; try { $password = $this->tokenProvider->getPassword($dbToken, $token); } catch (PasswordlessTokenException $ex) { // Ignore and use empty string instead } $this->manager->emit('\OC\User', 'preLogin', array($uid, $password)); $user = $this->manager->get($uid); if (is_null($user)) { // user does not exist return false; } return $this->completeLogin( $user, [ 'loginName' => $dbToken->getLoginName(), 'password' => $password, 'token' => $dbToken ], false); } /** * Create a new session token for the given user credentials * * @param IRequest $request * @param string $uid user UID * @param string $loginName login name * @param string $password * @param int $remember * @return boolean */ public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) { if (is_null($this->manager->get($uid))) { // User does not exist return false; } $name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser'; try { $sessionId = $this->session->getId(); $pwd = $this->getPassword($password); $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember); return true; } catch (SessionNotAvailableException $ex) { // This can happen with OCC, where a memory session is used // if a memory session is used, we shouldn't create a session token anyway return false; } } /** * Checks if the given password is a token. * If yes, the password is extracted from the token. * If no, the same password is returned. * * @param string $password either the login password or a device token * @return string|null the password or null if none was set in the token */ private function getPassword($password) { if (is_null($password)) { // This is surely no token ;-) return null; } try { $token = $this->tokenProvider->getToken($password); try { return $this->tokenProvider->getPassword($token, $password); } catch (PasswordlessTokenException $ex) { return null; } } catch (InvalidTokenException $ex) { return $password; } } /** * @param IToken $dbToken * @param string $token * @return boolean */ private function checkTokenCredentials(IToken $dbToken, $token) { // Check whether login credentials are still valid and the user was not disabled // This check is performed each 5 minutes $lastCheck = $dbToken->getLastCheck() ? : 0; $now = $this->timeFactory->getTime(); if ($lastCheck > ($now - 60 * 5)) { // Checked performed recently, nothing to do now return true; } try { $pwd = $this->tokenProvider->getPassword($dbToken, $token); } catch (InvalidTokenException $ex) { // An invalid token password was used -> log user out return false; } catch (PasswordlessTokenException $ex) { // Token has no password if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) { $this->tokenProvider->invalidateToken($token); return false; } $dbToken->setLastCheck($now); return true; } if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false || (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) { $this->tokenProvider->invalidateToken($token); // Password has changed or user was disabled -> log user out return false; } $dbToken->setLastCheck($now); return true; } /** * Check if the given token exists and performs password/user-enabled checks * * Invalidates the token if checks fail * * @param string $token * @param string $user login name * @return boolean */ private function validateToken($token, $user = null) { try { $dbToken = $this->tokenProvider->getToken($token); } catch (InvalidTokenException $ex) { return false; } // Check if login names match if (!is_null($user) && $dbToken->getLoginName() !== $user) { // TODO: this makes it imposssible to use different login names on browser and client // e.g. login by e-mail 'user@example.com' on browser for generating the token will not // allow to use the client token with the login name 'user'. return false; } if (!$this->checkTokenCredentials($dbToken, $token)) { return false; } $this->tokenProvider->updateTokenActivity($dbToken); return true; } /** * Tries to login the user with auth token header * * @param IRequest $request * @todo check remember me cookie * @return boolean */ public function tryTokenLogin(IRequest $request) { $authHeader = $request->getHeader('Authorization'); if (strpos($authHeader, 'Bearer ') === false) { // No auth header, let's try session id try { $token = $this->session->getId(); } catch (SessionNotAvailableException $ex) { return false; } } else { $token = substr($authHeader, 7); } if (!$this->loginWithToken($token)) { return false; } if(!$this->validateToken($token)) { return false; } return true; } /** * perform login using the magic cookie (remember login) * * @param string $uid the username * @param string $currentToken * @param string $oldSessionId * @return bool */ public function loginWithCookie($uid, $currentToken, $oldSessionId) { $this->session->regenerateId(); $this->manager->emit('\OC\User', 'preRememberedLogin', array($uid)); $user = $this->manager->get($uid); if (is_null($user)) { // user does not exist return false; } // get stored tokens $tokens = $this->config->getUserKeys($uid, 'login_token'); // test cookies token against stored tokens if (!in_array($currentToken, $tokens, true)) { return false; } // replace successfully used token with a new one $this->config->deleteUserValue($uid, 'login_token', $currentToken); $newToken = $this->random->generate(32); $this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime()); try { $sessionId = $this->session->getId(); $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId); } catch (SessionNotAvailableException $ex) { return false; } catch (InvalidTokenException $ex) { \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']); return false; } $this->setMagicInCookie($user->getUID(), $newToken); $token = $this->tokenProvider->getToken($sessionId); //login $this->setUser($user); $this->setLoginName($token->getLoginName()); $this->setToken($token->getId()); $this->lockdownManager->setToken($token); $user->updateLastLoginTimestamp(); $password = null; try { $password = $this->tokenProvider->getPassword($token, $sessionId); } catch (PasswordlessTokenException $ex) { // Ignore } $this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]); return true; } /** * @param IUser $user */ public function createRememberMeToken(IUser $user) { $token = $this->random->generate(32); $this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime()); $this->setMagicInCookie($user->getUID(), $token); } /** * logout the user from the session */ public function logout() { $this->manager->emit('\OC\User', 'logout'); $user = $this->getUser(); if (!is_null($user)) { try { $this->tokenProvider->invalidateToken($this->session->getId()); } catch (SessionNotAvailableException $ex) { } } $this->setUser(null); $this->setLoginName(null); $this->setToken(null); $this->unsetMagicInCookie(); $this->session->clear(); $this->manager->emit('\OC\User', 'postLogout'); } /** * Set cookie value to use in next page load * * @param string $username username to be set * @param string $token */ public function setMagicInCookie($username, $token) { $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https'; $webRoot = \OC::$WEBROOT; if ($webRoot === '') { $webRoot = '/'; } $expires = $this->timeFactory->getTime() + $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15); setcookie('nc_username', $username, $expires, $webRoot, '', $secureCookie, true); setcookie('nc_token', $token, $expires, $webRoot, '', $secureCookie, true); try { setcookie('nc_session_id', $this->session->getId(), $expires, $webRoot, '', $secureCookie, true); } catch (SessionNotAvailableException $ex) { // ignore } } /** * Remove cookie for "remember username" */ public function unsetMagicInCookie() { //TODO: DI for cookies and IRequest $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https'; unset($_COOKIE['nc_username']); //TODO: DI unset($_COOKIE['nc_token']); unset($_COOKIE['nc_session_id']); setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true); // old cookies might be stored under /webroot/ instead of /webroot // and Firefox doesn't like it! setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true); } /** * Update password of the browser session token if there is one * * @param string $password */ public function updateSessionTokenPassword($password) { try { $sessionId = $this->session->getId(); $token = $this->tokenProvider->getToken($sessionId); $this->tokenProvider->setPassword($token, $sessionId, $password); } catch (SessionNotAvailableException $ex) { // Nothing to do } catch (InvalidTokenException $ex) { // Nothing to do } } } NoUserException.php 0000604 00000001466 15247172772 0010370 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Jörn Friedrich Dreyer <jfd@butonic.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\User; class NoUserException extends \Exception {} LoginException.php 0000604 00000001536 15247172772 0010223 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\User; class LoginException extends \Exception { } Backend.php 0000604 00000007767 15247172772 0006637 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Roeland Jago Douma <roeland@famdouma.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\User; use \OCP\UserInterface; /** * Abstract base class for user management. Provides methods for querying backend * capabilities. */ abstract class Backend implements UserInterface { /** * error code for functions not provided by the user backend */ const NOT_IMPLEMENTED = -501; /** * actions that user backends can define */ const CREATE_USER = 1; // 1 << 0 const SET_PASSWORD = 16; // 1 << 4 const CHECK_PASSWORD = 256; // 1 << 8 const GET_HOME = 4096; // 1 << 12 const GET_DISPLAYNAME = 65536; // 1 << 16 const SET_DISPLAYNAME = 1048576; // 1 << 20 const PROVIDE_AVATAR = 16777216; // 1 << 24 const COUNT_USERS = 268435456; // 1 << 28 protected $possibleActions = array( self::CREATE_USER => 'createUser', self::SET_PASSWORD => 'setPassword', self::CHECK_PASSWORD => 'checkPassword', self::GET_HOME => 'getHome', self::GET_DISPLAYNAME => 'getDisplayName', self::SET_DISPLAYNAME => 'setDisplayName', self::PROVIDE_AVATAR => 'canChangeAvatar', self::COUNT_USERS => 'countUsers', ); /** * Get all supported actions * @return int bitwise-or'ed actions * * Returns the supported actions as int to be * compared with self::CREATE_USER etc. */ public function getSupportedActions() { $actions = 0; foreach($this->possibleActions AS $action => $methodName) { if(method_exists($this, $methodName)) { $actions |= $action; } } return $actions; } /** * Check if backend implements actions * @param int $actions bitwise-or'ed actions * @return boolean * * Returns the supported actions as int to be * compared with self::CREATE_USER etc. */ public function implementsActions($actions) { return (bool)($this->getSupportedActions() & $actions); } /** * delete a user * @param string $uid The username of the user to delete * @return bool * * Deletes a user */ public function deleteUser( $uid ) { return false; } /** * Get a list of all users * * @param string $search * @param null|int $limit * @param null|int $offset * @return string[] an array of all uids */ public function getUsers($search = '', $limit = null, $offset = null) { return array(); } /** * check if a user exists * @param string $uid the username * @return boolean */ public function userExists($uid) { return false; } /** * get the user's home directory * @param string $uid the username * @return boolean */ public function getHome($uid) { return false; } /** * get display name of the user * @param string $uid user ID of the user * @return string display name */ public function getDisplayName($uid) { return $uid; } /** * Get a list of all display names and user ids. * * @param string $search * @param string|null $limit * @param string|null $offset * @return array an array of all displayNames (value) and the corresponding uids (key) */ public function getDisplayNames($search = '', $limit = null, $offset = null) { $displayNames = array(); $users = $this->getUsers($search, $limit, $offset); foreach ( $users as $user) { $displayNames[$user] = $user; } return $displayNames; } /** * Check if a user list is available or not * @return boolean if users can be listed or not */ public function hasUserListings() { return false; } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings