/**
  * @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');
 }
Example #2
0
    }
    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
 */
Example #3
0
 /**
  * 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
     });
 }
Example #4
0
 public function testBotPassword()
 {
     global $wgServer, $wgSessionProviders;
     if (!isset($wgServer)) {
         $this->markTestIncomplete('This test needs $wgServer to be set in LocalSettings.php');
     }
     $this->setMwGlobals(array('wgSessionProviders' => array_merge($wgSessionProviders, array(array('class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => array(array('priority' => 40))))), 'wgEnableBotPasswords' => true, 'wgBotPasswordsDatabase' => false, 'wgCentralIdLookupProvider' => 'local', 'wgGrantPermissions' => array('test' => array('read' => true))));
     // Make sure our session provider is present
     $manager = TestingAccessWrapper::newFromObject(MediaWiki\Session\SessionManager::singleton());
     if (!isset($manager->sessionProviders['MediaWiki\\Session\\BotPasswordSessionProvider'])) {
         $tmp = $manager->sessionProviders;
         $manager->sessionProviders = null;
         $manager->sessionProviders = $tmp + $manager->getProviders();
     }
     $this->assertNotNull(MediaWiki\Session\SessionManager::singleton()->getProvider('MediaWiki\\Session\\BotPasswordSessionProvider'), 'sanity check');
     $user = self::$users['sysop'];
     $centralId = CentralIdLookup::factory()->centralIdFromLocalUser($user->getUser());
     $this->assertNotEquals(0, $centralId, 'sanity check');
     $passwordFactory = new PasswordFactory();
     $passwordFactory->init(RequestContext::getMain()->getConfig());
     // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
     $passwordFactory->setDefaultType('A');
     $pwhash = $passwordFactory->newFromPlaintext('foobaz');
     $dbw = wfGetDB(DB_MASTER);
     $dbw->insert('bot_passwords', array('bp_user' => $centralId, 'bp_app_id' => 'foo', 'bp_password' => $pwhash->toString(), 'bp_token' => '', 'bp_restrictions' => MWRestrictions::newDefault()->toJson(), 'bp_grants' => '["test"]'), __METHOD__);
     $lgName = $user->username . BotPassword::getSeparator() . 'foo';
     $ret = $this->doApiRequest(array('action' => 'login', 'lgname' => $lgName, 'lgpassword' => 'foobaz'));
     $result = $ret[0];
     $this->assertNotInternalType('bool', $result);
     $this->assertNotInternalType('null', $result['login']);
     $a = $result['login']['result'];
     $this->assertEquals('NeedToken', $a);
     $token = $result['login']['token'];
     $ret = $this->doApiRequest(array('action' => 'login', 'lgtoken' => $token, 'lgname' => $lgName, 'lgpassword' => 'foobaz'), $ret[2]);
     $result = $ret[0];
     $this->assertNotInternalType('bool', $result);
     $a = $result['login']['result'];
     $this->assertEquals('Success', $a);
 }
Example #5
0
 /**
  * Try to log the user in
  * @param string $username Combined user name and app ID
  * @param string $password Supplied password
  * @param WebRequest $request
  * @return Status On success, the good status's value is the new Session object
  */
 public static function login($username, $password, WebRequest $request)
 {
     global $wgEnableBotPasswords;
     if (!$wgEnableBotPasswords) {
         return Status::newFatal('botpasswords-disabled');
     }
     $manager = MediaWiki\Session\SessionManager::singleton();
     $provider = $manager->getProvider('MediaWiki\\Session\\BotPasswordSessionProvider');
     if (!$provider) {
         return Status::newFatal('botpasswords-no-provider');
     }
     // Split name into name+appId
     $sep = self::getSeparator();
     if (strpos($username, $sep) === false) {
         return Status::newFatal('botpasswords-invalid-name', $sep);
     }
     list($name, $appId) = explode($sep, $username, 2);
     // Find the named user
     $user = User::newFromName($name);
     if (!$user || $user->isAnon()) {
         return Status::newFatal('nosuchuser', $name);
     }
     // Get the bot password
     $bp = self::newFromUser($user, $appId);
     if (!$bp) {
         return Status::newFatal('botpasswords-not-exist', $name, $appId);
     }
     // Check restrictions
     $status = $bp->getRestrictions()->check($request);
     if (!$status->isOk()) {
         return Status::newFatal('botpasswords-restriction-failed');
     }
     // Check the password
     if (!$bp->getPassword()->equals($password)) {
         return Status::newFatal('wrongpassword');
     }
     // Ok! Create the session.
     return Status::newGood($provider->newSessionForRequest($user, $bp, $request));
 }
Example #6
0
 /**
  * Leave a message on the user talk page or in the session according to
  * $params['leaveMessage'].
  *
  * @param Status $status
  */
 protected function leaveMessage($status)
 {
     if ($this->params['leaveMessage']) {
         if ($status->isGood()) {
             // @todo FIXME: user->leaveUserMessage does not exist.
             $this->user->leaveUserMessage(wfMessage('upload-success-subj')->text(), wfMessage('upload-success-msg', $this->upload->getTitle()->getText(), $this->params['url'])->text());
         } else {
             // @todo FIXME: user->leaveUserMessage does not exist.
             $this->user->leaveUserMessage(wfMessage('upload-failure-subj')->text(), wfMessage('upload-failure-msg', $status->getWikiText(), $this->params['url'])->text());
         }
     } else {
         $session = MediaWiki\Session\SessionManager::singleton()->getSessionById($this->params['sessionId']);
         if ($status->isOk()) {
             $this->storeResultInSession($session, 'Success', 'filename', $this->upload->getLocalFile()->getName());
         } else {
             $this->storeResultInSession($session, 'Failure', 'errors', $status->getErrorsArray());
         }
     }
 }
Example #7
0
        if (is_object($func[0])) {
            $profName = $fname . '-extensions-' . get_class($func[0]) . '::' . $func[1];
        } else {
            $profName = $fname . '-extensions-' . implode('::', $func);
        }
    } else {
        $profName = $fname . '-extensions-' . strval($func);
    }
    $ps_ext_func = Profiler::instance()->scopedProfileIn($profName);
    call_user_func($func);
    Profiler::instance()->scopedProfileOut($ps_ext_func);
}
// If the session user has a 0 id but a valid name, that means we need to
// autocreate it.
if (!defined('MW_NO_SESSION') && !$wgCommandLineMode) {
    $sessionUser = MediaWiki\Session\SessionManager::getGlobalSession()->getUser();
    if ($sessionUser->getId() === 0 && User::isValidUserName($sessionUser->getName())) {
        $ps_autocreate = Profiler::instance()->scopedProfileIn($fname . '-autocreate');
        MediaWiki\Session\SessionManager::autoCreateUser($sessionUser);
        Profiler::instance()->scopedProfileOut($ps_autocreate);
    }
    unset($sessionUser);
}
wfDebug("Fully initialised\n");
$wgFullyInitialised = true;
// T125455
if (!defined('MW_NO_SESSION') && !$wgCommandLineMode) {
    MediaWiki\Session\SessionManager::singleton()->checkIpLimits();
}
Profiler::instance()->scopedProfileOut($ps_extensions);
Profiler::instance()->scopedProfileOut($ps_setup);
Example #8
0
 /**
  * Constructs an instance of ApiMain that utilizes the module and format specified by $request.
  *
  * @param IContextSource|WebRequest $context If this is an instance of
  *    FauxRequest, errors are thrown and no printing occurs
  * @param bool $enableWrite Should be set to true if the api may modify data
  */
 public function __construct($context = null, $enableWrite = false)
 {
     if ($context === null) {
         $context = RequestContext::getMain();
     } elseif ($context instanceof WebRequest) {
         // BC for pre-1.19
         $request = $context;
         $context = RequestContext::getMain();
     }
     // We set a derivative context so we can change stuff later
     $this->setContext(new DerivativeContext($context));
     if (isset($request)) {
         $this->getContext()->setRequest($request);
     } else {
         $request = $this->getRequest();
     }
     $this->mInternalMode = $request instanceof FauxRequest;
     // Special handling for the main module: $parent === $this
     parent::__construct($this, $this->mInternalMode ? 'main_int' : 'main');
     $config = $this->getConfig();
     if (!$this->mInternalMode) {
         // Log if a request with a non-whitelisted Origin header is seen
         // with session cookies.
         $originHeader = $request->getHeader('Origin');
         if ($originHeader === false) {
             $origins = [];
         } else {
             $originHeader = trim($originHeader);
             $origins = preg_split('/\\s+/', $originHeader);
         }
         $sessionCookies = array_intersect(array_keys($_COOKIE), MediaWiki\Session\SessionManager::singleton()->getVaryCookies());
         if ($origins && $sessionCookies && (count($origins) !== 1 || !self::matchOrigin($origins[0], $config->get('CrossSiteAJAXdomains'), $config->get('CrossSiteAJAXdomainExceptions')))) {
             LoggerFactory::getInstance('cors')->warning('Non-whitelisted CORS request with session cookies', ['origin' => $originHeader, 'cookies' => $sessionCookies, 'ip' => $request->getIP(), 'userAgent' => $this->getUserAgent(), 'wiki' => wfWikiID()]);
         }
         // If we're in a mode that breaks the same-origin policy, strip
         // user credentials for security.
         if ($this->lacksSameOriginSecurity()) {
             global $wgUser;
             wfDebug("API: stripping user credentials when the same-origin policy is not applied\n");
             $wgUser = new User();
             $this->getContext()->setUser($wgUser);
         }
     }
     $uselang = $this->getParameter('uselang');
     if ($uselang === 'user') {
         // Assume the parent context is going to return the user language
         // for uselang=user (see T85635).
     } else {
         if ($uselang === 'content') {
             global $wgContLang;
             $uselang = $wgContLang->getCode();
         }
         $code = RequestContext::sanitizeLangCode($uselang);
         $this->getContext()->setLanguage($code);
         if (!$this->mInternalMode) {
             global $wgLang;
             $wgLang = $this->getContext()->getLanguage();
             RequestContext::getMain()->setLanguage($wgLang);
         }
     }
     $this->mModuleMgr = new ApiModuleManager($this);
     $this->mModuleMgr->addModules(self::$Modules, 'action');
     $this->mModuleMgr->addModules($config->get('APIModules'), 'action');
     $this->mModuleMgr->addModules(self::$Formats, 'format');
     $this->mModuleMgr->addModules($config->get('APIFormatModules'), 'format');
     Hooks::run('ApiMain::moduleManager', [$this->mModuleMgr]);
     $this->mResult = new ApiResult($this->getConfig()->get('APIMaxResultSize'));
     $this->mErrorFormatter = new ApiErrorFormatter_BackCompat($this->mResult);
     $this->mResult->setErrorFormatter($this->mErrorFormatter);
     $this->mContinuationManager = null;
     $this->mEnableWrite = $enableWrite;
     $this->mSquidMaxage = -1;
     // flag for executeActionWithErrorHandling()
     $this->mCommit = false;
 }