/**
  * @static
  * @param $server IRestServer
  * @param $userSession WebServiceUserSession
  * @return AuthenticationResponse
  */
 public static function Success(IRestServer $server, $userSession)
 {
     $response = new AuthenticationResponse($server);
     $response->sessionToken = $userSession->SessionToken;
     $response->sessionExpires = $userSession->SessionExpiration;
     $response->isAuthenticated = true;
     $response->userId = $userSession->UserId;
     $response->AddService($server, WebServices::Logout);
     //$response->AddService($server, WebServices::MyBookings, array($userSession->PublicId));
     //$response->AddService($server, WebServices::AllBookings);
     //		$response->AddAction(RestAction::MyBookings());
     //		$response->AddAction(RestAction::CreateBooking());
     return $response;
 }
 public function testAbstractPrimaryAuthenticationProvider()
 {
     $user = \User::newFromName('UTSysop');
     $provider = $this->getMockForAbstractClass(AbstractPrimaryAuthenticationProvider::class);
     try {
         $provider->continuePrimaryAuthentication([]);
         $this->fail('Expected exception not thrown');
     } catch (\BadMethodCallException $ex) {
     }
     try {
         $provider->continuePrimaryAccountCreation($user, $user, []);
         $this->fail('Expected exception not thrown');
     } catch (\BadMethodCallException $ex) {
     }
     $req = $this->getMockForAbstractClass(AuthenticationRequest::class);
     $this->assertTrue($provider->providerAllowsPropertyChange('foo'));
     $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, []));
     $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, AuthManager::AUTOCREATE_SOURCE_SESSION));
     $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, false));
     $this->assertNull($provider->finishAccountCreation($user, $user, AuthenticationResponse::newPass()));
     $provider->autoCreatedAccount($user, AuthManager::AUTOCREATE_SOURCE_SESSION);
     $res = AuthenticationResponse::newPass();
     $provider->postAuthentication($user, $res);
     $provider->postAccountCreation($user, $user, $res);
     $provider->postAccountLink($user, $res);
     $provider->expects($this->once())->method('testUserExists')->with($this->equalTo('foo'))->will($this->returnValue(true));
     $this->assertTrue($provider->testUserCanAuthenticate('foo'));
 }
 public function testAbstractSecondaryAuthenticationProvider()
 {
     $user = \User::newFromName('UTSysop');
     $provider = $this->getMockForAbstractClass(AbstractSecondaryAuthenticationProvider::class);
     try {
         $provider->continueSecondaryAuthentication($user, []);
         $this->fail('Expected exception not thrown');
     } catch (\BadMethodCallException $ex) {
     }
     try {
         $provider->continueSecondaryAccountCreation($user, $user, []);
         $this->fail('Expected exception not thrown');
     } catch (\BadMethodCallException $ex) {
     }
     $req = $this->getMockForAbstractClass(AuthenticationRequest::class);
     $this->assertTrue($provider->providerAllowsPropertyChange('foo'));
     $this->assertEquals(\StatusValue::newGood('ignored'), $provider->providerAllowsAuthenticationDataChange($req));
     $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, []));
     $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, AuthManager::AUTOCREATE_SOURCE_SESSION));
     $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, false));
     $provider->providerChangeAuthenticationData($req);
     $provider->autoCreatedAccount($user, AuthManager::AUTOCREATE_SOURCE_SESSION);
     $res = AuthenticationResponse::newPass();
     $provider->postAuthentication($user, $res);
     $provider->postAccountCreation($user, $user, $res);
 }
 public function testRestrictsUserIfInvalidCredentials()
 {
     $username = '******';
     $password = '******';
     $request = new AuthenticationRequest($username, $password);
     $this->server->SetRequest($request);
     $this->authentication->expects($this->once())->method('Validate')->with($this->equalTo($username), $this->equalTo($password))->will($this->returnValue(false));
     $this->service->Authenticate($this->server);
     $expectedResponse = AuthenticationResponse::Failed();
     $this->assertEquals($expectedResponse, $this->server->_LastResponse);
 }
 public function testBeginSecondaryAuthentication()
 {
     $unblockedUser = \User::newFromName('UTSysop');
     $blockedUser = $this->getBlockedUser();
     $provider = new CheckBlocksSecondaryAuthenticationProvider(['blockDisablesLogin' => false]);
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginSecondaryAuthentication($unblockedUser, []));
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginSecondaryAuthentication($blockedUser, []));
     $provider = new CheckBlocksSecondaryAuthenticationProvider(['blockDisablesLogin' => true]);
     $this->assertEquals(AuthenticationResponse::newPass(), $provider->beginSecondaryAuthentication($unblockedUser, []));
     $ret = $provider->beginSecondaryAuthentication($blockedUser, []);
     $this->assertEquals(AuthenticationResponse::FAIL, $ret->status);
 }
 public function testAbstractPreAuthenticationProvider()
 {
     $user = \User::newFromName('UTSysop');
     $provider = $this->getMockForAbstractClass(AbstractPreAuthenticationProvider::class);
     $this->assertEquals([], $provider->getAuthenticationRequests(AuthManager::ACTION_LOGIN, []));
     $this->assertEquals(\StatusValue::newGood(), $provider->testForAuthentication([]));
     $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountCreation($user, $user, []));
     $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, AuthManager::AUTOCREATE_SOURCE_SESSION));
     $this->assertEquals(\StatusValue::newGood(), $provider->testUserForCreation($user, false));
     $this->assertEquals(\StatusValue::newGood(), $provider->testForAccountLink($user));
     $res = AuthenticationResponse::newPass();
     $provider->postAuthentication($user, $res);
     $provider->postAccountCreation($user, $user, $res);
     $provider->postAccountLink($user, $res);
 }
 /**
  * @name Authenticate
  * @description Authenticates an existing Booked Scheduler user
  * @request AuthenticationRequest
  * @response AuthenticationResponse
  * @return void
  */
 public function Authenticate()
 {
     /** @var $request AuthenticationRequest */
     $request = $this->server->GetRequest();
     $username = $request->username;
     $password = $request->password;
     Log::Debug('WebService Authenticate for user %s', $username);
     $isValid = $this->authentication->Validate($username, $password);
     if ($isValid) {
         Log::Debug('WebService Authenticate, user %s was authenticated', $username);
         $session = $this->authentication->Login($username);
         Log::Debug('SessionToken=%s', $session->SessionToken);
         $this->server->WriteResponse(AuthenticationResponse::Success($this->server, $session));
     } else {
         Log::Debug('WebService Authenticate, user %s was not authenticated', $username);
         $this->server->WriteResponse(AuthenticationResponse::Failed());
     }
 }
 public function testAccountCreation()
 {
     $user = \User::newFromName('foo');
     $user->setEmail('email');
     $user->setRealName('realname');
     $req = new PasswordAuthenticationRequest();
     $req->action = AuthManager::ACTION_CREATE;
     $reqs = [PasswordAuthenticationRequest::class => $req];
     $plugin = $this->getMock('AuthPlugin');
     $plugin->expects($this->any())->method('domainList')->willReturn([]);
     $plugin->expects($this->any())->method('canCreateAccounts')->will($this->returnValue(false));
     $plugin->expects($this->never())->method('addUser');
     $provider = new AuthPluginPrimaryAuthenticationProvider($plugin);
     try {
         $provider->beginPrimaryAccountCreation($user, $user, []);
         $this->fail('Expected exception was not thrown');
     } catch (\BadMethodCallException $ex) {
         $this->assertSame('Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage());
     }
     $plugin = $this->getMock('AuthPlugin');
     $plugin->expects($this->any())->method('domainList')->willReturn([]);
     $plugin->expects($this->any())->method('canCreateAccounts')->will($this->returnValue(true));
     $plugin->expects($this->never())->method('addUser');
     $provider = new AuthPluginPrimaryAuthenticationProvider($plugin);
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginPrimaryAccountCreation($user, $user, []));
     $req->username = '******';
     $req->password = null;
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginPrimaryAccountCreation($user, $user, $reqs));
     $req->username = null;
     $req->password = '******';
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginPrimaryAccountCreation($user, $user, $reqs));
     $req->username = '******';
     $req->password = '******';
     $plugin = $this->getMock('AuthPlugin');
     $plugin->expects($this->any())->method('domainList')->willReturn([]);
     $plugin->expects($this->any())->method('canCreateAccounts')->will($this->returnValue(true));
     $plugin->expects($this->once())->method('addUser')->with($this->callback(function ($u) {
         return $u instanceof \User && $u->getName() === 'Foo';
     }), $this->equalTo('bar'), $this->equalTo('email'), $this->equalTo('realname'))->will($this->returnValue(true));
     $provider = new AuthPluginPrimaryAuthenticationProvider($plugin);
     $this->assertEquals(AuthenticationResponse::newPass(), $provider->beginPrimaryAccountCreation($user, $user, $reqs));
     $plugin = $this->getMock('AuthPlugin');
     $plugin->expects($this->any())->method('domainList')->willReturn([]);
     $plugin->expects($this->any())->method('canCreateAccounts')->will($this->returnValue(true));
     $plugin->expects($this->once())->method('addUser')->with($this->callback(function ($u) {
         return $u instanceof \User && $u->getName() === 'Foo';
     }), $this->equalTo('bar'), $this->equalTo('email'), $this->equalTo('realname'))->will($this->returnValue(false));
     $provider = new AuthPluginPrimaryAuthenticationProvider($plugin);
     $ret = $provider->beginPrimaryAccountCreation($user, $user, $reqs);
     $this->assertSame(AuthenticationResponse::FAIL, $ret->status);
     $this->assertSame('authmanager-authplugin-create-fail', $ret->message->getKey());
     $plugin = $this->getMock('AuthPlugin');
     $plugin->expects($this->any())->method('canCreateAccounts')->will($this->returnValue(true));
     $plugin->expects($this->any())->method('domainList')->will($this->returnValue(['Domain1', 'Domain2']));
     $plugin->expects($this->any())->method('validDomain')->will($this->returnCallback(function ($domain) {
         return in_array($domain, ['Domain1', 'Domain2']);
     }));
     $plugin->expects($this->once())->method('setDomain')->with($this->equalTo('Domain2'));
     $plugin->expects($this->once())->method('addUser')->with($this->callback(function ($u) {
         return $u instanceof \User && $u->getName() === 'Foo';
     }), $this->equalTo('bar'))->will($this->returnValue(true));
     $provider = new AuthPluginPrimaryAuthenticationProvider($plugin);
     list($req) = $provider->getAuthenticationRequests(AuthManager::ACTION_CREATE, []);
     $req->username = '******';
     $req->password = '******';
     $req->domain = 'Domain2';
     $provider->beginPrimaryAccountCreation($user, $user, [$req]);
 }
 /**
  * Try to reset the password
  * @param \User $user
  * @param AuthenticationRequest[] $reqs
  * @return AuthenticationResponse
  */
 protected function tryReset(\User $user, array $reqs)
 {
     $data = $this->manager->getAuthenticationSessionData('reset-pass');
     if (!$data) {
         return AuthenticationResponse::newAbstain();
     }
     if (is_array($data)) {
         $data = (object) $data;
     }
     if (!is_object($data)) {
         throw new \UnexpectedValueException('reset-pass is not valid');
     }
     if (!isset($data->msg)) {
         throw new \UnexpectedValueException('reset-pass msg is missing');
     } elseif (!$data->msg instanceof \Message) {
         throw new \UnexpectedValueException('reset-pass msg is not valid');
     } elseif (!isset($data->hard)) {
         throw new \UnexpectedValueException('reset-pass hard is missing');
     } elseif (isset($data->req) && (!$data->req instanceof PasswordAuthenticationRequest || !array_key_exists('retype', $data->req->getFieldInfo()))) {
         throw new \UnexpectedValueException('reset-pass req is not valid');
     }
     if (!$data->hard) {
         $req = ButtonAuthenticationRequest::getRequestByName($reqs, 'skipReset');
         if ($req) {
             $this->manager->removeAuthenticationSessionData('reset-pass');
             return AuthenticationResponse::newPass();
         }
     }
     $needReq = isset($data->req) ? $data->req : new PasswordAuthenticationRequest();
     if (!$needReq->action) {
         $needReq->action = AuthManager::ACTION_CHANGE;
     }
     $needReq->required = $data->hard ? AuthenticationRequest::REQUIRED : AuthenticationRequest::OPTIONAL;
     $needReqs = [$needReq];
     if (!$data->hard) {
         $needReqs[] = new ButtonAuthenticationRequest('skipReset', wfMessage('authprovider-resetpass-skip-label'), wfMessage('authprovider-resetpass-skip-help'));
     }
     $req = AuthenticationRequest::getRequestByClass($reqs, get_class($needReq));
     if (!$req || !array_key_exists('retype', $req->getFieldInfo())) {
         return AuthenticationResponse::newUI($needReqs, $data->msg, 'warning');
     }
     if ($req->password !== $req->retype) {
         return AuthenticationResponse::newUI($needReqs, new \Message('badretype'), 'error');
     }
     $req->username = $user->getName();
     $status = $this->manager->allowsAuthenticationDataChange($req);
     if (!$status->isGood()) {
         return AuthenticationResponse::newUI($needReqs, $status->getMessage(), 'error');
     }
     $this->manager->changeAuthenticationData($req);
     $this->manager->removeAuthenticationSessionData('reset-pass');
     return AuthenticationResponse::newPass();
 }
 public function testPostAuthentication()
 {
     $provider = new ThrottlePreAuthenticationProvider(['passwordAttemptThrottle' => [], 'cache' => new \HashBagOStuff()]);
     $provider->setLogger(new \TestLogger());
     $provider->setConfig(new \HashConfig(['AccountCreationThrottle' => null, 'PasswordAttemptThrottle' => null]));
     $provider->setManager(AuthManager::singleton());
     $provider->postAuthentication(\User::newFromName('SomeUser'), AuthenticationResponse::newPass());
     $provider = new ThrottlePreAuthenticationProvider(['passwordAttemptThrottle' => [['count' => 2, 'seconds' => 86400]], 'cache' => new \HashBagOStuff()]);
     $logger = new \TestLogger(true);
     $provider->setLogger($logger);
     $provider->setConfig(new \HashConfig(['AccountCreationThrottle' => null, 'PasswordAttemptThrottle' => null]));
     $provider->setManager(AuthManager::singleton());
     $provider->postAuthentication(\User::newFromName('SomeUser'), AuthenticationResponse::newPass());
     $this->assertSame([[\Psr\Log\LogLevel::ERROR, 'throttler data not found for {user}']], $logger->getBuffer());
 }
 public function testContinueLinkAttempt()
 {
     $user = \User::newFromName('UTSysop');
     $obj = new \stdClass();
     $reqs = $this->getLinkRequests();
     $done = [false, false, false];
     // First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest
     $mock = $this->getMockBuilder(ConfirmLinkSecondaryAuthenticationProvider::class)->setMethods(['beginLinkAttempt'])->getMock();
     $mock->expects($this->once())->method('beginLinkAttempt')->with($this->identicalTo($user), $this->identicalTo('state'))->will($this->returnValue($obj));
     $this->assertSame($obj, \TestingAccessWrapper::newFromObject($mock)->continueLinkAttempt($user, 'state', $reqs));
     // Now test the actual functioning
     $provider = $this->getMockBuilder(ConfirmLinkSecondaryAuthenticationProvider::class)->setMethods(['beginLinkAttempt', 'providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'])->getMock();
     $provider->expects($this->never())->method('beginLinkAttempt');
     $provider->expects($this->any())->method('providerAllowsAuthenticationDataChange')->will($this->returnCallback(function ($req) use($reqs) {
         return $req->getUniqueId() === 'Request3' ? \StatusValue::newFatal('foo') : \StatusValue::newGood();
     }));
     $provider->expects($this->any())->method('providerChangeAuthenticationData')->will($this->returnCallback(function ($req) use(&$done) {
         $done[$req->id] = true;
     }));
     $config = new \HashConfig(['AuthManagerConfig' => ['preauth' => [], 'primaryauth' => [], 'secondaryauth' => [['factory' => function () use($provider) {
         return $provider;
     }]]]]);
     $request = new \FauxRequest();
     $manager = new AuthManager($request, $config);
     $provider->setManager($manager);
     $provider = \TestingAccessWrapper::newFromObject($provider);
     $req = new ConfirmLinkAuthenticationRequest($reqs);
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->continueLinkAttempt($user, 'state', [$req]));
     $request->getSession()->setSecret('state', ['maybeLink' => []]);
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->continueLinkAttempt($user, 'state', [$req]));
     $request->getSession()->setSecret('state', ['maybeLink' => $reqs]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res = $provider->continueLinkAttempt($user, 'state', [$req]));
     $this->assertSame([false, false, false], $done);
     $request->getSession()->setSecret('state', ['maybeLink' => [$reqs['Request2']]]);
     $req->confirmedLinkIDs = ['Request1', 'Request2'];
     $res = $provider->continueLinkAttempt($user, 'state', [$req]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res);
     $this->assertSame([false, true, false], $done);
     $done = [false, false, false];
     $request->getSession()->setSecret('state', ['maybeLink' => $reqs]);
     $req->confirmedLinkIDs = ['Request1', 'Request2'];
     $res = $provider->continueLinkAttempt($user, 'state', [$req]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res);
     $this->assertSame([true, true, false], $done);
     $done = [false, false, false];
     $request->getSession()->setSecret('state', ['maybeLink' => $reqs]);
     $req->confirmedLinkIDs = ['Request1', 'Request3'];
     $res = $provider->continueLinkAttempt($user, 'state', [$req]);
     $this->assertEquals(AuthenticationResponse::UI, $res->status);
     $this->assertCount(1, $res->neededRequests);
     $this->assertInstanceOf(ButtonAuthenticationRequest::class, $res->neededRequests[0]);
     $this->assertSame([true, false, false], $done);
     $done = [false, false, false];
     $res = $provider->continueLinkAttempt($user, 'state', [$res->neededRequests[0]]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res);
     $this->assertSame([false, false, false], $done);
 }
 public function testAccountCreationEmail()
 {
     $creator = \User::newFromName('Foo');
     $user = \User::newFromName('UTSysop');
     $reset = new \ScopedCallback(function ($email) use($user) {
         $user->setEmail($email);
         $user->saveSettings();
     }, [$user->getEmail()]);
     $user->setEmail(null);
     $req = TemporaryPasswordAuthenticationRequest::newRandom();
     $req->username = $user->getName();
     $req->mailpassword = true;
     $provider = $this->getProvider(['emailEnabled' => false]);
     $status = $provider->testForAccountCreation($user, $creator, [$req]);
     $this->assertEquals(\StatusValue::newFatal('emaildisabled'), $status);
     $req->hasBackchannel = true;
     $status = $provider->testForAccountCreation($user, $creator, [$req]);
     $this->assertFalse($status->hasMessage('emaildisabled'));
     $req->hasBackchannel = false;
     $provider = $this->getProvider(['emailEnabled' => true]);
     $status = $provider->testForAccountCreation($user, $creator, [$req]);
     $this->assertEquals(\StatusValue::newFatal('noemailcreate'), $status);
     $req->hasBackchannel = true;
     $status = $provider->testForAccountCreation($user, $creator, [$req]);
     $this->assertFalse($status->hasMessage('noemailcreate'));
     $req->hasBackchannel = false;
     $user->setEmail('*****@*****.**');
     $status = $provider->testForAccountCreation($user, $creator, [$req]);
     $this->assertEquals(\StatusValue::newGood(), $status);
     $mailed = false;
     $resetMailer = $this->hookMailer(function ($headers, $to, $from, $subject, $body) use(&$mailed, $req) {
         $mailed = true;
         $this->assertSame('*****@*****.**', $to[0]->address);
         $this->assertContains($req->password, $body);
         return false;
     });
     $expect = AuthenticationResponse::newPass('UTSysop');
     $expect->createRequest = clone $req;
     $expect->createRequest->username = '******';
     $res = $provider->beginPrimaryAccountCreation($user, $creator, [$req]);
     $this->assertEquals($expect, $res);
     $this->assertTrue($this->manager->getAuthenticationSessionData('no-email'));
     $this->assertFalse($mailed);
     $this->assertSame('byemail', $provider->finishAccountCreation($user, $creator, $res));
     $this->assertTrue($mailed);
     \ScopedCallback::consume($resetMailer);
     $this->assertTrue($mailed);
 }
 public function testAccountCreation()
 {
     $user = \User::newFromName('Foo');
     $req = new PasswordAuthenticationRequest();
     $req->action = AuthManager::ACTION_CREATE;
     $reqs = [PasswordAuthenticationRequest::class => $req];
     $provider = $this->getProvider(true);
     try {
         $provider->beginPrimaryAccountCreation($user, $user, []);
         $this->fail('Expected exception was not thrown');
     } catch (\BadMethodCallException $ex) {
         $this->assertSame('Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage());
     }
     try {
         $provider->finishAccountCreation($user, $user, AuthenticationResponse::newPass());
         $this->fail('Expected exception was not thrown');
     } catch (\BadMethodCallException $ex) {
         $this->assertSame('Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage());
     }
     $provider = $this->getProvider(false);
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginPrimaryAccountCreation($user, $user, []));
     $req->username = '******';
     $req->password = null;
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginPrimaryAccountCreation($user, $user, $reqs));
     $req->username = null;
     $req->password = '******';
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->beginPrimaryAccountCreation($user, $user, $reqs));
     $req->username = '******';
     $req->password = '******';
     $expect = AuthenticationResponse::newPass('Foo');
     $expect->createRequest = clone $req;
     $expect->createRequest->username = '******';
     $this->assertEquals($expect, $provider->beginPrimaryAccountCreation($user, $user, $reqs));
     // We have to cheat a bit to avoid having to add a new user to
     // the database to test the actual setting of the password works right
     $dbw = wfGetDB(DB_MASTER);
     $user = \User::newFromName('UTSysop');
     $req->username = $user->getName();
     $req->password = '******';
     $expect = AuthenticationResponse::newPass('UTSysop');
     $expect->createRequest = $req;
     $res2 = $provider->beginPrimaryAccountCreation($user, $user, $reqs);
     $this->assertEquals($expect, $res2, 'Sanity check');
     $ret = $provider->beginPrimaryAuthentication($reqs);
     $this->assertEquals(AuthenticationResponse::FAIL, $ret->status, 'sanity check');
     $this->assertNull($provider->finishAccountCreation($user, $user, $res2));
     $ret = $provider->beginPrimaryAuthentication($reqs);
     $this->assertEquals(AuthenticationResponse::PASS, $ret->status, 'new password is set');
 }
 public function testTryReset()
 {
     $user = \User::newFromName('UTSysop');
     $provider = $this->getMockBuilder(ResetPasswordSecondaryAuthenticationProvider::class)->setMethods(['providerAllowsAuthenticationDataChange', 'providerChangeAuthenticationData'])->getMock();
     $provider->expects($this->any())->method('providerAllowsAuthenticationDataChange')->will($this->returnCallback(function ($req) {
         $this->assertSame('UTSysop', $req->username);
         return $req->allow;
     }));
     $provider->expects($this->any())->method('providerChangeAuthenticationData')->will($this->returnCallback(function ($req) {
         $this->assertSame('UTSysop', $req->username);
         $req->done = true;
     }));
     $config = new \HashConfig(['AuthManagerConfig' => ['preauth' => [], 'primaryauth' => [], 'secondaryauth' => [['factory' => function () use($provider) {
         return $provider;
     }]]]]);
     $manager = new AuthManager(new \FauxRequest(), $config);
     $provider->setManager($manager);
     $provider = \TestingAccessWrapper::newFromObject($provider);
     $msg = wfMessage('foo');
     $skipReq = new ButtonAuthenticationRequest('skipReset', wfMessage('authprovider-resetpass-skip-label'), wfMessage('authprovider-resetpass-skip-help'));
     $passReq = new PasswordAuthenticationRequest();
     $passReq->action = AuthManager::ACTION_CHANGE;
     $passReq->password = '******';
     $passReq->retype = 'Bar';
     $passReq->allow = \StatusValue::newGood();
     $passReq->done = false;
     $passReq2 = $this->getMockBuilder(PasswordAuthenticationRequest::class)->enableProxyingToOriginalMethods()->getMock();
     $passReq2->action = AuthManager::ACTION_CHANGE;
     $passReq2->password = '******';
     $passReq2->retype = 'Foo';
     $passReq2->allow = \StatusValue::newGood();
     $passReq2->done = false;
     $passReq3 = new PasswordAuthenticationRequest();
     $passReq3->action = AuthManager::ACTION_LOGIN;
     $passReq3->password = '******';
     $passReq3->retype = 'Foo';
     $passReq3->allow = \StatusValue::newGood();
     $passReq3->done = false;
     $this->assertEquals(AuthenticationResponse::newAbstain(), $provider->tryReset($user, []));
     $manager->setAuthenticationSessionData('reset-pass', 'foo');
     try {
         $provider->tryReset($user, []);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('reset-pass is not valid', $ex->getMessage());
     }
     $manager->setAuthenticationSessionData('reset-pass', (object) []);
     try {
         $provider->tryReset($user, []);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('reset-pass msg is missing', $ex->getMessage());
     }
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => 'foo']);
     try {
         $provider->tryReset($user, []);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('reset-pass msg is not valid', $ex->getMessage());
     }
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg]);
     try {
         $provider->tryReset($user, []);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('reset-pass hard is missing', $ex->getMessage());
     }
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => true, 'req' => 'foo']);
     try {
         $provider->tryReset($user, []);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('reset-pass req is not valid', $ex->getMessage());
     }
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => false, 'req' => $passReq3]);
     try {
         $provider->tryReset($user, [$passReq]);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('reset-pass req is not valid', $ex->getMessage());
     }
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => true]);
     $res = $provider->tryReset($user, []);
     $this->assertInstanceOf(AuthenticationResponse::class, $res);
     $this->assertSame(AuthenticationResponse::UI, $res->status);
     $this->assertEquals($msg, $res->message);
     $this->assertCount(1, $res->neededRequests);
     $this->assertInstanceOf(PasswordAuthenticationRequest::class, $res->neededRequests[0]);
     $this->assertNotNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => false, 'req' => $passReq]);
     $res = $provider->tryReset($user, []);
     $this->assertInstanceOf(AuthenticationResponse::class, $res);
     $this->assertSame(AuthenticationResponse::UI, $res->status);
     $this->assertEquals($msg, $res->message);
     $this->assertCount(2, $res->neededRequests);
     $this->assertEquals($passReq, $res->neededRequests[0]);
     $this->assertEquals($skipReq, $res->neededRequests[1]);
     $this->assertNotNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $passReq->retype = 'Bad';
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => false, 'req' => $passReq]);
     $res = $provider->tryReset($user, [$skipReq, $passReq]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res);
     $this->assertNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $passReq->retype = 'Bad';
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => true]);
     $res = $provider->tryReset($user, [$skipReq, $passReq]);
     $this->assertSame(AuthenticationResponse::UI, $res->status);
     $this->assertSame('badretype', $res->message->getKey());
     $this->assertCount(1, $res->neededRequests);
     $this->assertInstanceOf(PasswordAuthenticationRequest::class, $res->neededRequests[0]);
     $this->assertNotNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => true]);
     $res = $provider->tryReset($user, [$skipReq, $passReq3]);
     $this->assertSame(AuthenticationResponse::UI, $res->status);
     $this->assertEquals($msg, $res->message);
     $this->assertCount(1, $res->neededRequests);
     $this->assertInstanceOf(PasswordAuthenticationRequest::class, $res->neededRequests[0]);
     $this->assertNotNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $passReq->retype = $passReq->password;
     $passReq->allow = \StatusValue::newFatal('arbitrary-fail');
     $res = $provider->tryReset($user, [$skipReq, $passReq]);
     $this->assertSame(AuthenticationResponse::UI, $res->status);
     $this->assertSame('arbitrary-fail', $res->message->getKey());
     $this->assertCount(1, $res->neededRequests);
     $this->assertInstanceOf(PasswordAuthenticationRequest::class, $res->neededRequests[0]);
     $this->assertNotNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $passReq->allow = \StatusValue::newGood();
     $res = $provider->tryReset($user, [$skipReq, $passReq]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res);
     $this->assertNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertTrue($passReq->done);
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => false, 'req' => $passReq2]);
     $res = $provider->tryReset($user, [$passReq2]);
     $this->assertEquals(AuthenticationResponse::newPass(), $res);
     $this->assertNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertTrue($passReq2->done);
     $passReq->done = false;
     $passReq2->done = false;
     $manager->setAuthenticationSessionData('reset-pass', ['msg' => $msg, 'hard' => false, 'req' => $passReq2]);
     $res = $provider->tryReset($user, [$passReq]);
     $this->assertInstanceOf(AuthenticationResponse::class, $res);
     $this->assertSame(AuthenticationResponse::UI, $res->status);
     $this->assertEquals($msg, $res->message);
     $this->assertCount(2, $res->neededRequests);
     $this->assertEquals($passReq2, $res->neededRequests[0]);
     $this->assertEquals($skipReq, $res->neededRequests[1]);
     $this->assertNotNull($manager->getAuthenticationSessionData('reset-pass'));
     $this->assertFalse($passReq->done);
     $this->assertFalse($passReq2->done);
 }