/** * @covers RequestContext::importScopedSession */ public function testImportScopedSession() { // Make sure session handling is started if (!MediaWiki\Session\PHPSessionHandler::isInstalled()) { MediaWiki\Session\PHPSessionHandler::install(MediaWiki\Session\SessionManager::singleton()); } $oldSessionId = session_id(); $context = RequestContext::getMain(); $oInfo = $context->exportSession(); $this->assertEquals('127.0.0.1', $oInfo['ip'], "Correct initial IP address."); $this->assertEquals(0, $oInfo['userId'], "Correct initial user ID."); $this->assertFalse(MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent(), 'Global session isn\'t persistent to start'); $user = User::newFromName('UnitTestContextUser'); $user->addToDatabase(); $sinfo = array('sessionId' => 'd612ee607c87e749ef14da4983a702cd', 'userId' => $user->getId(), 'ip' => '192.0.2.0', 'headers' => array('USER-AGENT' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.0')); // importScopedSession() sets these variables $this->setMwGlobals(array('wgUser' => new User(), 'wgRequest' => new FauxRequest())); $sc = RequestContext::importScopedSession($sinfo); // load new context $info = $context->exportSession(); $this->assertEquals($sinfo['ip'], $info['ip'], "Correct IP address."); $this->assertEquals($sinfo['headers'], $info['headers'], "Correct headers."); $this->assertEquals($sinfo['sessionId'], $info['sessionId'], "Correct session ID."); $this->assertEquals($sinfo['userId'], $info['userId'], "Correct user ID."); $this->assertEquals($sinfo['ip'], $context->getRequest()->getIP(), "Correct context IP address."); $this->assertEquals($sinfo['headers'], $context->getRequest()->getAllHeaders(), "Correct context headers."); $this->assertEquals($sinfo['sessionId'], MediaWiki\Session\SessionManager::getGlobalSession()->getId(), "Correct context session ID."); if (\MediaWiki\Session\PhpSessionHandler::isEnabled()) { $this->assertEquals($sinfo['sessionId'], session_id(), "Correct context session ID."); } else { $this->assertEquals($oldSessionId, session_id(), "Unchanged PHP session ID."); } $this->assertEquals(true, $context->getUser()->isLoggedIn(), "Correct context user."); $this->assertEquals($sinfo['userId'], $context->getUser()->getId(), "Correct context user ID."); $this->assertEquals('UnitTestContextUser', $context->getUser()->getName(), "Correct context user name."); unset($sc); // restore previous context $info = $context->exportSession(); $this->assertEquals($oInfo['ip'], $info['ip'], "Correct restored IP address."); $this->assertEquals($oInfo['headers'], $info['headers'], "Correct restored headers."); $this->assertEquals($oInfo['sessionId'], $info['sessionId'], "Correct restored session ID."); $this->assertEquals($oInfo['userId'], $info['userId'], "Correct restored user ID."); $this->assertFalse(MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent(), 'Global session isn\'t persistent after restoring the context'); }
} if ($session->isPersistent()) { $wgInitialSessionId = $session->getSessionId(); } $session->renew(); if (MediaWiki\Session\PHPSessionHandler::isEnabled() && ($session->isPersistent() || $session->shouldRememberUser())) { // Start the PHP-session for backwards compatibility session_id($session->getId()); MediaWiki\quietCall('session_start'); } unset($session); } else { // Even if we didn't set up a global Session, still install our session // handler unless specifically requested not to. if (!defined('MW_NO_SESSION_HANDLER')) { MediaWiki\Session\PHPSessionHandler::install(MediaWiki\Session\SessionManager::singleton()); } } Profiler::instance()->scopedProfileOut($ps_session); /** * @var User $wgUser */ $wgUser = RequestContext::getMain()->getUser(); // BackCompat /** * @var Language $wgLang */ $wgLang = new StubUserLang(); /** * @var OutputPage $wgOut */
/** * Import an client IP address, HTTP headers, user ID, and session ID * * This sets the current session, $wgUser, and $wgRequest from $params. * Once the return value falls out of scope, the old context is restored. * This method should only be called in contexts where there is no session * ID or end user receiving the response (CLI or HTTP job runners). This * is partly enforced, and is done so to avoid leaking cookies if certain * error conditions arise. * * This is useful when background scripts inherit context when acting on * behalf of a user. In general the 'sessionId' parameter should be set * to an empty string unless session importing is *truly* needed. This * feature is somewhat deprecated. * * @note suhosin.session.encrypt may interfere with this method. * * @param array $params Result of RequestContext::exportSession() * @return ScopedCallback * @throws MWException * @since 1.21 */ public static function importScopedSession(array $params) { if (strlen($params['sessionId']) && MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent()) { // Sanity check to avoid sending random cookies for the wrong users. // This method should only called by CLI scripts or by HTTP job runners. throw new MWException("Sessions can only be imported when none is active."); } elseif (!IP::isValid($params['ip'])) { throw new MWException("Invalid client IP address '{$params['ip']}'."); } if ($params['userId']) { // logged-in user $user = User::newFromId($params['userId']); $user->load(); if (!$user->getId()) { throw new MWException("No user with ID '{$params['userId']}'."); } } else { // anon user $user = User::newFromName($params['ip'], false); } $importSessionFunc = function (User $user, array $params) { global $wgRequest, $wgUser; $context = RequestContext::getMain(); // Commit and close any current session if (MediaWiki\Session\PHPSessionHandler::isEnabled()) { session_write_close(); // persist session_id(''); // detach $_SESSION = []; // clear in-memory array } // Get new session, if applicable $session = null; if (strlen($params['sessionId'])) { // don't make a new random ID $manager = MediaWiki\Session\SessionManager::singleton(); $session = $manager->getSessionById($params['sessionId'], true) ?: $manager->getEmptySession(); } // Remove any user IP or agent information, and attach the request // with the new session. $context->setRequest(new FauxRequest([], false, $session)); $wgRequest = $context->getRequest(); // b/c // Now that all private information is detached from the user, it should // be safe to load the new user. If errors occur or an exception is thrown // and caught (leaving the main context in a mixed state), there is no risk // of the User object being attached to the wrong IP, headers, or session. $context->setUser($user); $wgUser = $context->getUser(); // b/c if ($session && MediaWiki\Session\PHPSessionHandler::isEnabled()) { session_id($session->getId()); MediaWiki\quietCall('session_start'); } $request = new FauxRequest([], false, $session); $request->setIP($params['ip']); foreach ($params['headers'] as $name => $value) { $request->setHeader($name, $value); } // Set the current context to use the new WebRequest $context->setRequest($request); $wgRequest = $context->getRequest(); // b/c }; // Stash the old session and load in the new one $oUser = self::getMain()->getUser(); $oParams = self::getMain()->exportSession(); $oRequest = self::getMain()->getRequest(); $importSessionFunc($user, $params); // Set callback to save and close the new session and reload the old one return new ScopedCallback(function () use($importSessionFunc, $oUser, $oParams, $oRequest) { global $wgRequest; $importSessionFunc($oUser, $oParams); // Restore the exact previous Request object (instead of leaving FauxRequest) RequestContext::getMain()->setRequest($oRequest); $wgRequest = RequestContext::getMain()->getRequest(); // b/c }); }
} catch (OverflowException $ex) { if (isset($ex->sessionInfos) && count($ex->sessionInfos) >= 2) { // The exception is because the request had multiple possible // sessions tied for top priority. Report this to the user. $list = array(); foreach ($ex->sessionInfos as $info) { $list[] = $info->getProvider()->describe($wgContLang); } $list = $wgContLang->listToText($list); throw new HttpError(400, Message::newFromKey('sessionmanager-tie', $list)->inLanguage($wgContLang)->plain()); } // Not the one we want, rethrow throw $ex; } $session->renew(); if (MediaWiki\Session\PHPSessionHandler::isEnabled() && ($session->isPersistent() || $session->shouldRememberUser())) { // Start the PHP-session for backwards compatibility session_id($session->getId()); MediaWiki\quietCall('session_start'); } } Profiler::instance()->scopedProfileOut($ps_session); /** * @var User $wgUser */ $wgUser = RequestContext::getMain()->getUser(); // BackCompat /** * @var Language $wgLang */ $wgLang = new StubUserLang();
/** * 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'); }