session; } /** * Return the current logged in user, or null if no user is logged in. * * @return \ElggUser */ function elgg_get_logged_in_user_entity() { return _elgg_services()->session->getLoggedInUser(); } /** * Return the current logged in user by guid. * * @see elgg_get_logged_in_user_entity() * @return int */ function elgg_get_logged_in_user_guid() { return _elgg_services()->session->getLoggedInUserGuid(); } /** * Returns whether or not the user is currently logged in * * @return bool */ function elgg_is_logged_in() { return _elgg_services()->session->isLoggedIn(); } /** * Returns whether or not the viewer is currently logged in and an admin user. * * @return bool */ function elgg_is_admin_logged_in() { return _elgg_services()->session->isAdminLoggedIn(); } /** * Check if the given user has full access. * * @todo: Will always return full access if the user is an admin. * * @param int $user_guid The user to check * * @return bool * @since 1.7.1 */ function elgg_is_admin_user($user_guid) { global $CONFIG; $user_guid = (int)$user_guid; $current_user = elgg_get_logged_in_user_entity(); if ($current_user && $current_user->guid == $user_guid) { return $current_user->isAdmin(); } // cannot use magic metadata here because of recursion // must support the old way of getting admin from metadata // in order to run the upgrade to move it into the users table. $version = (int) datalist_get('version'); if ($version < 2010040201) { $admin = elgg_get_metastring_id('admin'); $yes = elgg_get_metastring_id('yes'); $one = elgg_get_metastring_id('1'); $query = "SELECT 1 FROM {$CONFIG->dbprefix}users_entity as e, {$CONFIG->dbprefix}metadata as md WHERE ( md.name_id = '$admin' AND md.value_id IN ('$yes', '$one') AND e.guid = md.entity_guid AND e.guid = {$user_guid} AND e.banned = 'no' )"; } else { $query = "SELECT 1 FROM {$CONFIG->dbprefix}users_entity as e WHERE ( e.guid = {$user_guid} AND e.admin = 'yes' )"; } // normalizing the results from get_data() // See #1242 $info = get_data($query); if (!((is_array($info) && count($info) < 1) || $info === false)) { return true; } return false; } /** * Perform user authentication with a given username and password. * * @warning This returns an error message on failure. Use the identical operator to check * for access: if (true === elgg_authenticate()) { ... }. * * * @see login * * @param string $username The username * @param string $password The password * * @return true|string True or an error message on failure * @access private */ function elgg_authenticate($username, $password) { $pam = new \ElggPAM('user'); $credentials = array('username' => $username, 'password' => $password); $result = $pam->authenticate($credentials); if (!$result) { return $pam->getFailureMessage(); } return true; } /** * Hook into the PAM system which accepts a username and password and attempts to authenticate * it against a known user. * * @param array $credentials Associated array of credentials passed to * Elgg's PAM system. This function expects * 'username' and 'password' (cleartext). * * @return bool * @throws LoginException * @access private */ function pam_auth_userpass(array $credentials = array()) { if (!isset($credentials['username']) || !isset($credentials['password'])) { return false; } $user = get_user_by_username($credentials['username']); if (!$user) { throw new \LoginException(_elgg_services()->translator->translate('LoginException:UsernameFailure')); } if (check_rate_limit_exceeded($user->guid)) { throw new \LoginException(_elgg_services()->translator->translate('LoginException:AccountLocked')); } $password_svc = _elgg_services()->passwords; $password = $credentials['password']; $hash = $user->password_hash; if (!$hash) { // try legacy hash $legacy_hash = $password_svc->generateLegacyHash($user, $password); if ($user->password !== $legacy_hash) { log_login_failure($user->guid); throw new \LoginException(_elgg_services()->translator->translate('LoginException:PasswordFailure')); } // migrate password $password_svc->forcePasswordReset($user, $password); return true; } if (!$password_svc->verify($password, $hash)) { log_login_failure($user->guid); throw new \LoginException(_elgg_services()->translator->translate('LoginException:PasswordFailure')); } if ($password_svc->needsRehash($hash)) { $password_svc->forcePasswordReset($user, $password); } return true; } /** * Log a failed login for $user_guid * * @param int $user_guid User GUID * * @return bool */ function log_login_failure($user_guid) { $user_guid = (int)$user_guid; $user = get_entity($user_guid); if (($user_guid) && ($user) && ($user instanceof \ElggUser)) { $fails = (int)$user->getPrivateSetting("login_failures"); $fails++; $user->setPrivateSetting("login_failures", $fails); $user->setPrivateSetting("login_failure_$fails", time()); return true; } return false; } /** * Resets the fail login count for $user_guid * * @param int $user_guid User GUID * * @return bool true on success (success = user has no logged failed attempts) */ function reset_login_failure_count($user_guid) { $user_guid = (int)$user_guid; $user = get_entity($user_guid); if (($user_guid) && ($user) && ($user instanceof \ElggUser)) { $fails = (int)$user->getPrivateSetting("login_failures"); if ($fails) { for ($n = 1; $n <= $fails; $n++) { $user->removePrivateSetting("login_failure_$n"); } $user->removePrivateSetting("login_failures"); return true; } // nothing to reset return true; } return false; } /** * Checks if the rate limit of failed logins has been exceeded for $user_guid. * * @param int $user_guid User GUID * * @return bool on exceeded limit. */ function check_rate_limit_exceeded($user_guid) { // 5 failures in 5 minutes causes temporary block on logins $limit = 5; $user_guid = (int)$user_guid; $user = get_entity($user_guid); if (($user_guid) && ($user) && ($user instanceof \ElggUser)) { $fails = (int)$user->getPrivateSetting("login_failures"); if ($fails >= $limit) { $cnt = 0; $time = time(); for ($n = $fails; $n > 0; $n--) { $f = $user->getPrivateSetting("login_failure_$n"); if ($f > $time - (60 * 5)) { $cnt++; } if ($cnt == $limit) { // Limit reached return true; } } } } return false; } /** * Set a cookie, but allow plugins to customize it first. * * To customize all cookies, register for the 'init:cookie', 'all' event. * * @param \ElggCookie $cookie The cookie that is being set * @return bool * @since 1.9 */ function elgg_set_cookie(\ElggCookie $cookie) { if (elgg_trigger_event('init:cookie', $cookie->name, $cookie)) { return setcookie($cookie->name, $cookie->value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly); } return false; } /** * Logs in a specified \ElggUser. For standard registration, use in conjunction * with elgg_authenticate. * * @see elgg_authenticate * * @param \ElggUser $user A valid Elgg user object * @param boolean $persistent Should this be a persistent login? * * @return true or throws exception * @throws LoginException */ function login(\ElggUser $user, $persistent = false) { if ($user->isBanned()) { throw new \LoginException(elgg_echo('LoginException:BannedUser')); } $session = _elgg_services()->session; // give plugins a chance to reject the login of this user (no user in session!) if (!elgg_trigger_before_event('login', 'user', $user)) { throw new \LoginException(elgg_echo('LoginException:Unknown')); } // #5933: set logged in user early so code in login event will be able to // use elgg_get_logged_in_user_entity(). $session->setLoggedInUser($user); // deprecate event $message = "The 'login' event was deprecated. Register for 'login:before' or 'login:after'"; $version = "1.9"; if (!elgg_trigger_deprecated_event('login', 'user', $user, $message, $version)) { $session->removeLoggedInUser(); throw new \LoginException(elgg_echo('LoginException:Unknown')); } // if remember me checked, set cookie with token and store hash(token) for user if ($persistent) { _elgg_services()->persistentLogin->makeLoginPersistent($user); } // User's privilege has been elevated, so change the session id (prevents session fixation) $session->migrate(); set_last_login($user->guid); reset_login_failure_count($user->guid); elgg_trigger_after_event('login', 'user', $user); // if memcache is enabled, invalidate the user in memcache @see https://github.com/Elgg/Elgg/issues/3143 if (is_memcache_available()) { $guid = $user->getGUID(); // this needs to happen with a shutdown function because of the timing with set_last_login() register_shutdown_function("_elgg_invalidate_memcache_for_entity", $guid); } return true; } /** * Log the current user out * * @return bool */ function logout() { $session = _elgg_services()->session; $user = $session->getLoggedInUser(); if (!$user) { return false; } if (!elgg_trigger_before_event('logout', 'user', $user)) { return false; } // deprecate event $message = "The 'logout' event was deprecated. Register for 'logout:before' or 'logout:after'"; $version = "1.9"; if (!elgg_trigger_deprecated_event('logout', 'user', $user, $message, $version)) { return false; } _elgg_services()->persistentLogin->removePersistentLogin(); // pass along any messages into new session $old_msg = $session->get('msg'); $session->invalidate(); $session->set('msg', $old_msg); elgg_trigger_after_event('logout', 'user', $user); return true; } /** * Initializes the session and checks for the remember me cookie * * @return bool * @access private */ function _elgg_session_boot() { elgg_register_action('login', '', 'public'); elgg_register_action('logout'); register_pam_handler('pam_auth_userpass'); $session = _elgg_services()->session; $session->start(); // test whether we have a user session if ($session->has('guid')) { $user = _elgg_services()->entityTable->get($session->get('guid'), 'user'); if (!$user) { // OMG user has been deleted. $session->invalidate(); forward(''); } $session->setLoggedInUser($user); _elgg_services()->persistentLogin->replaceLegacyToken($user); } else { $user = _elgg_services()->persistentLogin->bootSession(); if ($user) { $session->setLoggedInUser($user); } } if ($session->has('guid')) { set_last_action($session->get('guid')); } // initialize the deprecated global session wrapper global $SESSION; $SESSION = new \Elgg\DeprecationWrapper($session, "\$SESSION is deprecated", 1.9); // logout a user with open session who has been banned $user = $session->getLoggedInUser(); if ($user && $user->isBanned()) { logout(); return false; } return true; }