Пример #1
0
 /**
  * @dataProvider provideAccountCreation
  * @param StatusValue $preTest
  * @param StatusValue $primaryTest
  * @param StatusValue $secondaryTest
  * @param array $primaryResponses
  * @param array $secondaryResponses
  * @param array $managerResponses
  */
 public function testAccountCreation(StatusValue $preTest, $primaryTest, $secondaryTest, array $primaryResponses, array $secondaryResponses, array $managerResponses)
 {
     $creator = \User::newFromName('UTSysop');
     $username = self::usernameForCreation();
     $this->initializeManager();
     // Set up lots of mocks...
     $req = $this->getMockForAbstractClass(AuthenticationRequest::class);
     $req->preTest = $preTest;
     $req->primaryTest = $primaryTest;
     $req->secondaryTest = $secondaryTest;
     $req->primary = $primaryResponses;
     $req->secondary = $secondaryResponses;
     $mocks = [];
     foreach (['pre', 'primary', 'secondary'] as $key) {
         $class = ucfirst($key) . 'AuthenticationProvider';
         $mocks[$key] = $this->getMockForAbstractClass("MediaWiki\\Auth\\{$class}", [], "Mock{$class}");
         $mocks[$key]->expects($this->any())->method('getUniqueId')->will($this->returnValue($key));
         $mocks[$key]->expects($this->any())->method('testUserForCreation')->will($this->returnValue(StatusValue::newGood()));
         $mocks[$key]->expects($this->any())->method('testForAccountCreation')->will($this->returnCallback(function ($user, $creatorIn, $reqs) use($username, $creator, $req, $key) {
             $this->assertSame($username, $user->getName());
             $this->assertSame($creator->getId(), $creatorIn->getId());
             $this->assertSame($creator->getName(), $creatorIn->getName());
             $foundReq = false;
             foreach ($reqs as $r) {
                 $this->assertSame($username, $r->username);
                 $foundReq = $foundReq || get_class($r) === get_class($req);
             }
             $this->assertTrue($foundReq, '$reqs contains $req');
             $k = $key . 'Test';
             return $req->{$k};
         }));
         for ($i = 2; $i <= 3; $i++) {
             $mocks[$key . $i] = $this->getMockForAbstractClass("MediaWiki\\Auth\\{$class}", [], "Mock{$class}");
             $mocks[$key . $i]->expects($this->any())->method('getUniqueId')->will($this->returnValue($key . $i));
             $mocks[$key . $i]->expects($this->any())->method('testUserForCreation')->will($this->returnValue(StatusValue::newGood()));
             $mocks[$key . $i]->expects($this->atMost(1))->method('testForAccountCreation')->will($this->returnValue(StatusValue::newGood()));
         }
     }
     $mocks['primary']->expects($this->any())->method('accountCreationType')->will($this->returnValue(PrimaryAuthenticationProvider::TYPE_CREATE));
     $mocks['primary']->expects($this->any())->method('testUserExists')->will($this->returnValue(false));
     $ct = count($req->primary);
     $callback = $this->returnCallback(function ($user, $creator, $reqs) use($username, $req) {
         $this->assertSame($username, $user->getName());
         $this->assertSame('UTSysop', $creator->getName());
         $foundReq = false;
         foreach ($reqs as $r) {
             $this->assertSame($username, $r->username);
             $foundReq = $foundReq || get_class($r) === get_class($req);
         }
         $this->assertTrue($foundReq, '$reqs contains $req');
         return array_shift($req->primary);
     });
     $mocks['primary']->expects($this->exactly(min(1, $ct)))->method('beginPrimaryAccountCreation')->will($callback);
     $mocks['primary']->expects($this->exactly(max(0, $ct - 1)))->method('continuePrimaryAccountCreation')->will($callback);
     $ct = count($req->secondary);
     $callback = $this->returnCallback(function ($user, $creator, $reqs) use($username, $req) {
         $this->assertSame($username, $user->getName());
         $this->assertSame('UTSysop', $creator->getName());
         $foundReq = false;
         foreach ($reqs as $r) {
             $this->assertSame($username, $r->username);
             $foundReq = $foundReq || get_class($r) === get_class($req);
         }
         $this->assertTrue($foundReq, '$reqs contains $req');
         return array_shift($req->secondary);
     });
     $mocks['secondary']->expects($this->exactly(min(1, $ct)))->method('beginSecondaryAccountCreation')->will($callback);
     $mocks['secondary']->expects($this->exactly(max(0, $ct - 1)))->method('continueSecondaryAccountCreation')->will($callback);
     $abstain = AuthenticationResponse::newAbstain();
     $mocks['primary2']->expects($this->any())->method('accountCreationType')->will($this->returnValue(PrimaryAuthenticationProvider::TYPE_LINK));
     $mocks['primary2']->expects($this->any())->method('testUserExists')->will($this->returnValue(false));
     $mocks['primary2']->expects($this->atMost(1))->method('beginPrimaryAccountCreation')->will($this->returnValue($abstain));
     $mocks['primary2']->expects($this->never())->method('continuePrimaryAccountCreation');
     $mocks['primary3']->expects($this->any())->method('accountCreationType')->will($this->returnValue(PrimaryAuthenticationProvider::TYPE_NONE));
     $mocks['primary3']->expects($this->any())->method('testUserExists')->will($this->returnValue(false));
     $mocks['primary3']->expects($this->never())->method('beginPrimaryAccountCreation');
     $mocks['primary3']->expects($this->never())->method('continuePrimaryAccountCreation');
     $mocks['secondary2']->expects($this->atMost(1))->method('beginSecondaryAccountCreation')->will($this->returnValue($abstain));
     $mocks['secondary2']->expects($this->never())->method('continueSecondaryAccountCreation');
     $mocks['secondary3']->expects($this->atMost(1))->method('beginSecondaryAccountCreation')->will($this->returnValue($abstain));
     $mocks['secondary3']->expects($this->never())->method('continueSecondaryAccountCreation');
     $this->preauthMocks = [$mocks['pre'], $mocks['pre2']];
     $this->primaryauthMocks = [$mocks['primary3'], $mocks['primary'], $mocks['primary2']];
     $this->secondaryauthMocks = [$mocks['secondary3'], $mocks['secondary'], $mocks['secondary2']];
     $this->logger = new \TestLogger(true, function ($message, $level) {
         return $level === LogLevel::DEBUG ? null : $message;
     });
     $expectLog = [];
     $this->initializeManager(true);
     $constraint = \PHPUnit_Framework_Assert::logicalOr($this->equalTo(AuthenticationResponse::PASS), $this->equalTo(AuthenticationResponse::FAIL));
     $providers = array_merge($this->preauthMocks, $this->primaryauthMocks, $this->secondaryauthMocks);
     foreach ($providers as $p) {
         $p->postCalled = false;
         $p->expects($this->atMost(1))->method('postAccountCreation')->willReturnCallback(function ($user, $creator, $response) use($constraint, $p, $username) {
             $this->assertInstanceOf('User', $user);
             $this->assertSame($username, $user->getName());
             $this->assertSame('UTSysop', $creator->getName());
             $this->assertInstanceOf(AuthenticationResponse::class, $response);
             $this->assertThat($response->status, $constraint);
             $p->postCalled = $response->status;
         });
     }
     // We're testing with $wgNewUserLog = false, so assert that it worked
     $dbw = wfGetDB(DB_MASTER);
     $maxLogId = $dbw->selectField('logging', 'MAX(log_id)', ['log_type' => 'newusers']);
     $first = true;
     $created = false;
     foreach ($managerResponses as $i => $response) {
         $success = $response instanceof AuthenticationResponse && $response->status === AuthenticationResponse::PASS;
         if ($i === 'created') {
             $created = true;
             $this->hook('LocalUserCreated', $this->once())->with($this->callback(function ($user) use($username) {
                 return $user->getName() === $username;
             }), $this->equalTo(false));
             $expectLog[] = [LogLevel::INFO, "Creating user {user} during account creation"];
         } else {
             $this->hook('LocalUserCreated', $this->never());
         }
         $ex = null;
         try {
             if ($first) {
                 $userReq = new UsernameAuthenticationRequest();
                 $userReq->username = $username;
                 $ret = $this->manager->beginAccountCreation($creator, [$userReq, $req], 'http://localhost/');
             } else {
                 $ret = $this->manager->continueAccountCreation([$req]);
             }
             if ($response instanceof \Exception) {
                 $this->fail('Expected exception not thrown', "Response {$i}");
             }
         } catch (\Exception $ex) {
             if (!$response instanceof \Exception) {
                 throw $ex;
             }
             $this->assertEquals($response->getMessage(), $ex->getMessage(), "Response {$i}, exception");
             $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState'), "Response {$i}, exception, session state");
             $this->unhook('LocalUserCreated');
             return;
         }
         $this->unhook('LocalUserCreated');
         $this->assertSame('http://localhost/', $req->returnToUrl);
         if ($success) {
             $this->assertNotNull($ret->loginRequest, "Response {$i}, login marker");
             $this->assertContains($ret->loginRequest, $this->managerPriv->createdAccountAuthenticationRequests, "Response {$i}, login marker");
             $expectLog[] = [LogLevel::INFO, "MediaWiki\\Auth\\AuthManager::continueAccountCreation: Account creation succeeded for {user}"];
             // Set some fields in the expected $response that we couldn't
             // know in provideAccountCreation().
             $response->username = $username;
             $response->loginRequest = $ret->loginRequest;
         } else {
             $this->assertNull($ret->loginRequest, "Response {$i}, login marker");
             $this->assertSame([], $this->managerPriv->createdAccountAuthenticationRequests, "Response {$i}, login marker");
         }
         $ret->message = $this->message($ret->message);
         $this->assertEquals($response, $ret, "Response {$i}, response");
         if ($success || $response->status === AuthenticationResponse::FAIL) {
             $this->assertNull($this->request->getSession()->getSecret('AuthManager::accountCreationState'), "Response {$i}, session state");
             foreach ($providers as $p) {
                 $this->assertSame($response->status, $p->postCalled, "Response {$i}, post-auth callback called");
             }
         } else {
             $this->assertNotNull($this->request->getSession()->getSecret('AuthManager::accountCreationState'), "Response {$i}, session state");
             $this->assertEquals($ret->neededRequests, $this->manager->getAuthenticationRequests(AuthManager::ACTION_CREATE_CONTINUE), "Response {$i}, continuation check");
             foreach ($providers as $p) {
                 $this->assertFalse($p->postCalled, "Response {$i}, post-auth callback not called");
             }
         }
         if ($created) {
             $this->assertNotEquals(0, \User::idFromName($username));
         } else {
             $this->assertEquals(0, \User::idFromName($username));
         }
         $first = false;
     }
     $this->assertSame($expectLog, $this->logger->getBuffer());
     $this->assertSame($maxLogId, $dbw->selectField('logging', 'MAX(log_id)', ['log_type' => 'newusers']));
 }