public function testBeginAuthentication()
 {
     $this->initializeManager();
     // Immutable session
     list($provider, $reset) = $this->getMockSessionProvider(false);
     $this->hook('UserLoggedIn', $this->never());
     $this->request->getSession()->setSecret('AuthManager::authnState', 'test');
     try {
         $this->manager->beginAuthentication([], 'http://localhost/');
         $this->fail('Expected exception not thrown');
     } catch (\LogicException $ex) {
         $this->assertSame('Authentication is not possible now', $ex->getMessage());
     }
     $this->unhook('UserLoggedIn');
     $this->assertNull($this->request->getSession()->getSecret('AuthManager::authnState'));
     \ScopedCallback::consume($reset);
     $this->initializeManager(true);
     // CreatedAccountAuthenticationRequest
     $user = \User::newFromName('UTSysop');
     $reqs = [new CreatedAccountAuthenticationRequest($user->getId(), $user->getName())];
     $this->hook('UserLoggedIn', $this->never());
     try {
         $this->manager->beginAuthentication($reqs, 'http://localhost/');
         $this->fail('Expected exception not thrown');
     } catch (\LogicException $ex) {
         $this->assertSame('CreatedAccountAuthenticationRequests are only valid on the same AuthManager ' . 'that created the account', $ex->getMessage());
     }
     $this->unhook('UserLoggedIn');
     $this->request->getSession()->clear();
     $this->request->getSession()->setSecret('AuthManager::authnState', 'test');
     $this->managerPriv->createdAccountAuthenticationRequests = [$reqs[0]];
     $this->hook('UserLoggedIn', $this->once())->with($this->callback(function ($u) use($user) {
         return $user->getId() === $u->getId() && $user->getName() === $u->getName();
     }));
     $this->hook('AuthManagerLoginAuthenticateAudit', $this->once());
     $this->logger->setCollect(true);
     $ret = $this->manager->beginAuthentication($reqs, 'http://localhost/');
     $this->logger->setCollect(false);
     $this->unhook('UserLoggedIn');
     $this->unhook('AuthManagerLoginAuthenticateAudit');
     $this->assertSame(AuthenticationResponse::PASS, $ret->status);
     $this->assertSame($user->getName(), $ret->username);
     $this->assertSame($user->getId(), $this->request->getSessionData('AuthManager:lastAuthId'));
     $this->assertEquals(time(), $this->request->getSessionData('AuthManager:lastAuthTimestamp'), 'timestamp ±1', 1);
     $this->assertNull($this->request->getSession()->getSecret('AuthManager::authnState'));
     $this->assertSame($user->getId(), $this->request->getSession()->getUser()->getId());
     $this->assertSame([[LogLevel::INFO, 'Logging in {user} after account creation']], $this->logger->getBuffer());
 }
 /**
  * Internal implementation for self::getEditToken() and
  * self::matchEditToken().
  *
  * @param string|array $salt
  * @param WebRequest $request
  * @param string|int $timestamp
  * @return string
  */
 private function getEditTokenAtTimestamp($salt, $request, $timestamp)
 {
     if ($this->isAnon()) {
         return self::EDIT_TOKEN_SUFFIX;
     } else {
         $token = $request->getSessionData('wsEditToken');
         if ($token === null) {
             $token = MWCryptRand::generateHex(32);
             $request->setSessionData('wsEditToken', $token);
         }
         if (is_array($salt)) {
             $salt = implode('|', $salt);
         }
         return hash_hmac('md5', $timestamp . $salt, $token, false) . dechex($timestamp) . self::EDIT_TOKEN_SUFFIX;
     }
 }