private function getProvider($name = null, $prefix = null)
 {
     global $wgSessionProviders;
     $params = ['priority' => 40, 'sessionCookieName' => $name, 'sessionCookieOptions' => []];
     if ($prefix !== null) {
         $params['sessionCookieOptions']['prefix'] = $prefix;
     }
     if (!$this->config) {
         $this->config = new \HashConfig(['CookiePrefix' => 'wgCookiePrefix', 'EnableBotPasswords' => true, 'BotPasswordsDatabase' => false, 'SessionProviders' => $wgSessionProviders + [BotPasswordSessionProvider::class => ['class' => BotPasswordSessionProvider::class, 'args' => [$params]]]]);
     }
     $manager = new SessionManager(['config' => new \MultiConfig([$this->config, \RequestContext::getMain()->getConfig()]), 'logger' => new \Psr\Log\NullLogger(), 'store' => new TestBagOStuff()]);
     return $manager->getProvider(BotPasswordSessionProvider::class);
 }
 private function getProvider($name = null, $prefix = null)
 {
     global $wgSessionProviders;
     $params = array('priority' => 40, 'sessionCookieName' => $name, 'sessionCookieOptions' => array());
     if ($prefix !== null) {
         $params['sessionCookieOptions']['prefix'] = $prefix;
     }
     if (!$this->config) {
         $this->config = new \HashConfig(array('CookiePrefix' => 'wgCookiePrefix', 'EnableBotPasswords' => true, 'BotPasswordsDatabase' => false, 'SessionProviders' => $wgSessionProviders + array('MediaWiki\\Session\\BotPasswordSessionProvider' => array('class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => array($params)))));
     }
     $manager = new SessionManager(array('config' => new \MultiConfig(array($this->config, \RequestContext::getMain()->getConfig())), 'logger' => new \Psr\Log\NullLogger(), 'store' => new TestBagOStuff()));
     return $manager->getProvider('MediaWiki\\Session\\BotPasswordSessionProvider');
 }
 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);
 }
Exemple #4
0
 public function provideSessionInfo(WebRequest $request)
 {
     $info = array('id' => $this->getCookie($request, $this->params['sessionName'], ''));
     if (!SessionManager::validateSessionId($info['id'])) {
         unset($info['id']);
     }
     list($userId, $userName, $token) = $this->getUserInfoFromCookies($request);
     if ($userId !== null) {
         try {
             $userInfo = UserInfo::newFromId($userId);
         } catch (\InvalidArgumentException $ex) {
             return null;
         }
         // Sanity check
         if ($userName !== null && $userInfo->getName() !== $userName) {
             return null;
         }
         if ($token !== null) {
             if (!hash_equals($userInfo->getToken(), $token)) {
                 return null;
             }
             $info['userInfo'] = $userInfo->verified();
         } elseif (isset($info['id'])) {
             // No point if no session ID
             $info['userInfo'] = $userInfo;
         }
     }
     if (!$info) {
         return null;
     }
     $info += array('provider' => $this, 'persisted' => isset($info['id']), 'forceHTTPS' => $this->getCookie($request, 'forceHTTPS', '', false));
     return new SessionInfo($this->priority, $info);
 }
 /**
  * Get the session ID from the cookie, if any.
  *
  * Only call this if $this->sessionCookieName !== null. If
  * sessionCookieName is null, do some logic (probably involving a call to
  * $this->hashToSessionId()) to create the single session ID corresponding
  * to this WebRequest instead of calling this method.
  *
  * @param WebRequest $request
  * @return string|null
  */
 protected function getSessionIdFromCookie(WebRequest $request)
 {
     if ($this->sessionCookieName === null) {
         throw new \BadMethodCallException(__METHOD__ . ' may not be called when $this->sessionCookieName === null');
     }
     $prefix = isset($this->sessionCookieOptions['prefix']) ? $this->sessionCookieOptions['prefix'] : $this->config->get('CookiePrefix');
     $id = $request->getCookie($this->sessionCookieName, $prefix);
     return SessionManager::validateSessionId($id) ? $id : null;
 }
Exemple #6
0
 /**
  * Destroy a session
  * @private For internal use only
  * @param string $id Session id
  * @return bool Success
  */
 public function destroy($id)
 {
     if (self::$instance !== $this) {
         throw new \UnexpectedValueException(__METHOD__ . ': Wrong instance called!');
     }
     if (!$this->enable) {
         throw new \BadMethodCallException('Attempt to use PHP session management');
     }
     $session = $this->manager->getSessionById($id, false);
     if ($session) {
         $session->clear();
     }
     return true;
 }
 public function provideSessionInfo(WebRequest $request)
 {
     $sessionId = $this->getCookie($request, $this->params['sessionName'], '');
     $info = ['provider' => $this, 'forceHTTPS' => $this->getCookie($request, 'forceHTTPS', '', false)];
     if (SessionManager::validateSessionId($sessionId)) {
         $info['id'] = $sessionId;
         $info['persisted'] = true;
     }
     list($userId, $userName, $token) = $this->getUserInfoFromCookies($request);
     if ($userId !== null) {
         try {
             $userInfo = UserInfo::newFromId($userId);
         } catch (\InvalidArgumentException $ex) {
             return null;
         }
         // Sanity check
         if ($userName !== null && $userInfo->getName() !== $userName) {
             $this->logger->warning('Session "{session}" requested with mismatched UserID and UserName cookies.', ['session' => $sessionId, 'mismatch' => ['userid' => $userId, 'cookie_username' => $userName, 'username' => $userInfo->getName()]]);
             return null;
         }
         if ($token !== null) {
             if (!hash_equals($userInfo->getToken(), $token)) {
                 $this->logger->warning('Session "{session}" requested with invalid Token cookie.', ['session' => $sessionId, 'userid' => $userId, 'username' => $userInfo->getName()]);
                 return null;
             }
             $info['userInfo'] = $userInfo->verified();
             $info['persisted'] = true;
             // If we have user+token, it should be
         } elseif (isset($info['id'])) {
             $info['userInfo'] = $userInfo;
         } else {
             // No point in returning, loadSessionInfoFromStore() will
             // reject it anyway.
             return null;
         }
     } elseif (isset($info['id'])) {
         // No UserID cookie, so insist that the session is anonymous.
         // Note: this event occurs for several normal activities:
         // * anon visits Special:UserLogin
         // * anon browsing after seeing Special:UserLogin
         // * anon browsing after edit or preview
         $this->logger->debug('Session "{session}" requested without UserID cookie', ['session' => $info['id']]);
         $info['userInfo'] = UserInfo::newAnonymous();
     } else {
         // No session ID and no user is the same as an empty session, so
         // there's no point.
         return null;
     }
     return new SessionInfo($this->priority, $info);
 }
 public function provideSessionInfo(WebRequest $request)
 {
     $info = array('id' => $this->getCookie($request, $this->params['sessionName'], ''), 'provider' => $this, 'forceHTTPS' => $this->getCookie($request, 'forceHTTPS', '', false));
     if (!SessionManager::validateSessionId($info['id'])) {
         unset($info['id']);
     }
     $info['persisted'] = isset($info['id']);
     list($userId, $userName, $token) = $this->getUserInfoFromCookies($request);
     if ($userId !== null) {
         try {
             $userInfo = UserInfo::newFromId($userId);
         } catch (\InvalidArgumentException $ex) {
             return null;
         }
         // Sanity check
         if ($userName !== null && $userInfo->getName() !== $userName) {
             return null;
         }
         if ($token !== null) {
             if (!hash_equals($userInfo->getToken(), $token)) {
                 return null;
             }
             $info['userInfo'] = $userInfo->verified();
         } elseif (isset($info['id'])) {
             $info['userInfo'] = $userInfo;
         } else {
             // No point in returning, loadSessionInfoFromStore() will
             // reject it anyway.
             return null;
         }
     } elseif (isset($info['id'])) {
         // No UserID cookie, so insist that the session is anonymous.
         $info['userInfo'] = UserInfo::newAnonymous();
     } else {
         // No session ID and no user is the same as an empty session, so
         // there's no point.
         return null;
     }
     return new SessionInfo($this->priority, $info);
 }
Exemple #9
0
 /**
  * @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();
         }
     }
 }
 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();
     }
 }
 static function setupSession($sessionId = false)
 {
     SessionManager::getGlobalSession()->persist();
 }
Exemple #13
0
/**
 * 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 ($sessionId) {
        session_id($sessionId);
    }
    $session = SessionManager::getGlobalSession();
    $session->persist();
    if (session_id() !== $session->getId()) {
        session_id($session->getId());
    }
    MediaWiki\quietCall('session_start');
}
 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'));
 }
 public function testAutoCreateUser()
 {
     global $wgGroupPermissions;
     $that = $this;
     \ObjectCache::$instances[__METHOD__] = new \HashBagOStuff();
     $this->setMwGlobals(array('wgMainCacheType' => __METHOD__));
     $this->stashMwGlobals(array('wgGroupPermissions'));
     $wgGroupPermissions['*']['createaccount'] = true;
     $wgGroupPermissions['*']['autocreateaccount'] = false;
     // Replace the global singleton with one configured for testing
     $manager = $this->getManager();
     $reset = TestUtils::setSessionManagerSingleton($manager);
     $logger = new \TestLogger(true, function ($m) {
         if (substr($m, 0, 15) === 'SessionBackend ') {
             // Don't care.
             return null;
         }
         $m = str_replace('MediaWiki\\Session\\SessionManager::autoCreateUser: '******'', $m);
         $m = preg_replace('/ - from: .*$/', ' - from: XXX', $m);
         return $m;
     });
     $manager->setLogger($logger);
     $session = SessionManager::getGlobalSession();
     // Can't create an already-existing user
     $user = User::newFromName('UTSysop');
     $id = $user->getId();
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame($id, $user->getId());
     $this->assertSame('UTSysop', $user->getName());
     $this->assertSame(array(), $logger->getBuffer());
     $logger->clearBuffer();
     // Sanity check that creation works at all
     $user = User::newFromName('UTSessionAutoCreate1');
     $this->assertSame(0, $user->getId(), 'sanity check');
     $this->assertTrue($manager->autoCreateUser($user));
     $this->assertNotEquals(0, $user->getId());
     $this->assertSame('UTSessionAutoCreate1', $user->getName());
     $this->assertEquals($user->getId(), User::idFromName('UTSessionAutoCreate1', User::READ_LATEST));
     $this->assertSame(array(array(LogLevel::INFO, 'creating new user (UTSessionAutoCreate1) - from: XXX')), $logger->getBuffer());
     $logger->clearBuffer();
     // Check lack of permissions
     $wgGroupPermissions['*']['createaccount'] = false;
     $wgGroupPermissions['*']['autocreateaccount'] = false;
     $user = User::newFromName('UTDoesNotExist');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'user is blocked from this wiki, blacklisting')), $logger->getBuffer());
     $logger->clearBuffer();
     // Check other permission
     $wgGroupPermissions['*']['createaccount'] = false;
     $wgGroupPermissions['*']['autocreateaccount'] = true;
     $user = User::newFromName('UTSessionAutoCreate2');
     $this->assertSame(0, $user->getId(), 'sanity check');
     $this->assertTrue($manager->autoCreateUser($user));
     $this->assertNotEquals(0, $user->getId());
     $this->assertSame('UTSessionAutoCreate2', $user->getName());
     $this->assertEquals($user->getId(), User::idFromName('UTSessionAutoCreate2', User::READ_LATEST));
     $this->assertSame(array(array(LogLevel::INFO, 'creating new user (UTSessionAutoCreate2) - from: XXX')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test account-creation block
     $anon = new User();
     $block = new \Block(array('address' => $anon->getName(), 'user' => $id, 'reason' => __METHOD__, 'expiry' => time() + 100500, 'createAccount' => true));
     $block->insert();
     $this->assertInstanceOf('Block', $anon->isBlockedFromCreateAccount(), 'sanity check');
     $reset2 = new \ScopedCallback(array($block, 'delete'));
     $user = User::newFromName('UTDoesNotExist');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     \ScopedCallback::consume($reset2);
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'user is blocked from this wiki, blacklisting')), $logger->getBuffer());
     $logger->clearBuffer();
     // Sanity check that creation still works
     $user = User::newFromName('UTSessionAutoCreate3');
     $this->assertSame(0, $user->getId(), 'sanity check');
     $this->assertTrue($manager->autoCreateUser($user));
     $this->assertNotEquals(0, $user->getId());
     $this->assertSame('UTSessionAutoCreate3', $user->getName());
     $this->assertEquals($user->getId(), User::idFromName('UTSessionAutoCreate3', User::READ_LATEST));
     $this->assertSame(array(array(LogLevel::INFO, 'creating new user (UTSessionAutoCreate3) - from: XXX')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test prevention by AuthPlugin
     global $wgAuth;
     $oldWgAuth = $wgAuth;
     $mockWgAuth = $this->getMock('AuthPlugin', array('autoCreate'));
     $mockWgAuth->expects($this->once())->method('autoCreate')->will($this->returnValue(false));
     $this->setMwGlobals(array('wgAuth' => $mockWgAuth));
     $user = User::newFromName('UTDoesNotExist');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $this->setMwGlobals(array('wgAuth' => $oldWgAuth));
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'denied by AuthPlugin')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test prevention by wfReadOnly()
     $this->setMwGlobals(array('wgReadOnly' => 'Because'));
     $user = User::newFromName('UTDoesNotExist');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $this->setMwGlobals(array('wgReadOnly' => false));
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'denied by wfReadOnly()')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test prevention by a previous session
     $session->set('MWSession::AutoCreateBlacklist', 'test');
     $user = User::newFromName('UTDoesNotExist');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'blacklisted in session (test)')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test uncreatable name
     $user = User::newFromName('UTDoesNotExist@');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist@', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'Invalid username, blacklisting')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test AbortAutoAccount hook
     $mock = $this->getMock(__CLASS__, array('onAbortAutoAccount'));
     $mock->expects($this->once())->method('onAbortAutoAccount')->will($this->returnCallback(function (User $user, &$msg) {
         $msg = 'No way!';
         return false;
     }));
     $this->mergeMwGlobalArrayValue('wgHooks', array('AbortAutoAccount' => array($mock)));
     $user = User::newFromName('UTDoesNotExist');
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $this->mergeMwGlobalArrayValue('wgHooks', array('AbortAutoAccount' => array()));
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'denied by hook: No way!')), $logger->getBuffer());
     $logger->clearBuffer();
     // Test AbortAutoAccount hook screwing up the name
     $mock = $this->getMock('stdClass', array('onAbortAutoAccount'));
     $mock->expects($this->once())->method('onAbortAutoAccount')->will($this->returnCallback(function (User $user) {
         $user->setName('UTDoesNotExistEither');
     }));
     $this->mergeMwGlobalArrayValue('wgHooks', array('AbortAutoAccount' => array($mock)));
     try {
         $user = User::newFromName('UTDoesNotExist');
         $manager->autoCreateUser($user);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('AbortAutoAccount hook tried to change the user name', $ex->getMessage());
     }
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertNotSame('UTDoesNotExistEither', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $this->assertEquals(0, User::idFromName('UTDoesNotExistEither', User::READ_LATEST));
     $this->mergeMwGlobalArrayValue('wgHooks', array('AbortAutoAccount' => array()));
     $session->clear();
     $this->assertSame(array(), $logger->getBuffer());
     $logger->clearBuffer();
     // Test for "exception backoff"
     $user = User::newFromName('UTDoesNotExist');
     $cache = \ObjectCache::getLocalClusterInstance();
     $backoffKey = wfMemcKey('MWSession', 'autocreate-failed', md5($user->getName()));
     $cache->set($backoffKey, 1, 60 * 10);
     $this->assertFalse($manager->autoCreateUser($user));
     $this->assertSame(0, $user->getId());
     $this->assertNotSame('UTDoesNotExist', $user->getName());
     $this->assertEquals(0, User::idFromName('UTDoesNotExist', User::READ_LATEST));
     $cache->delete($backoffKey);
     $session->clear();
     $this->assertSame(array(array(LogLevel::DEBUG, 'denied by prior creation attempt failures')), $logger->getBuffer());
     $logger->clearBuffer();
     // Sanity check that creation still works, and test completion hook
     $cb = $this->callback(function (User $user) use($that) {
         $that->assertNotEquals(0, $user->getId());
         $that->assertSame('UTSessionAutoCreate4', $user->getName());
         $that->assertEquals($user->getId(), User::idFromName('UTSessionAutoCreate4', User::READ_LATEST));
         return true;
     });
     $mock = $this->getMock('stdClass', array('onAuthPluginAutoCreate', 'onLocalUserCreated'));
     $mock->expects($this->once())->method('onAuthPluginAutoCreate')->with($cb);
     $mock->expects($this->once())->method('onLocalUserCreated')->with($cb, $this->identicalTo(true));
     $this->mergeMwGlobalArrayValue('wgHooks', array('AuthPluginAutoCreate' => array($mock), 'LocalUserCreated' => array($mock)));
     $user = User::newFromName('UTSessionAutoCreate4');
     $this->assertSame(0, $user->getId(), 'sanity check');
     $this->assertTrue($manager->autoCreateUser($user));
     $this->assertNotEquals(0, $user->getId());
     $this->assertSame('UTSessionAutoCreate4', $user->getName());
     $this->assertEquals($user->getId(), User::idFromName('UTSessionAutoCreate4', User::READ_LATEST));
     $this->mergeMwGlobalArrayValue('wgHooks', array('AuthPluginAutoCreate' => array(), 'LocalUserCreated' => array()));
     $this->assertSame(array(array(LogLevel::INFO, 'creating new user (UTSessionAutoCreate4) - from: XXX')), $logger->getBuffer());
     $logger->clearBuffer();
 }
 /**
  * This should kill the session as hard as possible.
  * It will leave the cookie behind, but everything it could possibly
  * reference will be gone.
  */
 public function session_killAllEverything()
 {
     if ($this->isBatchProcessor()) {
         return;
     }
     SessionManager::getGlobalSession()->clear();
 }
Exemple #17
0
 /**
  * @param int $priority Session priority
  * @param array $data
  *  - provider: (SessionProvider|null) If not given, the provider will be
  *    determined from the saved session data.
  *  - id: (string|null) Session ID
  *  - userInfo: (UserInfo|null) User known from the request. If
  *    $provider->canChangeUser() is false, a verified user
  *    must be provided.
  *  - persisted: (bool) Whether this session was persisted
  *  - remembered: (bool) Whether the verified user was remembered.
  *    Defaults to true.
  *  - forceHTTPS: (bool) Whether to force HTTPS for this session
  *  - metadata: (array) Provider metadata, to be returned by
  *    Session::getProviderMetadata().
  *  - idIsSafe: (bool) Set true if the 'id' did not come from the user.
  *    Generally you'll use this from SessionProvider::newEmptySession(),
  *    and not from any other method.
  *  - copyFrom: (SessionInfo) SessionInfo to copy other data items from.
  */
 public function __construct($priority, array $data)
 {
     if ($priority < self::MIN_PRIORITY || $priority > self::MAX_PRIORITY) {
         throw new \InvalidArgumentException('Invalid priority');
     }
     if (isset($data['copyFrom'])) {
         $from = $data['copyFrom'];
         if (!$from instanceof SessionInfo) {
             throw new \InvalidArgumentException('Invalid copyFrom');
         }
         $data += array('provider' => $from->provider, 'id' => $from->id, 'userInfo' => $from->userInfo, 'persisted' => $from->persisted, 'remembered' => $from->remembered, 'forceHTTPS' => $from->forceHTTPS, 'metadata' => $from->providerMetadata, 'idIsSafe' => $from->idIsSafe);
         // @codeCoverageIgnoreEnd
     } else {
         $data += array('provider' => null, 'id' => null, 'userInfo' => null, 'persisted' => false, 'remembered' => true, 'forceHTTPS' => false, 'metadata' => null, 'idIsSafe' => false);
         // @codeCoverageIgnoreEnd
     }
     if ($data['id'] !== null && !SessionManager::validateSessionId($data['id'])) {
         throw new \InvalidArgumentException('Invalid session ID');
     }
     if ($data['userInfo'] !== null && !$data['userInfo'] instanceof UserInfo) {
         throw new \InvalidArgumentException('Invalid userInfo');
     }
     if (!$data['provider'] && $data['id'] === null) {
         throw new \InvalidArgumentException('Must supply an ID when no provider is given');
     }
     if ($data['metadata'] !== null && !is_array($data['metadata'])) {
         throw new \InvalidArgumentException('Invalid metadata');
     }
     $this->provider = $data['provider'];
     if ($data['id'] !== null) {
         $this->id = $data['id'];
         $this->idIsSafe = $data['idIsSafe'];
     } else {
         $this->id = $this->provider->getManager()->generateSessionId();
         $this->idIsSafe = true;
     }
     $this->priority = (int) $priority;
     $this->userInfo = $data['userInfo'];
     $this->persisted = (bool) $data['persisted'];
     if ($data['provider'] !== null) {
         if ($this->userInfo !== null && !$this->userInfo->isAnon() && $this->userInfo->isVerified()) {
             $this->remembered = (bool) $data['remembered'];
         }
         $this->providerMetadata = $data['metadata'];
     }
     $this->forceHTTPS = (bool) $data['forceHTTPS'];
 }
Exemple #18
0
 /**
  * Check if all users may be assumed to have the given permission
  *
  * We generally assume so if the right is granted to '*' and isn't revoked
  * on any group. It doesn't attempt to take grants or other extension
  * limitations on rights into account in the general case, though, as that
  * would require it to always return false and defeat the purpose.
  * Specifically, session-based rights restrictions (such as OAuth or bot
  * passwords) are applied based on the current session.
  *
  * @since 1.22
  * @param string $right Right to check
  * @return bool
  */
 public static function isEveryoneAllowed($right)
 {
     global $wgGroupPermissions, $wgRevokePermissions;
     static $cache = array();
     // Use the cached results, except in unit tests which rely on
     // being able change the permission mid-request
     if (isset($cache[$right]) && !defined('MW_PHPUNIT_TEST')) {
         return $cache[$right];
     }
     if (!isset($wgGroupPermissions['*'][$right]) || !$wgGroupPermissions['*'][$right]) {
         $cache[$right] = false;
         return false;
     }
     // If it's revoked anywhere, then everyone doesn't have it
     foreach ($wgRevokePermissions as $rights) {
         if (isset($rights[$right]) && $rights[$right]) {
             $cache[$right] = false;
             return false;
         }
     }
     // Remove any rights that aren't allowed to the global-session user
     $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
     if ($allowedRights !== null && !in_array($right, $allowedRights, true)) {
         $cache[$right] = false;
         return false;
     }
     // Allow extensions to say false
     if (!Hooks::run('UserIsEveryoneAllowed', array($right))) {
         $cache[$right] = false;
         return false;
     }
     $cache[$right] = true;
     return true;
 }
 /**
  * @param string|null $subPage
  */
 public function execute($subPage)
 {
     $authManager = AuthManager::singleton();
     $session = SessionManager::getGlobalSession();
     // Session data is used for various things in the authentication process, so we must make
     // sure a session cookie or some equivalent mechanism is set.
     $session->persist();
     $this->load($subPage);
     $this->setHeaders();
     $this->checkPermissions();
     // Make sure it's possible to log in
     if (!$this->isSignup() && !$session->canSetUser()) {
         throw new ErrorPageError('cannotloginnow-title', 'cannotloginnow-text', [$session->getProvider()->describe(RequestContext::getMain()->getLanguage())]);
     }
     /*
      * In the case where the user is already logged in, and was redirected to
      * the login form from a page that requires login, do not show the login
      * page. The use case scenario for this is when a user opens a large number
      * of tabs, is redirected to the login page on all of them, and then logs
      * in on one, expecting all the others to work properly.
      *
      * However, do show the form if it was visited intentionally (no 'returnto'
      * is present). People who often switch between several accounts have grown
      * accustomed to this behavior.
      *
      * Also make an exception when force=<level> is set in the URL, which means the user must
      * reauthenticate for security reasons.
      */
     if (!$this->isSignup() && !$this->mPosted && !$this->securityLevel && ($this->mReturnTo !== '' || $this->mReturnToQuery !== '') && $this->getUser()->isLoggedIn()) {
         $this->successfulAction();
     }
     // If logging in and not on HTTPS, either redirect to it or offer a link.
     global $wgSecureLogin;
     if ($this->getRequest()->getProtocol() !== 'https') {
         $title = $this->getFullTitle();
         $query = $this->getPreservedParams(false) + ['title' => null, $this->mEntryErrorType === 'error' ? 'error' : 'warning' => $this->mEntryError] + $this->getRequest()->getQueryValues();
         $url = $title->getFullURL($query, false, PROTO_HTTPS);
         if ($wgSecureLogin && !$this->mFromHTTP && wfCanIPUseHTTPS($this->getRequest()->getIP())) {
             // Avoid infinite redirect
             $url = wfAppendQuery($url, 'fromhttp=1');
             $this->getOutput()->redirect($url);
             // Since we only do this redir to change proto, always vary
             $this->getOutput()->addVaryHeader('X-Forwarded-Proto');
             return;
         } else {
             // A wiki without HTTPS login support should set $wgServer to
             // http://somehost, in which case the secure URL generated
             // above won't actually start with https://
             if (substr($url, 0, 8) === 'https://') {
                 $this->mSecureLoginUrl = $url;
             }
         }
     }
     if (!$this->isActionAllowed($this->authAction)) {
         // FIXME how do we explain this to the user? can we handle session loss better?
         // messages used: authpage-cannot-login, authpage-cannot-login-continue,
         // authpage-cannot-create, authpage-cannot-create-continue
         $this->mainLoginForm([], 'authpage-cannot-' . $this->authAction);
         return;
     }
     $status = $this->trySubmit();
     if (!$status || !$status->isGood()) {
         $this->mainLoginForm($this->authRequests, $status ? $status->getMessage() : '', 'error');
         return;
     }
     /** @var AuthenticationResponse $response */
     $response = $status->getValue();
     $returnToUrl = $this->getPageTitle('return')->getFullURL($this->getPreservedParams(true), false, PROTO_HTTPS);
     switch ($response->status) {
         case AuthenticationResponse::PASS:
             $this->logAuthResult(true);
             $this->proxyAccountCreation = $this->isSignup() && !$this->getUser()->isAnon();
             $this->targetUser = User::newFromName($response->username);
             if (!$this->proxyAccountCreation && $response->loginRequest && $authManager->canAuthenticateNow()) {
                 // successful registration; log the user in instantly
                 $response2 = $authManager->beginAuthentication([$response->loginRequest], $returnToUrl);
                 if ($response2->status !== AuthenticationResponse::PASS) {
                     LoggerFactory::getInstance('login')->error('Could not log in after account creation');
                     $this->successfulAction(true, Status::newFatal('createacct-loginerror'));
                     break;
                 }
             }
             if (!$this->proxyAccountCreation) {
                 // Ensure that the context user is the same as the session user.
                 $this->setSessionUserForCurrentRequest();
             }
             $this->successfulAction(true);
             break;
         case AuthenticationResponse::FAIL:
             // fall through
         // fall through
         case AuthenticationResponse::RESTART:
             unset($this->authForm);
             if ($response->status === AuthenticationResponse::FAIL) {
                 $action = $this->getDefaultAction($subPage);
                 $messageType = 'error';
             } else {
                 $action = $this->getContinueAction($this->authAction);
                 $messageType = 'warning';
             }
             $this->logAuthResult(false, $response->message ? $response->message->getKey() : '-');
             $this->loadAuth($subPage, $action, true);
             $this->mainLoginForm($this->authRequests, $response->message, $messageType);
             break;
         case AuthenticationResponse::REDIRECT:
             unset($this->authForm);
             $this->getOutput()->redirect($response->redirectTarget);
             break;
         case AuthenticationResponse::UI:
             unset($this->authForm);
             $this->authAction = $this->isSignup() ? AuthManager::ACTION_CREATE_CONTINUE : AuthManager::ACTION_LOGIN_CONTINUE;
             $this->authRequests = $response->neededRequests;
             $this->mainLoginForm($response->neededRequests, $response->message, 'warning');
             break;
         default:
             throw new LogicException('invalid AuthenticationResponse');
     }
 }
 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'));
 }
 /**
  * Renew the user's session id, using strong entropy
  */
 private function renewSessionId()
 {
     global $wgSecureLogin, $wgCookieSecure;
     if ($wgSecureLogin && !$this->mStickHTTPS) {
         $wgCookieSecure = false;
     }
     SessionManager::getGlobalSession()->resetId();
 }
 /**
  * For backwards compatibility, open the PHP session when the global
  * session is persisted
  */
 private function checkPHPSession()
 {
     if (!$this->checkPHPSessionRecursionGuard) {
         $this->checkPHPSessionRecursionGuard = true;
         $reset = new \ScopedCallback(function () {
             $this->checkPHPSessionRecursionGuard = false;
         });
         if ($this->usePhpSessionHandling && session_id() === '' && PHPSessionHandler::isEnabled() && SessionManager::getGlobalSession()->getId() === (string) $this->id) {
             $this->logger->debug('SessionBackend "{session}" Taking over PHP session', ['session' => $this->id]);
             session_id((string) $this->id);
             \MediaWiki\quietCall('session_start');
         }
     }
 }
 /**
  * For backwards compatibility, open the PHP session when the global
  * session is persisted
  */
 private function checkPHPSession()
 {
     if (!$this->checkPHPSessionRecursionGuard) {
         $this->checkPHPSessionRecursionGuard = true;
         $ref =& $this->checkPHPSessionRecursionGuard;
         $reset = new \ScopedCallback(function () use(&$ref) {
             $ref = false;
         });
         if ($this->usePhpSessionHandling && session_id() === '' && PHPSessionHandler::isEnabled() && SessionManager::getGlobalSession()->getId() === (string) $this->id) {
             $this->logger->debug("SessionBackend {$this->id}: Taking over PHP session");
             session_id((string) $this->id);
             \MediaWiki\quietCall('session_cache_limiter', 'private, must-revalidate');
             \MediaWiki\quietCall('session_start');
         }
     }
 }
Exemple #24
0
 /**
  * @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());
     }
 }
Exemple #25
0
 /**
  * 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;
 }
/**
 * 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');
}
Exemple #27
0
 /**
  * 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;
 }
 public function testGenerateSessionId()
 {
     $manager = $this->getManager();
     $id = $manager->generateSessionId();
     $this->assertTrue(SessionManager::validateSessionId($id), "Generated ID: {$id}");
 }
 /**
  * Send cache control HTTP headers
  */
 public function sendCacheControl()
 {
     $response = $this->getRequest()->response();
     $config = $this->getConfig();
     if ($config->get('UseETag') && $this->mETag) {
         $response->header("ETag: {$this->mETag}");
     }
     $this->addVaryHeader('Cookie');
     $this->addAcceptLanguage();
     # don't serve compressed data to clients who can't handle it
     # maintain different caches for logged-in users and non-logged in ones
     $response->header($this->getVaryHeader());
     if ($config->get('UseKeyHeader')) {
         $response->header($this->getKeyHeader());
     }
     if ($this->mEnableClientCache) {
         if ($config->get('UseSquid') && !SessionManager::getGlobalSession()->isPersistent() && !$this->isPrintable() && $this->mCdnMaxage != 0 && !$this->haveCacheVaryCookies()) {
             if ($config->get('UseESI')) {
                 # We'll purge the proxy cache explicitly, but require end user agents
                 # to revalidate against the proxy on each visit.
                 # Surrogate-Control controls our CDN, Cache-Control downstream caches
                 wfDebug(__METHOD__ . ": proxy caching with ESI; {$this->mLastModified} **", 'private');
                 # start with a shorter timeout for initial testing
                 # header( 'Surrogate-Control: max-age=2678400+2678400, content="ESI/1.0"');
                 $response->header('Surrogate-Control: max-age=' . $config->get('SquidMaxage') . '+' . $this->mCdnMaxage . ', content="ESI/1.0"');
                 $response->header('Cache-Control: s-maxage=0, must-revalidate, max-age=0');
             } else {
                 # We'll purge the proxy cache for anons explicitly, but require end user agents
                 # to revalidate against the proxy on each visit.
                 # IMPORTANT! The CDN needs to replace the Cache-Control header with
                 # Cache-Control: s-maxage=0, must-revalidate, max-age=0
                 wfDebug(__METHOD__ . ": local proxy caching; {$this->mLastModified} **", 'private');
                 # start with a shorter timeout for initial testing
                 # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" );
                 $response->header('Cache-Control: s-maxage=' . $this->mCdnMaxage . ', must-revalidate, max-age=0');
             }
         } else {
             # We do want clients to cache if they can, but they *must* check for updates
             # on revisiting the page.
             wfDebug(__METHOD__ . ": private caching; {$this->mLastModified} **", 'private');
             $response->header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT');
             $response->header("Cache-Control: private, must-revalidate, max-age=0");
         }
         if ($this->mLastModified) {
             $response->header("Last-Modified: {$this->mLastModified}");
         }
     } else {
         wfDebug(__METHOD__ . ": no caching **", 'private');
         # In general, the absence of a last modified header should be enough to prevent
         # the client from using its cache. We send a few other things just to make sure.
         $response->header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . ' GMT');
         $response->header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
         $response->header('Pragma: no-cache');
     }
 }
 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();
 }