public function execute($subPage) { $this->setHeaders(); $this->loadAuth($subPage); $this->outputHeader(); $status = $this->trySubmit(); if ($status === false || !$status->isOK()) { $this->displayForm($status); return; } /** @var AuthenticationResponse $response */ $response = $status->getValue(); if ($response->status === AuthenticationResponse::FAIL) { $this->displayForm(StatusValue::newFatal($response->message)); return; } $status = StatusValue::newGood(); $status->warning(wfMessage('unlinkaccounts-success')); $this->loadAuth($subPage, null, true); // update requests so the unlinked one doesn't show up // Reset sessions - if the user unlinked an account because it was compromised, // log attackers out from sessions obtained via that account. $session = $this->getRequest()->getSession(); $user = $this->getUser(); SessionManager::singleton()->invalidateSessionsForUser($user); $session->setUser($user); $session->resetId(); $this->displayForm($status); }
public function testGetGlobalSession() { $context = \RequestContext::getMain(); if (!PHPSessionHandler::isInstalled()) { PHPSessionHandler::install(SessionManager::singleton()); } $rProp = new \ReflectionProperty('MediaWiki\\Session\\PHPSessionHandler', 'instance'); $rProp->setAccessible(true); $handler = \TestingAccessWrapper::newFromObject($rProp->getValue()); $oldEnable = $handler->enable; $reset[] = new \ScopedCallback(function () use($handler, $oldEnable) { if ($handler->enable) { session_write_close(); } $handler->enable = $oldEnable; }); $reset[] = TestUtils::setSessionManagerSingleton($this->getManager()); $handler->enable = true; $request = new \FauxRequest(); $context->setRequest($request); $id = $request->getSession()->getId(); session_id(''); $session = SessionManager::getGlobalSession(); $this->assertSame($id, $session->getId()); session_id('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); $session = SessionManager::getGlobalSession(); $this->assertSame('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', $session->getId()); $this->assertSame('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', $request->getSession()->getId()); session_write_close(); $handler->enable = false; $request = new \FauxRequest(); $context->setRequest($request); $id = $request->getSession()->getId(); session_id(''); $session = SessionManager::getGlobalSession(); $this->assertSame($id, $session->getId()); session_id('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'); $session = SessionManager::getGlobalSession(); $this->assertSame($id, $session->getId()); $this->assertSame($id, $request->getSession()->getId()); }
/** * @param array $data Array of *non*-urlencoded key => value pairs, the * fake GET/POST values * @param bool $wasPosted Whether to treat the data as POST * @param MediaWiki\\Session\\Session|array|null $session Session, session * data array, or null * @param string $protocol 'http' or 'https' * @throws MWException */ public function __construct($data = array(), $wasPosted = false, $session = null, $protocol = 'http') { $this->requestTime = microtime(true); if (is_array($data)) { $this->data = $data; } else { throw new MWException("FauxRequest() got bogus data"); } $this->wasPosted = $wasPosted; if ($session instanceof MediaWiki\Session\Session) { $this->sessionId = $session->getSessionId(); } elseif (is_array($session)) { $mwsession = SessionManager::singleton()->getEmptySession($this); $this->sessionId = $mwsession->getSessionId(); foreach ($session as $key => $value) { $mwsession->set($key, $value); } } elseif ($session !== null) { throw new MWException("FauxRequest() got bogus session"); } $this->protocol = $protocol; }
public function execute() { $username = $this->getOption('user'); $file = $this->getOption('file'); if ($username === null && $file === null) { $this->error('Either --user or --file is required', 1); } elseif ($username !== null && $file !== null) { $this->error('Cannot use both --user and --file', 1); } if ($username !== null) { $usernames = [$username]; } else { $usernames = is_readable($file) ? file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : false; if ($usernames === false) { $this->error("Could not open {$file}", 2); } } $i = 0; $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); $sessionManager = SessionManager::singleton(); foreach ($usernames as $username) { $i++; $user = User::newFromName($username); try { $sessionManager->invalidateSessionsForUser($user); if ($user->getId()) { $this->output("Invalidated sessions for user {$username}\n"); } else { # session invalidation might still work if there is a central identity provider $this->output("Could not find user {$username}, tried to invalidate anyway\n"); } } catch (Exception $e) { $this->output("Failed to invalidate sessions for user {$username} | " . str_replace(["\r", "\n"], ' ', $e->getMessage()) . "\n"); } if ($i % $this->mBatchSize) { $lbFactory->waitForReplication(); } } }
public function testGetLoginCookieExpiration() { $config = $this->getConfig(); $provider = \TestingAccessWrapper::newFromObject(new CookieSessionProvider(['priority' => 10])); $provider->setLogger(new \Psr\Log\NullLogger()); $provider->setConfig($config); $provider->setManager(SessionManager::singleton()); $this->assertSame(200, $provider->getLoginCookieExpiration('Token')); $this->assertSame(100, $provider->getLoginCookieExpiration('User')); $config->set('ExtendedLoginCookieExpiration', null); $this->assertSame(100, $provider->getLoginCookieExpiration('Token')); $this->assertSame(100, $provider->getLoginCookieExpiration('User')); }
/** * Returns true if the request has a persistent session. * This does not necessarily mean that the user is logged in! * * @deprecated since 1.27, use * \\MediaWiki\\Session\\SessionManager::singleton()->getPersistedSessionId() * instead. * @return bool */ public function checkSessionCookie() { wfDeprecated(__METHOD__, '1.27'); return SessionManager::singleton()->getPersistedSessionId($this) !== null; }
/** * Initialise php session * * @deprecated since 1.27, use MediaWiki\\Session\\SessionManager instead. * Generally, "using" SessionManager will be calling ->getSessionById() or * ::getGlobalSession() (depending on whether you were passing $sessionId * here), then calling $session->persist(). * @param bool|string $sessionId */ function wfSetupSession($sessionId = false) { wfDeprecated(__FUNCTION__, '1.27'); // If they're calling this, they probably want our session management even // if NO_SESSION was set for Setup.php. if (!MediaWiki\Session\PHPSessionHandler::isInstalled()) { MediaWiki\Session\PHPSessionHandler::install(SessionManager::singleton()); } if ($sessionId) { session_id($sessionId); } $session = SessionManager::getGlobalSession(); $session->persist(); if (session_id() !== $session->getId()) { session_id($session->getId()); } MediaWiki\quietCall('session_cache_limiter', 'private, must-revalidate'); MediaWiki\quietCall('session_start'); }
public function testResetIdOfGlobalSession() { if (!PHPSessionHandler::isInstalled()) { PHPSessionHandler::install(SessionManager::singleton()); } if (!PHPSessionHandler::isEnabled()) { $rProp = new \ReflectionProperty('MediaWiki\\Session\\PHPSessionHandler', 'instance'); $rProp->setAccessible(true); $handler = \TestingAccessWrapper::newFromObject($rProp->getValue()); $resetHandler = new \ScopedCallback(function () use($handler) { session_write_close(); $handler->enable = false; }); $handler->enable = true; } $backend = $this->getBackend(User::newFromName('UTSysop')); \TestingAccessWrapper::newFromObject($backend)->usePhpSessionHandling = true; TestUtils::setSessionManagerSingleton($this->manager); $manager = \TestingAccessWrapper::newFromObject($this->manager); $request = \RequestContext::getMain()->getRequest(); $manager->globalSession = $backend->getSession($request); $manager->globalSessionRequest = $request; session_id(self::SESSIONID); \MediaWiki\quietCall('session_start'); $backend->resetId(); $this->assertNotEquals(self::SESSIONID, $backend->getId()); $this->assertSame($backend->getId(), session_id()); session_write_close(); session_id(''); $this->assertNotSame($backend->getId(), session_id(), 'sanity check'); $backend->persist(); $this->assertSame($backend->getId(), session_id()); session_write_close(); }
/** * Actually set the password and such * @since 1.27 cannot set a password for a user not in the database * @param string|null $str New password to set or null to set an invalid * password hash meaning that the user will not be able to log in * through the web interface. * @return bool Success */ private function setPasswordInternal($str) { global $wgDisableAuthManager; if ($wgDisableAuthManager) { $id = self::idFromName($this->getName(), self::READ_LATEST); if ($id == 0) { throw new LogicException('Cannot set a password for a user that is not in the database.'); } $passwordFactory = new PasswordFactory(); $passwordFactory->init(RequestContext::getMain()->getConfig()); $dbw = wfGetDB(DB_MASTER); $dbw->update('user', ['user_password' => $passwordFactory->newFromPlaintext($str)->toString(), 'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(), 'user_newpass_time' => $dbw->timestampOrNull(null)], ['user_id' => $id], __METHOD__); // When the main password is changed, invalidate all bot passwords too BotPassword::invalidateAllPasswordsForUser($this->getName()); } else { $manager = AuthManager::singleton(); // If the user doesn't exist yet, fail if (!$manager->userExists($this->getName())) { throw new LogicException('Cannot set a password for a user that is not in the database.'); } $data = ['username' => $this->getName(), 'password' => $str, 'retype' => $str]; $reqs = $manager->getAuthenticationRequests(AuthManager::ACTION_CHANGE, $this); $reqs = AuthenticationRequest::loadRequestsFromSubmission($reqs, $data); foreach ($reqs as $req) { $status = $manager->allowsAuthenticationDataChange($req); if (!$status->isOk()) { \MediaWiki\Logger\LoggerFactory::getInstance('authentication')->info(__METHOD__ . ': Password change rejected: ' . $status->getWikiText()); return false; } } foreach ($reqs as $req) { $manager->changeAuthenticationData($req); } $this->setOption('watchlisttoken', false); } SessionManager::singleton()->invalidateSessionsForUser($this); return true; }
/** * @param User $user * @param bool $useContextLang Use 'uselang' to set the user's language */ private function setDefaultUserOptions(User $user, $useContextLang) { global $wgContLang; \MediaWiki\Session\SessionManager::singleton()->invalidateSessionsForUser($user); $lang = $useContextLang ? \RequestContext::getMain()->getLanguage() : $wgContLang; $user->setOption('language', $lang->getPreferredVariant()); if ($wgContLang->hasVariants()) { $user->setOption('variant', $wgContLang->getPreferredVariant()); } }
/** * Static factory method for creation of a "system" user from username. * * A "system" user is an account that's used to attribute logged actions * taken by MediaWiki itself, as opposed to a bot or human user. Examples * might include the 'Maintenance script' or 'Conversion script' accounts * used by various scripts in the maintenance/ directory or accounts such * as 'MediaWiki message delivery' used by the MassMessage extension. * * This can optionally create the user if it doesn't exist, and "steal" the * account if it does exist. * * @param string $name Username * @param array $options Options are: * - validate: As for User::getCanonicalName(), default 'valid' * - create: Whether to create the user if it doesn't already exist, default true * - steal: Whether to reset the account's password and email if it * already exists, default false * @return User|null */ public static function newSystemUser($name, $options = array()) { $options += array('validate' => 'valid', 'create' => true, 'steal' => false); $name = self::getCanonicalName($name, $options['validate']); if ($name === false) { return null; } $dbw = wfGetDB(DB_MASTER); $row = $dbw->selectRow('user', array_merge(self::selectFields(), array('user_password', 'user_newpassword')), array('user_name' => $name), __METHOD__); if (!$row) { // No user. Create it? return $options['create'] ? self::createNew($name) : null; } $user = self::newFromRow($row); // A user is considered to exist as a non-system user if it has a // password set, or a temporary password set, or an email set. $passwordFactory = new PasswordFactory(); $passwordFactory->init(RequestContext::getMain()->getConfig()); try { $password = $passwordFactory->newFromCiphertext($row->user_password); } catch (PasswordError $e) { wfDebug('Invalid password hash found in database.'); $password = PasswordFactory::newInvalidPassword(); } try { $newpassword = $passwordFactory->newFromCiphertext($row->user_newpassword); } catch (PasswordError $e) { wfDebug('Invalid password hash found in database.'); $newpassword = PasswordFactory::newInvalidPassword(); } if (!$password instanceof InvalidPassword || !$newpassword instanceof InvalidPassword || $user->mEmail) { // User exists. Steal it? if (!$options['steal']) { return null; } $nopass = PasswordFactory::newInvalidPassword()->toString(); $dbw->update('user', array('user_password' => $nopass, 'user_newpassword' => $nopass, 'user_newpass_time' => null), array('user_id' => $user->getId()), __METHOD__); $user->invalidateEmail(); $user->saveSettings(); } SessionManager::singleton()->preventSessionsForUser($user->getName()); return $user; }
public function resetAuthToken() { \MediaWiki\Session\SessionManager::singleton()->invalidateSessionsForUser($this->user); return true; }
/** * Check if a session cookie is present. * * This will not pick up a cookie set during _this_ request, but is meant * to ensure that the client is returning the cookie which was set on a * previous pass through the system. * * @private * @return bool */ function hasSessionCookie() { global $wgDisableCookieCheck; return $wgDisableCookieCheck || SessionManager::singleton()->getPersistedSessionId($this->getRequest()) !== null; }
protected function success() { $session = $this->getRequest()->getSession(); $user = $this->getUser(); $out = $this->getOutput(); $returnUrl = $this->getReturnUrl(); // change user token and update the session SessionManager::singleton()->invalidateSessionsForUser($user); $session->setUser($user); $session->resetId(); if ($returnUrl) { $out->redirect($returnUrl); } else { // messages used: changecredentials-success removecredentials-success $out->wrapWikiMsg("<div class=\"successbox\">\n\$1\n</div>", static::$messagePrefix . '-success'); $out->returnToMain(); } }
/** * Actually add a user to the database. * Give it a User object that has been initialised with a name. * * @param User $u * @param bool $autocreate True if this is an autocreation via auth plugin * @return Status Status object, with the User object in the value member on success * @private */ function initUser($u, $autocreate) { global $wgAuth; $status = $u->addToDatabase(); if (!$status->isOK()) { return $status; } if ($wgAuth->allowPasswordChange()) { $u->setPassword($this->mPassword); } $u->setEmail($this->mEmail); $u->setRealName($this->mRealName); SessionManager::singleton()->invalidateSessionsForUser($u); Hooks::run('LocalUserCreated', [$u, $autocreate]); $oldUser = $u; $wgAuth->initUser($u, $autocreate); if ($oldUser !== $u) { wfWarn(get_class($wgAuth) . '::initUser() replaced the user object'); } $u->saveSettings(); // Update user count DeferredUpdates::addUpdate(new SiteStatsUpdate(0, 0, 0, 0, 1)); // Watch user's userpage and talk page $u->addWatch($u->getUserPage(), User::IGNORE_USER_RIGHTS); return Status::newGood($u); }
/** * Return the session for this request * @since 1.27 * @note For performance, keep the session locally if you will be making * much use of it instead of calling this method repeatedly. * @return Session */ public function getSession() { if ($this->sessionId !== null) { $session = SessionManager::singleton()->getSessionById((string) $this->sessionId, true, $this); if ($session) { return $session; } } $session = SessionManager::singleton()->getSessionForRequest($this); $this->sessionId = $session->getSessionId(); return $session; }
public function testSetLoggedOutCookie() { $provider = \TestingAccessWrapper::newFromObject(new CookieSessionProvider(array('priority' => 1, 'sessionName' => 'MySessionName', 'cookieOptions' => array('prefix' => 'x')))); $provider->setLogger(new \Psr\Log\NullLogger()); $provider->setConfig($this->getConfig()); $provider->setManager(SessionManager::singleton()); $t1 = time(); $t2 = time() - 86400 * 2; // Set it $request = new \FauxRequest(); $provider->setLoggedOutCookie($t1, $request); $this->assertSame((string) $t1, $request->response()->getCookie('xLoggedOut')); // Too old $request = new \FauxRequest(); $provider->setLoggedOutCookie($t2, $request); $this->assertSame(null, $request->response()->getCookie('xLoggedOut')); // Don't reset if it's already set $request = new \FauxRequest(); $request->setCookies(array('xLoggedOut' => $t1), ''); $provider->setLoggedOutCookie($t1, $request); $this->assertSame(null, $request->response()->getCookie('xLoggedOut')); }
/** * Get a complete Key header * * @return string */ public function getKeyHeader() { $cvCookies = $this->getCacheVaryCookies(); $cookiesOption = array(); foreach ($cvCookies as $cookieName) { $cookiesOption[] = 'param=' . $cookieName; } $this->addVaryHeader('Cookie', $cookiesOption); foreach (SessionManager::singleton()->getVaryHeaders() as $header => $options) { $this->addVaryHeader($header, $options); } $headers = array(); foreach ($this->mVaryHeader as $header => $option) { $newheader = $header; if (is_array($option) && count($option) > 0) { $newheader .= ';' . implode(';', $option); } $headers[] = $newheader; } $key = 'Key: ' . implode(',', $headers); return $key; }
/** * Actually set the password and such * @since 1.27 cannot set a password for a user not in the database * @param string|null $str New password to set or null to set an invalid * password hash meaning that the user will not be able to log in * through the web interface. * @return bool Success */ private function setPasswordInternal($str) { $manager = AuthManager::singleton(); // If the user doesn't exist yet, fail if (!$manager->userExists($this->getName())) { throw new LogicException('Cannot set a password for a user that is not in the database.'); } $status = $this->changeAuthenticationData(['username' => $this->getName(), 'password' => $str, 'retype' => $str]); if (!$status->isGood()) { \MediaWiki\Logger\LoggerFactory::getInstance('authentication')->info(__METHOD__ . ': Password change rejected: ' . $status->getWikiText(null, null, 'en')); return false; } $this->setOption('watchlisttoken', false); SessionManager::singleton()->invalidateSessionsForUser($this); return true; }