function execute($par)
 {
     /**
      * Some satellite ISPs use broken precaching schemes that log people out straight after
      * they're logged in (bug 17790). Luckily, there's a way to detect such requests.
      */
     if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], '&') !== false) {
         wfDebug("Special:Userlogout request {$_SERVER['REQUEST_URI']} looks suspicious, denying.\n");
         throw new HttpError(400, $this->msg('suspicious-userlogout'), $this->msg('loginerror'));
     }
     $this->setHeaders();
     $this->outputHeader();
     // Make sure it's possible to log out
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     if (!$session->canSetUser()) {
         throw new ErrorPageError('cannotlogoutnow-title', 'cannotlogoutnow-text', [$session->getProvider()->describe(RequestContext::getMain()->getLanguage())]);
     }
     $user = $this->getUser();
     $oldName = $user->getName();
     $user->logout();
     $loginURL = SpecialPage::getTitleFor('Userlogin')->getFullURL($this->getRequest()->getValues('returnto', 'returntoquery'));
     $out = $this->getOutput();
     $out->addWikiMsg('logouttext', $loginURL);
     // Hook.
     $injected_html = '';
     Hooks::run('UserLogoutComplete', [&$user, &$injected_html, $oldName]);
     $out->addHTML($injected_html);
     $out->returnToMain();
 }
Example #2
0
 function onView()
 {
     $this->getOutput()->disable();
     $request = $this->getRequest();
     $response = $request->response();
     $config = $this->context->getConfig();
     if (!$request->checkUrlExtension()) {
         return;
     }
     if ($this->getOutput()->checkLastModified($this->page->getTouched())) {
         return;
         // Client cache fresh and headers sent, nothing more to do.
     }
     $gen = $request->getVal('gen');
     if ($gen == 'css' || $gen == 'js') {
         $this->gen = true;
     }
     $contentType = $this->getContentType();
     $maxage = $request->getInt('maxage', $config->get('SquidMaxage'));
     $smaxage = $request->getIntOrNull('smaxage');
     if ($smaxage === null) {
         if ($contentType == 'text/css' || $contentType == 'text/javascript') {
             // CSS/JS raw content has its own CDN max age configuration.
             // Note: Title::getCdnUrls() includes action=raw for css/js pages,
             // so if using the canonical url, this will get HTCP purges.
             $smaxage = intval($config->get('ForcedRawSMaxage'));
         } else {
             // No CDN cache for anything else
             $smaxage = 0;
         }
     }
     $response->header('Content-type: ' . $contentType . '; charset=UTF-8');
     // Output may contain user-specific data;
     // vary generated content for open sessions on private wikis
     $privateCache = !User::isEveryoneAllowed('read') && ($smaxage == 0 || MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent());
     // Don't accidentally cache cookies if user is logged in (T55032)
     $privateCache = $privateCache || $this->getUser()->isLoggedIn();
     $mode = $privateCache ? 'private' : 'public';
     $response->header('Cache-Control: ' . $mode . ', s-maxage=' . $smaxage . ', max-age=' . $maxage);
     $text = $this->getRawText();
     // Don't return a 404 response for CSS or JavaScript;
     // 404s aren't generally cached and it would create
     // extra hits when user CSS/JS are on and the user doesn't
     // have the pages.
     if ($text === false && $contentType == 'text/x-wiki') {
         $response->statusHeader(404);
     }
     if (!Hooks::run('RawPageViewBeforeOutput', array(&$this, &$text))) {
         wfDebug(__METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n");
     }
     echo $text;
 }
Example #3
0
 public function execute()
 {
     // Make sure it's possible to log out
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     if (!$session->canSetUser()) {
         $this->dieUsage('Cannot log out when using ' . $session->getProvider()->describe(Language::factory('en')), 'cannotlogout');
     }
     $user = $this->getUser();
     $oldName = $user->getName();
     $user->logout();
     // Give extensions to do something after user logout
     $injected_html = '';
     Hooks::run('UserLogoutComplete', array(&$user, &$injected_html, $oldName));
 }
 /**
  * @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 #5
0
 public function execute()
 {
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     // Handle bot password logout specially
     if ($session->getProvider() instanceof BotPasswordSessionProvider) {
         $session->unpersist();
         return;
     }
     // Make sure it's possible to log out
     if (!$session->canSetUser()) {
         $this->dieUsage('Cannot log out when using ' . $session->getProvider()->describe(Language::factory('en')), 'cannotlogout');
     }
     $user = $this->getUser();
     $oldName = $user->getName();
     $user->logout();
     // Give extensions to do something after user logout
     $injected_html = '';
     Hooks::run('UserLogoutComplete', [&$user, &$injected_html, $oldName]);
 }
Example #6
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 #7
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 #8
0
// any necessary initialisation in the fully initialised environment
foreach ($wgExtensionFunctions as $func) {
    // Allow closures in PHP 5.3+
    if (is_object($func) && $func instanceof Closure) {
        $profName = $fname . '-extensions-closure';
    } elseif (is_array($func)) {
        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.
$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;
Profiler::instance()->scopedProfileOut($ps_extensions);
Profiler::instance()->scopedProfileOut($ps_setup);
Example #9
0
 /**
  * Send caching headers
  * @param boolean $isError Whether an error response is being output
  * @since 1.26 added $isError parameter
  */
 protected function sendCacheHeaders($isError)
 {
     $response = $this->getRequest()->response();
     $out = $this->getOutput();
     $config = $this->getConfig();
     if ($config->get('VaryOnXFP')) {
         $out->addVaryHeader('X-Forwarded-Proto');
     }
     if (!$isError && $this->mModule && ($this->getRequest()->getMethod() === 'GET' || $this->getRequest()->getMethod() === 'HEAD')) {
         $etag = $this->mModule->getConditionalRequestData('etag');
         if ($etag !== null) {
             $response->header("ETag: {$etag}");
         }
         $lastMod = $this->mModule->getConditionalRequestData('last-modified');
         if ($lastMod !== null) {
             $response->header('Last-Modified: ' . wfTimestamp(TS_RFC2822, $lastMod));
         }
     }
     // The logic should be:
     // $this->mCacheControl['max-age'] is set?
     //    Use it, the module knows better than our guess.
     // !$this->mModule || $this->mModule->isWriteMode(), and mCacheMode is private?
     //    Use 0 because we can guess caching is probably the wrong thing to do.
     // Use $this->getParameter( 'maxage' ), which already defaults to 0.
     $maxage = 0;
     if (isset($this->mCacheControl['max-age'])) {
         $maxage = $this->mCacheControl['max-age'];
     } elseif ($this->mModule && !$this->mModule->isWriteMode() || $this->mCacheMode !== 'private') {
         $maxage = $this->getParameter('maxage');
     }
     $privateCache = 'private, must-revalidate, max-age=' . $maxage;
     if ($this->mCacheMode == 'private') {
         $response->header("Cache-Control: {$privateCache}");
         return;
     }
     $useKeyHeader = $config->get('UseKeyHeader');
     if ($this->mCacheMode == 'anon-public-user-private') {
         $out->addVaryHeader('Cookie');
         $response->header($out->getVaryHeader());
         if ($useKeyHeader) {
             $response->header($out->getKeyHeader());
             if ($out->haveCacheVaryCookies()) {
                 // Logged in, mark this request private
                 $response->header("Cache-Control: {$privateCache}");
                 return;
             }
             // Logged out, send normal public headers below
         } elseif (MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent()) {
             // Logged in or otherwise has session (e.g. anonymous users who have edited)
             // Mark request private
             $response->header("Cache-Control: {$privateCache}");
             return;
         }
         // else no Key and anonymous, send public headers below
     }
     // Send public headers
     $response->header($out->getVaryHeader());
     if ($useKeyHeader) {
         $response->header($out->getKeyHeader());
     }
     // If nobody called setCacheMaxAge(), use the (s)maxage parameters
     if (!isset($this->mCacheControl['s-maxage'])) {
         $this->mCacheControl['s-maxage'] = $this->getParameter('smaxage');
     }
     if (!isset($this->mCacheControl['max-age'])) {
         $this->mCacheControl['max-age'] = $this->getParameter('maxage');
     }
     if (!$this->mCacheControl['s-maxage'] && !$this->mCacheControl['max-age']) {
         // Public cache not requested
         // Sending a Vary header in this case is harmless, and protects us
         // against conditional calls of setCacheMaxAge().
         $response->header("Cache-Control: {$privateCache}");
         return;
     }
     $this->mCacheControl['public'] = true;
     // Send an Expires header
     $maxAge = min($this->mCacheControl['s-maxage'], $this->mCacheControl['max-age']);
     $expiryUnixTime = $maxAge == 0 ? 1 : time() + $maxAge;
     $response->header('Expires: ' . wfTimestamp(TS_RFC2822, $expiryUnixTime));
     // Construct the Cache-Control header
     $ccHeader = '';
     $separator = '';
     foreach ($this->mCacheControl as $name => $value) {
         if (is_bool($value)) {
             if ($value) {
                 $ccHeader .= $separator . $name;
                 $separator = ', ';
             }
         } else {
             $ccHeader .= $separator . "{$name}={$value}";
             $separator = ', ';
         }
     }
     $response->header("Cache-Control: {$ccHeader}");
 }
Example #10
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 #11
0
 protected function tearDown()
 {
     global $wgRequest, $wgSQLMode;
     $status = ob_get_status();
     if (isset($status['name']) && $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier') {
         ob_end_flush();
     }
     $this->called['tearDown'] = true;
     // Cleaning up temporary files
     foreach ($this->tmpFiles as $fileName) {
         if (is_file($fileName) || is_link($fileName)) {
             unlink($fileName);
         } elseif (is_dir($fileName)) {
             wfRecursiveRemoveDir($fileName);
         }
     }
     if ($this->needsDB() && $this->db) {
         // Clean up open transactions
         while ($this->db->trxLevel() > 0) {
             $this->db->rollback(__METHOD__, 'flush');
         }
         if ($this->db->getType() === 'mysql') {
             $this->db->query("SET sql_mode = " . $this->db->addQuotes($wgSQLMode));
         }
     }
     // Restore mw globals
     foreach ($this->mwGlobals as $key => $value) {
         $GLOBALS[$key] = $value;
     }
     $this->mwGlobals = [];
     $this->restoreLoggers();
     if (self::$serviceLocator && MediaWikiServices::getInstance() !== self::$serviceLocator) {
         MediaWikiServices::forceGlobalInstance(self::$serviceLocator);
     }
     // TODO: move global state into MediaWikiServices
     RequestContext::resetMain();
     if (session_id() !== '') {
         session_write_close();
         session_id('');
     }
     $wgRequest = new FauxRequest();
     MediaWiki\Session\SessionManager::resetCache();
     MediaWiki\Auth\AuthManager::resetCache();
     $phpErrorLevel = intval(ini_get('error_reporting'));
     if ($phpErrorLevel !== $this->phpErrorLevel) {
         ini_set('error_reporting', $this->phpErrorLevel);
         $oldHex = strtoupper(dechex($this->phpErrorLevel));
         $newHex = strtoupper(dechex($phpErrorLevel));
         $message = "PHP error_reporting setting was left dirty: " . "was 0x{$oldHex} before test, 0x{$newHex} after test!";
         $this->fail($message);
     }
     parent::tearDown();
 }
Example #12
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');
        $res = MediaWiki\Auth\AuthManager::singleton()->autoCreateUser($sessionUser, MediaWiki\Auth\AuthManager::AUTOCREATE_SOURCE_SESSION, true);
        Profiler::instance()->scopedProfileOut($ps_autocreate);
        \MediaWiki\Logger\LoggerFactory::getInstance('authevents')->info('Autocreation attempt', ['event' => 'autocreate', 'status' => $res]);
        unset($res);
    }
    unset($sessionUser);
}
if (!$wgCommandLineMode) {
    Pingback::schedulePingback();
}
wfDebug("Fully initialised\n");
$wgFullyInitialised = true;
Profiler::instance()->scopedProfileOut($ps_extensions);
Example #13
0
 /**
  * Initialize the session data. Sets the initial result to queued.
  */
 public function initializeSessionData()
 {
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     $data = self::getSessionData($session, $this->params['sessionKey']);
     $data['result'] = 'Queued';
     self::setSessionData($session, $this->params['sessionKey'], $data);
 }
Example #14
0
 public function execute()
 {
     // If we're in a mode that breaks the same-origin policy, no tokens can
     // be obtained
     if ($this->lacksSameOriginSecurity()) {
         $this->dieUsage('Cannot create account when the same-origin policy is not applied', 'aborted');
     }
     // $loginForm->addNewaccountInternal will throw exceptions
     // if wiki is read only (already handled by api), user is blocked or does not have rights.
     // Use userCan in order to hit GlobalBlock checks (according to Special:userlogin)
     $loginTitle = SpecialPage::getTitleFor('Userlogin');
     if (!$loginTitle->userCan('createaccount', $this->getUser())) {
         $this->dieUsage('You do not have the right to create a new account', 'permdenied-createaccount');
     }
     if ($this->getUser()->isBlockedFromCreateAccount()) {
         $this->dieUsage('You cannot create a new account because you are blocked', 'blocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($this->getUser()->getBlock())));
     }
     $params = $this->extractRequestParams();
     // Make sure session is persisted
     MediaWiki\Session\SessionManager::getGlobalSession()->persist();
     if ($params['mailpassword'] && !$params['email']) {
         $this->dieUsageMsg('noemail');
     }
     if ($params['language'] && !Language::isSupportedLanguage($params['language'])) {
         $this->dieUsage('Invalid language parameter', 'langinvalid');
     }
     $context = new DerivativeContext($this->getContext());
     $context->setRequest(new DerivativeRequest($this->getContext()->getRequest(), array('type' => 'signup', 'uselang' => $params['language'], 'wpName' => $params['name'], 'wpPassword' => $params['password'], 'wpRetype' => $params['password'], 'wpDomain' => $params['domain'], 'wpEmail' => $params['email'], 'wpRealName' => $params['realname'], 'wpCreateaccountToken' => $params['token'], 'wpCreateaccount' => $params['mailpassword'] ? null : '1', 'wpCreateaccountMail' => $params['mailpassword'] ? '1' : null)));
     $loginForm = new LoginForm();
     $loginForm->setContext($context);
     Hooks::run('AddNewAccountApiForm', array($this, $loginForm));
     $loginForm->load();
     $status = $loginForm->addNewAccountInternal();
     LoggerFactory::getInstance('authmanager')->info('Account creation attempt via API', array('event' => 'accountcreation', 'status' => $status));
     $result = array();
     if ($status->isGood()) {
         // Success!
         $user = $status->getValue();
         if ($params['language']) {
             $user->setOption('language', $params['language']);
         }
         if ($params['mailpassword']) {
             // If mailpassword was set, disable the password and send an email.
             $user->setPassword(null);
             $status->merge($loginForm->mailPasswordInternal($user, false, 'createaccount-title', 'createaccount-text'));
         } elseif ($this->getConfig()->get('EmailAuthentication') && Sanitizer::validateEmail($user->getEmail())) {
             // Send out an email authentication message if needed
             $status->merge($user->sendConfirmationMail());
         }
         // Save settings (including confirmation token)
         $user->saveSettings();
         Hooks::run('AddNewAccount', array($user, $params['mailpassword']));
         if ($params['mailpassword']) {
             $logAction = 'byemail';
         } elseif ($this->getUser()->isLoggedIn()) {
             $logAction = 'create2';
         } else {
             $logAction = 'create';
         }
         $user->addNewUserLogEntry($logAction, (string) $params['reason']);
         // Add username, id, and token to result.
         $result['username'] = $user->getName();
         $result['userid'] = $user->getId();
         $result['token'] = $user->getToken();
     }
     $apiResult = $this->getResult();
     if ($status->hasMessage('sessionfailure') || $status->hasMessage('nocookiesfornew')) {
         // Token was incorrect, so add it to result, but don't throw an exception
         // since not having the correct token is part of the normal
         // flow of events.
         $result['token'] = LoginForm::getCreateaccountToken();
         $result['result'] = 'NeedToken';
     } elseif (!$status->isOK()) {
         // There was an error. Die now.
         $this->dieStatus($status);
     } elseif (!$status->isGood()) {
         // Status is not good, but OK. This means warnings.
         $result['result'] = 'Warning';
         // Add any warnings to the result
         $warnings = $status->getErrorsByType('warning');
         if ($warnings) {
             foreach ($warnings as &$warning) {
                 ApiResult::setIndexedTagName($warning['params'], 'param');
             }
             ApiResult::setIndexedTagName($warnings, 'warning');
             $result['warnings'] = $warnings;
         }
     } else {
         // Everything was fine.
         $result['result'] = 'Success';
     }
     // Give extensions a chance to modify the API result data
     Hooks::run('AddNewAccountApiResult', array($this, $loginForm, &$result));
     $apiResult->addValue(null, 'createaccount', $result);
 }
Example #15
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 #16
0
 /**
  * @param string $comment
  * @param string $pageText
  * @param bool $watch
  * @param User $user
  * @return string
  */
 protected function insertJob($comment, $pageText, $watch, $user)
 {
     $sessionKey = $this->stashSession();
     $job = new UploadFromUrlJob($this->getTitle(), array('url' => $this->mUrl, 'comment' => $comment, 'pageText' => $pageText, 'watch' => $watch, 'userName' => $user->getName(), 'leaveMessage' => $this->mAsync == 'async-leavemessage', 'ignoreWarnings' => $this->mIgnoreWarnings, 'sessionId' => MediaWiki\Session\SessionManager::getGlobalSession()->getId(), 'sessionKey' => $sessionKey));
     $job->initializeSessionData();
     JobQueueGroup::singleton()->push($job);
     return $sessionKey;
 }
Example #17
0
 /**
  * Executes the log-in attempt using the parameters passed. If
  * the log-in succeeds, it attaches a cookie to the session
  * and outputs the user id, username, and session token. If a
  * log-in fails, as the result of a bad password, a nonexistent
  * user, or any other reason, the host is cached with an expiry
  * and no log-in attempts will be accepted until that expiry
  * is reached. The expiry is $this->mLoginThrottle.
  */
 public function execute()
 {
     // If we're in a mode that breaks the same-origin policy, no tokens can
     // be obtained
     if ($this->lacksSameOriginSecurity()) {
         $this->getResult()->addValue(null, 'login', array('result' => 'Aborted', 'reason' => 'Cannot log in when the same-origin policy is not applied'));
         return;
     }
     $params = $this->extractRequestParams();
     $result = array();
     // Make sure session is persisted
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     $session->persist();
     // Make sure it's possible to log in
     if (!$session->canSetUser()) {
         $this->getResult()->addValue(null, 'login', array('result' => 'Aborted', 'reason' => 'Cannot log in when using ' . $session->getProvider()->describe(Language::factory('en'))));
         return;
     }
     $authRes = false;
     $context = new DerivativeContext($this->getContext());
     $loginType = 'N/A';
     // Check login token
     $token = LoginForm::getLoginToken();
     if (!$token) {
         LoginForm::setLoginToken();
         $authRes = LoginForm::NEED_TOKEN;
     } elseif (!$params['token']) {
         $authRes = LoginForm::NEED_TOKEN;
     } elseif ($token !== $params['token']) {
         $authRes = LoginForm::WRONG_TOKEN;
     }
     // Try bot passwords
     if ($authRes === false && $this->getConfig()->get('EnableBotPasswords') && strpos($params['name'], BotPassword::getSeparator()) !== false) {
         $status = BotPassword::login($params['name'], $params['password'], $this->getRequest());
         if ($status->isOk()) {
             $session = $status->getValue();
             $authRes = LoginForm::SUCCESS;
             $loginType = 'BotPassword';
         } else {
             LoggerFactory::getInstance('authmanager')->info('BotPassword login failed: ' . $status->getWikiText());
         }
     }
     // Normal login
     if ($authRes === false) {
         $context->setRequest(new DerivativeRequest($this->getContext()->getRequest(), array('wpName' => $params['name'], 'wpPassword' => $params['password'], 'wpDomain' => $params['domain'], 'wpLoginToken' => $params['token'], 'wpRemember' => '')));
         $loginForm = new LoginForm();
         $loginForm->setContext($context);
         $authRes = $loginForm->authenticateUserData();
         $loginType = 'LoginForm';
     }
     switch ($authRes) {
         case LoginForm::SUCCESS:
             $user = $context->getUser();
             $this->getContext()->setUser($user);
             $user->setCookies($this->getRequest(), null, true);
             ApiQueryInfo::resetTokenCache();
             // Run hooks.
             // @todo FIXME: Split back and frontend from this hook.
             // @todo FIXME: This hook should be placed in the backend
             $injected_html = '';
             Hooks::run('UserLoginComplete', array(&$user, &$injected_html));
             $result['result'] = 'Success';
             $result['lguserid'] = intval($user->getId());
             $result['lgusername'] = $user->getName();
             // @todo: These are deprecated, and should be removed at some
             // point (1.28 at the earliest, and see T121527). They were ok
             // when the core cookie-based login was the only thing, but
             // CentralAuth broke that a while back and
             // SessionManager/AuthManager are *really* going to break it.
             $result['lgtoken'] = $user->getToken();
             $result['cookieprefix'] = $this->getConfig()->get('CookiePrefix');
             $result['sessionid'] = $session->getId();
             break;
         case LoginForm::NEED_TOKEN:
             $result['result'] = 'NeedToken';
             $result['token'] = LoginForm::getLoginToken();
             // @todo: See above about deprecation
             $result['cookieprefix'] = $this->getConfig()->get('CookiePrefix');
             $result['sessionid'] = $session->getId();
             break;
         case LoginForm::WRONG_TOKEN:
             $result['result'] = 'WrongToken';
             break;
         case LoginForm::NO_NAME:
             $result['result'] = 'NoName';
             break;
         case LoginForm::ILLEGAL:
             $result['result'] = 'Illegal';
             break;
         case LoginForm::WRONG_PLUGIN_PASS:
             $result['result'] = 'WrongPluginPass';
             break;
         case LoginForm::NOT_EXISTS:
             $result['result'] = 'NotExists';
             break;
             // bug 20223 - Treat a temporary password as wrong. Per SpecialUserLogin:
             // The e-mailed temporary password should not be used for actual logins.
         // bug 20223 - Treat a temporary password as wrong. Per SpecialUserLogin:
         // The e-mailed temporary password should not be used for actual logins.
         case LoginForm::RESET_PASS:
         case LoginForm::WRONG_PASS:
             $result['result'] = 'WrongPass';
             break;
         case LoginForm::EMPTY_PASS:
             $result['result'] = 'EmptyPass';
             break;
         case LoginForm::CREATE_BLOCKED:
             $result['result'] = 'CreateBlocked';
             $result['details'] = 'Your IP address is blocked from account creation';
             $block = $context->getUser()->getBlock();
             if ($block) {
                 $result = array_merge($result, ApiQueryUserInfo::getBlockInfo($block));
             }
             break;
         case LoginForm::THROTTLED:
             $result['result'] = 'Throttled';
             $throttle = $this->getConfig()->get('PasswordAttemptThrottle');
             $result['wait'] = intval($throttle['seconds']);
             break;
         case LoginForm::USER_BLOCKED:
             $result['result'] = 'Blocked';
             $block = User::newFromName($params['name'])->getBlock();
             if ($block) {
                 $result = array_merge($result, ApiQueryUserInfo::getBlockInfo($block));
             }
             break;
         case LoginForm::ABORTED:
             $result['result'] = 'Aborted';
             $result['reason'] = $loginForm->mAbortLoginErrorMsg;
             break;
         default:
             ApiBase::dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
     }
     $this->getResult()->addValue(null, 'login', $result);
     LoggerFactory::getInstance('authmanager')->info('Login attempt', array('event' => 'login', 'successful' => $authRes === LoginForm::SUCCESS, 'loginType' => $loginType, 'status' => LoginForm::$statusCodes[$authRes]));
 }
Example #18
0
 protected function tearDown()
 {
     // Avoid leaking session over tests
     MediaWiki\Session\SessionManager::getGlobalSession()->clear();
     parent::tearDown();
 }
Example #19
0
 protected function tearDown()
 {
     global $wgRequest;
     $status = ob_get_status();
     if (isset($status['name']) && $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier') {
         ob_end_flush();
     }
     $this->called['tearDown'] = true;
     // Cleaning up temporary files
     foreach ($this->tmpFiles as $fileName) {
         if (is_file($fileName) || is_link($fileName)) {
             unlink($fileName);
         } elseif (is_dir($fileName)) {
             wfRecursiveRemoveDir($fileName);
         }
     }
     if ($this->needsDB() && $this->db) {
         // Clean up open transactions
         while ($this->db->trxLevel() > 0) {
             $this->db->rollback(__METHOD__, 'flush');
         }
     }
     // Restore mw globals
     foreach ($this->mwGlobals as $key => $value) {
         $GLOBALS[$key] = $value;
     }
     $this->mwGlobals = array();
     RequestContext::resetMain();
     MediaHandler::resetCache();
     if (session_id() !== '') {
         session_write_close();
         session_id('');
     }
     $wgRequest = new FauxRequest();
     MediaWiki\Session\SessionManager::resetCache();
     $phpErrorLevel = intval(ini_get('error_reporting'));
     if ($phpErrorLevel !== $this->phpErrorLevel) {
         ini_set('error_reporting', $this->phpErrorLevel);
         $oldHex = strtoupper(dechex($this->phpErrorLevel));
         $newHex = strtoupper(dechex($phpErrorLevel));
         $message = "PHP error_reporting setting was left dirty: " . "was 0x{$oldHex} before test, 0x{$newHex} after test!";
         $this->fail($message);
     }
     parent::tearDown();
 }
Example #20
0
 public function show()
 {
     // Send a cookie so anons get talk message notifications
     MediaWiki\Session\SessionManager::getGlobalSession()->persist();
     parent::show();
 }
Example #21
0
 /**
  * Executes the log-in attempt using the parameters passed. If
  * the log-in succeeds, it attaches a cookie to the session
  * and outputs the user id, username, and session token. If a
  * log-in fails, as the result of a bad password, a nonexistent
  * user, or any other reason, the host is cached with an expiry
  * and no log-in attempts will be accepted until that expiry
  * is reached. The expiry is $this->mLoginThrottle.
  */
 public function execute()
 {
     // If we're in a mode that breaks the same-origin policy, no tokens can
     // be obtained
     if ($this->lacksSameOriginSecurity()) {
         $this->getResult()->addValue(null, 'login', ['result' => 'Aborted', 'reason' => 'Cannot log in when the same-origin policy is not applied']);
         return;
     }
     $params = $this->extractRequestParams();
     $result = [];
     // Make sure session is persisted
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     $session->persist();
     // Make sure it's possible to log in
     if (!$session->canSetUser()) {
         $this->getResult()->addValue(null, 'login', ['result' => 'Aborted', 'reason' => 'Cannot log in when using ' . $session->getProvider()->describe(Language::factory('en'))]);
         return;
     }
     $authRes = false;
     $context = new DerivativeContext($this->getContext());
     $loginType = 'N/A';
     // Check login token
     $token = $session->getToken('', 'login');
     if ($token->wasNew() || !$params['token']) {
         $authRes = 'NeedToken';
     } elseif (!$token->match($params['token'])) {
         $authRes = 'WrongToken';
     }
     // Try bot passwords
     if ($authRes === false && $this->getConfig()->get('EnableBotPasswords') && strpos($params['name'], BotPassword::getSeparator()) !== false) {
         $status = BotPassword::login($params['name'], $params['password'], $this->getRequest());
         if ($status->isOK()) {
             $session = $status->getValue();
             $authRes = 'Success';
             $loginType = 'BotPassword';
         } else {
             $authRes = 'Failed';
             $message = $status->getMessage();
             LoggerFactory::getInstance('authmanager')->info('BotPassword login failed: ' . $status->getWikiText(false, false, 'en'));
         }
     }
     if ($authRes === false) {
         if ($this->getConfig()->get('DisableAuthManager')) {
             // Non-AuthManager login
             $context->setRequest(new DerivativeRequest($this->getContext()->getRequest(), ['wpName' => $params['name'], 'wpPassword' => $params['password'], 'wpDomain' => $params['domain'], 'wpLoginToken' => $params['token'], 'wpRemember' => '']));
             $loginForm = new LoginForm();
             $loginForm->setContext($context);
             $authRes = $loginForm->authenticateUserData();
             $loginType = 'LoginForm';
             switch ($authRes) {
                 case LoginForm::SUCCESS:
                     $authRes = 'Success';
                     break;
                 case LoginForm::NEED_TOKEN:
                     $authRes = 'NeedToken';
                     break;
             }
         } else {
             // Simplified AuthManager login, for backwards compatibility
             $manager = AuthManager::singleton();
             $reqs = AuthenticationRequest::loadRequestsFromSubmission($manager->getAuthenticationRequests(AuthManager::ACTION_LOGIN, $this->getUser()), ['username' => $params['name'], 'password' => $params['password'], 'domain' => $params['domain'], 'rememberMe' => true]);
             $res = AuthManager::singleton()->beginAuthentication($reqs, 'null:');
             switch ($res->status) {
                 case AuthenticationResponse::PASS:
                     if ($this->getConfig()->get('EnableBotPasswords')) {
                         $warn = 'Main-account login via action=login is deprecated and may stop working ' . 'without warning.';
                         $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
                         $warn .= ' To safely continue using main-account login, see action=clientlogin.';
                     } else {
                         $warn = 'Login via action=login is deprecated and may stop working without warning.';
                         $warn .= ' To safely log in, see action=clientlogin.';
                     }
                     $this->setWarning($warn);
                     $authRes = 'Success';
                     $loginType = 'AuthManager';
                     break;
                 case AuthenticationResponse::FAIL:
                     // Hope it's not a PreAuthenticationProvider that failed...
                     $authRes = 'Failed';
                     $message = $res->message;
                     \MediaWiki\Logger\LoggerFactory::getInstance('authentication')->info(__METHOD__ . ': Authentication failed: ' . $message->plain());
                     break;
                 default:
                     $authRes = 'Aborted';
                     break;
             }
         }
     }
     $result['result'] = $authRes;
     switch ($authRes) {
         case 'Success':
             if ($this->getConfig()->get('DisableAuthManager')) {
                 $user = $context->getUser();
                 $this->getContext()->setUser($user);
                 $user->setCookies($this->getRequest(), null, true);
             } else {
                 $user = $session->getUser();
             }
             ApiQueryInfo::resetTokenCache();
             // Deprecated hook
             $injected_html = '';
             Hooks::run('UserLoginComplete', [&$user, &$injected_html]);
             $result['lguserid'] = intval($user->getId());
             $result['lgusername'] = $user->getName();
             // @todo: These are deprecated, and should be removed at some
             // point (1.28 at the earliest, and see T121527). They were ok
             // when the core cookie-based login was the only thing, but
             // CentralAuth broke that a while back and
             // SessionManager/AuthManager *really* break it.
             $result['lgtoken'] = $user->getToken();
             $result['cookieprefix'] = $this->getConfig()->get('CookiePrefix');
             $result['sessionid'] = $session->getId();
             break;
         case 'NeedToken':
             $result['token'] = $token->toString();
             $this->setWarning('Fetching a token via action=login is deprecated. ' . 'Use action=query&meta=tokens&type=login instead.');
             $this->logFeatureUsage('action=login&!lgtoken');
             // @todo: See above about deprecation
             $result['cookieprefix'] = $this->getConfig()->get('CookiePrefix');
             $result['sessionid'] = $session->getId();
             break;
         case 'WrongToken':
             break;
         case 'Failed':
             $result['reason'] = $message->useDatabase('false')->inLanguage('en')->text();
             break;
         case 'Aborted':
             $result['reason'] = 'Authentication requires user interaction, ' . 'which is not supported by action=login.';
             if ($this->getConfig()->get('EnableBotPasswords')) {
                 $result['reason'] .= ' To be able to login with action=login, see [[Special:BotPasswords]].';
                 $result['reason'] .= ' To continue using main-account login, see action=clientlogin.';
             } else {
                 $result['reason'] .= ' To log in, see action=clientlogin.';
             }
             break;
             // Results from LoginForm for when $wgDisableAuthManager is true
         // Results from LoginForm for when $wgDisableAuthManager is true
         case LoginForm::WRONG_TOKEN:
             $result['result'] = 'WrongToken';
             break;
         case LoginForm::NO_NAME:
             $result['result'] = 'NoName';
             break;
         case LoginForm::ILLEGAL:
             $result['result'] = 'Illegal';
             break;
         case LoginForm::WRONG_PLUGIN_PASS:
             $result['result'] = 'WrongPluginPass';
             break;
         case LoginForm::NOT_EXISTS:
             $result['result'] = 'NotExists';
             break;
             // bug 20223 - Treat a temporary password as wrong. Per SpecialUserLogin:
             // The e-mailed temporary password should not be used for actual logins.
         // bug 20223 - Treat a temporary password as wrong. Per SpecialUserLogin:
         // The e-mailed temporary password should not be used for actual logins.
         case LoginForm::RESET_PASS:
         case LoginForm::WRONG_PASS:
             $result['result'] = 'WrongPass';
             break;
         case LoginForm::EMPTY_PASS:
             $result['result'] = 'EmptyPass';
             break;
         case LoginForm::CREATE_BLOCKED:
             $result['result'] = 'CreateBlocked';
             $result['details'] = 'Your IP address is blocked from account creation';
             $block = $context->getUser()->getBlock();
             if ($block) {
                 $result = array_merge($result, ApiQueryUserInfo::getBlockInfo($block));
             }
             break;
         case LoginForm::THROTTLED:
             $result['result'] = 'Throttled';
             $result['wait'] = intval($loginForm->mThrottleWait);
             break;
         case LoginForm::USER_BLOCKED:
             $result['result'] = 'Blocked';
             $block = User::newFromName($params['name'])->getBlock();
             if ($block) {
                 $result = array_merge($result, ApiQueryUserInfo::getBlockInfo($block));
             }
             break;
         case LoginForm::ABORTED:
             $result['result'] = 'Aborted';
             $result['reason'] = $loginForm->mAbortLoginErrorMsg;
             break;
         default:
             ApiBase::dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
     }
     $this->getResult()->addValue(null, 'login', $result);
     if ($loginType === 'LoginForm' && isset(LoginForm::$statusCodes[$authRes])) {
         $authRes = LoginForm::$statusCodes[$authRes];
     }
     LoggerFactory::getInstance('authmanager')->info('Login attempt', ['event' => 'login', 'successful' => $authRes === 'Success', 'loginType' => $loginType, 'status' => $authRes]);
 }
Example #22
0
 /**
  * Executes the log-in attempt using the parameters passed. If
  * the log-in succeeds, it attaches a cookie to the session
  * and outputs the user id, username, and session token. If a
  * log-in fails, as the result of a bad password, a nonexistent
  * user, or any other reason, the host is cached with an expiry
  * and no log-in attempts will be accepted until that expiry
  * is reached. The expiry is $this->mLoginThrottle.
  */
 public function execute()
 {
     // If we're in a mode that breaks the same-origin policy, no tokens can
     // be obtained
     if ($this->lacksSameOriginSecurity()) {
         $this->getResult()->addValue(null, 'login', ['result' => 'Aborted', 'reason' => 'Cannot log in when the same-origin policy is not applied']);
         return;
     }
     try {
         $this->requirePostedParameters(['password', 'token']);
     } catch (UsageException $ex) {
         // Make this a warning for now, upgrade to an error in 1.29.
         $this->setWarning($ex->getMessage());
         $this->logFeatureUsage('login-params-in-query-string');
     }
     $params = $this->extractRequestParams();
     $result = [];
     // Make sure session is persisted
     $session = MediaWiki\Session\SessionManager::getGlobalSession();
     $session->persist();
     // Make sure it's possible to log in
     if (!$session->canSetUser()) {
         $this->getResult()->addValue(null, 'login', ['result' => 'Aborted', 'reason' => 'Cannot log in when using ' . $session->getProvider()->describe(Language::factory('en'))]);
         return;
     }
     $authRes = false;
     $context = new DerivativeContext($this->getContext());
     $loginType = 'N/A';
     // Check login token
     $token = $session->getToken('', 'login');
     if ($token->wasNew() || !$params['token']) {
         $authRes = 'NeedToken';
     } elseif (!$token->match($params['token'])) {
         $authRes = 'WrongToken';
     }
     // Try bot passwords
     if ($authRes === false && $this->getConfig()->get('EnableBotPasswords') && ($botLoginData = BotPassword::canonicalizeLoginData($params['name'], $params['password']))) {
         $status = BotPassword::login($botLoginData[0], $botLoginData[1], $this->getRequest());
         if ($status->isOK()) {
             $session = $status->getValue();
             $authRes = 'Success';
             $loginType = 'BotPassword';
         } elseif (!$botLoginData[2]) {
             $authRes = 'Failed';
             $message = $status->getMessage();
             LoggerFactory::getInstance('authentication')->info('BotPassword login failed: ' . $status->getWikiText(false, false, 'en'));
         }
     }
     if ($authRes === false) {
         // Simplified AuthManager login, for backwards compatibility
         $manager = AuthManager::singleton();
         $reqs = AuthenticationRequest::loadRequestsFromSubmission($manager->getAuthenticationRequests(AuthManager::ACTION_LOGIN, $this->getUser()), ['username' => $params['name'], 'password' => $params['password'], 'domain' => $params['domain'], 'rememberMe' => true]);
         $res = AuthManager::singleton()->beginAuthentication($reqs, 'null:');
         switch ($res->status) {
             case AuthenticationResponse::PASS:
                 if ($this->getConfig()->get('EnableBotPasswords')) {
                     $warn = 'Main-account login via action=login is deprecated and may stop working ' . 'without warning.';
                     $warn .= ' To continue login with action=login, see [[Special:BotPasswords]].';
                     $warn .= ' To safely continue using main-account login, see action=clientlogin.';
                 } else {
                     $warn = 'Login via action=login is deprecated and may stop working without warning.';
                     $warn .= ' To safely log in, see action=clientlogin.';
                 }
                 $this->setWarning($warn);
                 $authRes = 'Success';
                 $loginType = 'AuthManager';
                 break;
             case AuthenticationResponse::FAIL:
                 // Hope it's not a PreAuthenticationProvider that failed...
                 $authRes = 'Failed';
                 $message = $res->message;
                 \MediaWiki\Logger\LoggerFactory::getInstance('authentication')->info(__METHOD__ . ': Authentication failed: ' . $message->inLanguage('en')->plain());
                 break;
             default:
                 \MediaWiki\Logger\LoggerFactory::getInstance('authentication')->info(__METHOD__ . ': Authentication failed due to unsupported response type: ' . $res->status, $this->getAuthenticationResponseLogData($res));
                 $authRes = 'Aborted';
                 break;
         }
     }
     $result['result'] = $authRes;
     switch ($authRes) {
         case 'Success':
             $user = $session->getUser();
             ApiQueryInfo::resetTokenCache();
             // Deprecated hook
             $injected_html = '';
             Hooks::run('UserLoginComplete', [&$user, &$injected_html, true]);
             $result['lguserid'] = intval($user->getId());
             $result['lgusername'] = $user->getName();
             break;
         case 'NeedToken':
             $result['token'] = $token->toString();
             $this->setWarning('Fetching a token via action=login is deprecated. ' . 'Use action=query&meta=tokens&type=login instead.');
             $this->logFeatureUsage('action=login&!lgtoken');
             break;
         case 'WrongToken':
             break;
         case 'Failed':
             $result['reason'] = $message->useDatabase('false')->inLanguage('en')->text();
             break;
         case 'Aborted':
             $result['reason'] = 'Authentication requires user interaction, ' . 'which is not supported by action=login.';
             if ($this->getConfig()->get('EnableBotPasswords')) {
                 $result['reason'] .= ' To be able to login with action=login, see [[Special:BotPasswords]].';
                 $result['reason'] .= ' To continue using main-account login, see action=clientlogin.';
             } else {
                 $result['reason'] .= ' To log in, see action=clientlogin.';
             }
             break;
         default:
             ApiBase::dieDebug(__METHOD__, "Unhandled case value: {$authRes}");
     }
     $this->getResult()->addValue(null, 'login', $result);
     if ($loginType === 'LoginForm' && isset(LoginForm::$statusCodes[$authRes])) {
         $authRes = LoginForm::$statusCodes[$authRes];
     }
     LoggerFactory::getInstance('authevents')->info('Login attempt', ['event' => 'login', 'successful' => $authRes === 'Success', 'loginType' => $loginType, 'status' => $authRes]);
 }