Merge "Chinese Conversion Table Update 2018-4"
[lhc/web/wiklou.git] / tests / phpunit / includes / auth / LocalPasswordPrimaryAuthenticationProviderTest.php
1 <?php
2
3 namespace MediaWiki\Auth;
4
5 use MediaWiki\MediaWikiServices;
6 use Wikimedia\TestingAccessWrapper;
7
8 /**
9 * @group AuthManager
10 * @group Database
11 * @covers \MediaWiki\Auth\LocalPasswordPrimaryAuthenticationProvider
12 */
13 class LocalPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestCase {
14
15 private $manager = null;
16 private $config = null;
17 private $validity = null;
18
19 /**
20 * Get an instance of the provider
21 *
22 * $provider->checkPasswordValidity is mocked to return $this->validity,
23 * because we don't need to test that here.
24 *
25 * @param bool $loginOnly
26 * @return LocalPasswordPrimaryAuthenticationProvider
27 */
28 protected function getProvider( $loginOnly = false ) {
29 if ( !$this->config ) {
30 $this->config = new \HashConfig();
31 }
32 $config = new \MultiConfig( [
33 $this->config,
34 MediaWikiServices::getInstance()->getMainConfig()
35 ] );
36
37 if ( !$this->manager ) {
38 $this->manager = new AuthManager( new \FauxRequest(), $config );
39 }
40 $this->validity = \Status::newGood();
41
42 $provider = $this->getMockBuilder( LocalPasswordPrimaryAuthenticationProvider::class )
43 ->setMethods( [ 'checkPasswordValidity' ] )
44 ->setConstructorArgs( [ [ 'loginOnly' => $loginOnly ] ] )
45 ->getMock();
46 $provider->expects( $this->any() )->method( 'checkPasswordValidity' )
47 ->will( $this->returnCallback( function () {
48 return $this->validity;
49 } ) );
50 $provider->setConfig( $config );
51 $provider->setLogger( new \Psr\Log\NullLogger() );
52 $provider->setManager( $this->manager );
53
54 return $provider;
55 }
56
57 public function testBasics() {
58 $user = $this->getMutableTestUser()->getUser();
59 $userName = $user->getName();
60 $lowerInitialUserName = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
61
62 $provider = new LocalPasswordPrimaryAuthenticationProvider();
63
64 $this->assertSame(
65 PrimaryAuthenticationProvider::TYPE_CREATE,
66 $provider->accountCreationType()
67 );
68
69 $this->assertTrue( $provider->testUserExists( $userName ) );
70 $this->assertTrue( $provider->testUserExists( $lowerInitialUserName ) );
71 $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
72 $this->assertFalse( $provider->testUserExists( '<invalid>' ) );
73
74 $provider = new LocalPasswordPrimaryAuthenticationProvider( [ 'loginOnly' => true ] );
75
76 $this->assertSame(
77 PrimaryAuthenticationProvider::TYPE_NONE,
78 $provider->accountCreationType()
79 );
80
81 $this->assertTrue( $provider->testUserExists( $userName ) );
82 $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
83
84 $req = new PasswordAuthenticationRequest;
85 $req->action = AuthManager::ACTION_CHANGE;
86 $req->username = '<invalid>';
87 $provider->providerChangeAuthenticationData( $req );
88 }
89
90 public function testTestUserCanAuthenticate() {
91 $user = $this->getMutableTestUser()->getUser();
92 $userName = $user->getName();
93 $dbw = wfGetDB( DB_MASTER );
94
95 $provider = $this->getProvider();
96
97 $this->assertFalse( $provider->testUserCanAuthenticate( '<invalid>' ) );
98
99 $this->assertFalse( $provider->testUserCanAuthenticate( 'DoesNotExist' ) );
100
101 $this->assertTrue( $provider->testUserCanAuthenticate( $userName ) );
102 $lowerInitialUserName = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
103 $this->assertTrue( $provider->testUserCanAuthenticate( $lowerInitialUserName ) );
104
105 $dbw->update(
106 'user',
107 [ 'user_password' => \PasswordFactory::newInvalidPassword()->toString() ],
108 [ 'user_name' => $userName ]
109 );
110 $this->assertFalse( $provider->testUserCanAuthenticate( $userName ) );
111
112 // Really old format
113 $dbw->update(
114 'user',
115 [ 'user_password' => '0123456789abcdef0123456789abcdef' ],
116 [ 'user_name' => $userName ]
117 );
118 $this->assertTrue( $provider->testUserCanAuthenticate( $userName ) );
119 }
120
121 public function testSetPasswordResetFlag() {
122 // Set instance vars
123 $this->getProvider();
124
125 /// @todo: Because we're currently using User, which uses the global config...
126 $this->setMwGlobals( [ 'wgPasswordExpireGrace' => 100 ] );
127
128 $this->config->set( 'PasswordExpireGrace', 100 );
129 $this->config->set( 'InvalidPasswordReset', true );
130
131 $provider = new LocalPasswordPrimaryAuthenticationProvider();
132 $provider->setConfig( $this->config );
133 $provider->setLogger( new \Psr\Log\NullLogger() );
134 $provider->setManager( $this->manager );
135 $providerPriv = TestingAccessWrapper::newFromObject( $provider );
136
137 $user = $this->getMutableTestUser()->getUser();
138 $userName = $user->getName();
139 $dbw = wfGetDB( DB_MASTER );
140 $row = $dbw->selectRow(
141 'user',
142 '*',
143 [ 'user_name' => $userName ],
144 __METHOD__
145 );
146
147 $this->manager->removeAuthenticationSessionData( null );
148 $row->user_password_expires = wfTimestamp( TS_MW, time() + 200 );
149 $providerPriv->setPasswordResetFlag( $userName, \Status::newGood(), $row );
150 $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
151
152 $this->manager->removeAuthenticationSessionData( null );
153 $row->user_password_expires = wfTimestamp( TS_MW, time() - 200 );
154 $providerPriv->setPasswordResetFlag( $userName, \Status::newGood(), $row );
155 $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
156 $this->assertNotNull( $ret );
157 $this->assertSame( 'resetpass-expired', $ret->msg->getKey() );
158 $this->assertTrue( $ret->hard );
159
160 $this->manager->removeAuthenticationSessionData( null );
161 $row->user_password_expires = wfTimestamp( TS_MW, time() - 1 );
162 $providerPriv->setPasswordResetFlag( $userName, \Status::newGood(), $row );
163 $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
164 $this->assertNotNull( $ret );
165 $this->assertSame( 'resetpass-expired-soft', $ret->msg->getKey() );
166 $this->assertFalse( $ret->hard );
167
168 $this->manager->removeAuthenticationSessionData( null );
169 $row->user_password_expires = null;
170 $status = \Status::newGood();
171 $status->error( 'testing' );
172 $providerPriv->setPasswordResetFlag( $userName, $status, $row );
173 $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
174 $this->assertNotNull( $ret );
175 $this->assertSame( 'resetpass-validity-soft', $ret->msg->getKey() );
176 $this->assertFalse( $ret->hard );
177
178 $this->manager->removeAuthenticationSessionData( null );
179 $row->user_password_expires = null;
180 $status = \Status::newGood( [ 'forceChange' => true ] );
181 $status->error( 'testing' );
182 $providerPriv->setPasswordResetFlag( $userName, $status, $row );
183 $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
184 $this->assertNotNull( $ret );
185 $this->assertSame( 'resetpass-validity', $ret->msg->getKey() );
186 $this->assertTrue( $ret->hard );
187 }
188
189 public function testAuthentication() {
190 $testUser = $this->getMutableTestUser();
191 $userName = $testUser->getUser()->getName();
192
193 $dbw = wfGetDB( DB_MASTER );
194 $id = \User::idFromName( $userName );
195
196 $req = new PasswordAuthenticationRequest();
197 $req->action = AuthManager::ACTION_LOGIN;
198 $reqs = [ PasswordAuthenticationRequest::class => $req ];
199
200 $provider = $this->getProvider();
201
202 // General failures
203 $this->assertEquals(
204 AuthenticationResponse::newAbstain(),
205 $provider->beginPrimaryAuthentication( [] )
206 );
207
208 $req->username = 'foo';
209 $req->password = null;
210 $this->assertEquals(
211 AuthenticationResponse::newAbstain(),
212 $provider->beginPrimaryAuthentication( $reqs )
213 );
214
215 $req->username = null;
216 $req->password = 'bar';
217 $this->assertEquals(
218 AuthenticationResponse::newAbstain(),
219 $provider->beginPrimaryAuthentication( $reqs )
220 );
221
222 $req->username = '<invalid>';
223 $req->password = 'WhoCares';
224 $ret = $provider->beginPrimaryAuthentication( $reqs );
225 $this->assertEquals(
226 AuthenticationResponse::newAbstain(),
227 $provider->beginPrimaryAuthentication( $reqs )
228 );
229
230 $req->username = 'DoesNotExist';
231 $req->password = 'DoesNotExist';
232 $ret = $provider->beginPrimaryAuthentication( $reqs );
233 $this->assertEquals(
234 AuthenticationResponse::FAIL,
235 $ret->status
236 );
237 $this->assertEquals(
238 'wrongpassword',
239 $ret->message->getKey()
240 );
241
242 // Validation failure
243 $req->username = $userName;
244 $req->password = $testUser->getPassword();
245 $this->validity = \Status::newFatal( 'arbitrary-failure' );
246 $ret = $provider->beginPrimaryAuthentication( $reqs );
247 $this->assertEquals(
248 AuthenticationResponse::FAIL,
249 $ret->status
250 );
251 $this->assertEquals(
252 'arbitrary-failure',
253 $ret->message->getKey()
254 );
255
256 // Successful auth
257 $this->manager->removeAuthenticationSessionData( null );
258 $this->validity = \Status::newGood();
259 $this->assertEquals(
260 AuthenticationResponse::newPass( $userName ),
261 $provider->beginPrimaryAuthentication( $reqs )
262 );
263 $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
264
265 // Successful auth after normalizing name
266 $this->manager->removeAuthenticationSessionData( null );
267 $this->validity = \Status::newGood();
268 $req->username = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
269 $this->assertEquals(
270 AuthenticationResponse::newPass( $userName ),
271 $provider->beginPrimaryAuthentication( $reqs )
272 );
273 $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
274 $req->username = $userName;
275
276 // Successful auth with reset
277 $this->manager->removeAuthenticationSessionData( null );
278 $this->validity->error( 'arbitrary-warning' );
279 $this->assertEquals(
280 AuthenticationResponse::newPass( $userName ),
281 $provider->beginPrimaryAuthentication( $reqs )
282 );
283 $this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
284
285 // Wrong password
286 $this->validity = \Status::newGood();
287 $req->password = 'Wrong';
288 $ret = $provider->beginPrimaryAuthentication( $reqs );
289 $this->assertEquals(
290 AuthenticationResponse::FAIL,
291 $ret->status
292 );
293 $this->assertEquals(
294 'wrongpassword',
295 $ret->message->getKey()
296 );
297
298 // Correct handling of legacy encodings
299 $password = ':B:salt:' . md5( 'salt-' . md5( "\xe1\xe9\xed\xf3\xfa" ) );
300 $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
301 $req->password = 'áéíóú';
302 $ret = $provider->beginPrimaryAuthentication( $reqs );
303 $this->assertEquals(
304 AuthenticationResponse::FAIL,
305 $ret->status
306 );
307 $this->assertEquals(
308 'wrongpassword',
309 $ret->message->getKey()
310 );
311
312 $this->config->set( 'LegacyEncoding', true );
313 $this->assertEquals(
314 AuthenticationResponse::newPass( $userName ),
315 $provider->beginPrimaryAuthentication( $reqs )
316 );
317
318 $req->password = 'áéíóú Wrong';
319 $ret = $provider->beginPrimaryAuthentication( $reqs );
320 $this->assertEquals(
321 AuthenticationResponse::FAIL,
322 $ret->status
323 );
324 $this->assertEquals(
325 'wrongpassword',
326 $ret->message->getKey()
327 );
328
329 // Correct handling of really old password hashes
330 $this->config->set( 'PasswordSalt', false );
331 $password = md5( 'FooBar' );
332 $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
333 $req->password = 'FooBar';
334 $this->assertEquals(
335 AuthenticationResponse::newPass( $userName ),
336 $provider->beginPrimaryAuthentication( $reqs )
337 );
338
339 $this->config->set( 'PasswordSalt', true );
340 $password = md5( "$id-" . md5( 'FooBar' ) );
341 $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
342 $req->password = 'FooBar';
343 $this->assertEquals(
344 AuthenticationResponse::newPass( $userName ),
345 $provider->beginPrimaryAuthentication( $reqs )
346 );
347 }
348
349 /**
350 * @dataProvider provideProviderAllowsAuthenticationDataChange
351 * @param string $type
352 * @param string $user
353 * @param \Status $validity Result of the password validity check
354 * @param \StatusValue $expect1 Expected result with $checkData = false
355 * @param \StatusValue $expect2 Expected result with $checkData = true
356 */
357 public function testProviderAllowsAuthenticationDataChange( $type, $user, \Status $validity,
358 \StatusValue $expect1, \StatusValue $expect2
359 ) {
360 if ( $type === PasswordAuthenticationRequest::class ) {
361 $req = new $type();
362 } elseif ( $type === PasswordDomainAuthenticationRequest::class ) {
363 $req = new $type( [] );
364 } else {
365 $req = $this->createMock( $type );
366 }
367 $req->action = AuthManager::ACTION_CHANGE;
368 $req->username = $user;
369 $req->password = 'NewPassword';
370 $req->retype = 'NewPassword';
371
372 $provider = $this->getProvider();
373 $this->validity = $validity;
374 $this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
375 $this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
376
377 $req->retype = 'BadRetype';
378 $this->assertEquals(
379 $expect1,
380 $provider->providerAllowsAuthenticationDataChange( $req, false )
381 );
382 $this->assertEquals(
383 $expect2->getValue() === 'ignored' ? $expect2 : \StatusValue::newFatal( 'badretype' ),
384 $provider->providerAllowsAuthenticationDataChange( $req, true )
385 );
386
387 $provider = $this->getProvider( true );
388 $this->assertEquals(
389 \StatusValue::newGood( 'ignored' ),
390 $provider->providerAllowsAuthenticationDataChange( $req, true ),
391 'loginOnly mode should claim to ignore all changes'
392 );
393 }
394
395 public static function provideProviderAllowsAuthenticationDataChange() {
396 $err = \StatusValue::newGood();
397 $err->error( 'arbitrary-warning' );
398
399 return [
400 [ AuthenticationRequest::class, 'UTSysop', \Status::newGood(),
401 \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
402 [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
403 \StatusValue::newGood(), \StatusValue::newGood() ],
404 [ PasswordAuthenticationRequest::class, 'uTSysop', \Status::newGood(),
405 \StatusValue::newGood(), \StatusValue::newGood() ],
406 [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::wrap( $err ),
407 \StatusValue::newGood(), $err ],
408 [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newFatal( 'arbitrary-error' ),
409 \StatusValue::newGood(), \StatusValue::newFatal( 'arbitrary-error' ) ],
410 [ PasswordAuthenticationRequest::class, 'DoesNotExist', \Status::newGood(),
411 \StatusValue::newGood(), \StatusValue::newGood( 'ignored' ) ],
412 [ PasswordDomainAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
413 \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
414 ];
415 }
416
417 /**
418 * @dataProvider provideProviderChangeAuthenticationData
419 * @param callable|bool $usernameTransform
420 * @param string $type
421 * @param bool $loginOnly
422 * @param bool $changed
423 */
424 public function testProviderChangeAuthenticationData(
425 $usernameTransform, $type, $loginOnly, $changed ) {
426 $testUser = $this->getMutableTestUser();
427 $user = $testUser->getUser()->getName();
428 if ( is_callable( $usernameTransform ) ) {
429 $user = call_user_func( $usernameTransform, $user );
430 }
431 $cuser = ucfirst( $user );
432 $oldpass = $testUser->getPassword();
433 $newpass = 'NewPassword';
434
435 $dbw = wfGetDB( DB_MASTER );
436 $oldExpiry = $dbw->selectField( 'user', 'user_password_expires', [ 'user_name' => $cuser ] );
437
438 $this->mergeMwGlobalArrayValue( 'wgHooks', [
439 'ResetPasswordExpiration' => [ function ( $user, &$expires ) {
440 $expires = '30001231235959';
441 } ]
442 ] );
443
444 $provider = $this->getProvider( $loginOnly );
445
446 // Sanity check
447 $loginReq = new PasswordAuthenticationRequest();
448 $loginReq->action = AuthManager::ACTION_LOGIN;
449 $loginReq->username = $user;
450 $loginReq->password = $oldpass;
451 $loginReqs = [ PasswordAuthenticationRequest::class => $loginReq ];
452 $this->assertEquals(
453 AuthenticationResponse::newPass( $cuser ),
454 $provider->beginPrimaryAuthentication( $loginReqs ),
455 'Sanity check'
456 );
457
458 if ( $type === PasswordAuthenticationRequest::class ) {
459 $changeReq = new $type();
460 } else {
461 $changeReq = $this->createMock( $type );
462 }
463 $changeReq->action = AuthManager::ACTION_CHANGE;
464 $changeReq->username = $user;
465 $changeReq->password = $newpass;
466 $provider->providerChangeAuthenticationData( $changeReq );
467
468 if ( $loginOnly && $changed ) {
469 $old = 'fail';
470 $new = 'fail';
471 $expectExpiry = null;
472 } elseif ( $changed ) {
473 $old = 'fail';
474 $new = 'pass';
475 $expectExpiry = '30001231235959';
476 } else {
477 $old = 'pass';
478 $new = 'fail';
479 $expectExpiry = $oldExpiry;
480 }
481
482 $loginReq->password = $oldpass;
483 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
484 if ( $old === 'pass' ) {
485 $this->assertEquals(
486 AuthenticationResponse::newPass( $cuser ),
487 $ret,
488 'old password should pass'
489 );
490 } else {
491 $this->assertEquals(
492 AuthenticationResponse::FAIL,
493 $ret->status,
494 'old password should fail'
495 );
496 $this->assertEquals(
497 'wrongpassword',
498 $ret->message->getKey(),
499 'old password should fail'
500 );
501 }
502
503 $loginReq->password = $newpass;
504 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
505 if ( $new === 'pass' ) {
506 $this->assertEquals(
507 AuthenticationResponse::newPass( $cuser ),
508 $ret,
509 'new password should pass'
510 );
511 } else {
512 $this->assertEquals(
513 AuthenticationResponse::FAIL,
514 $ret->status,
515 'new password should fail'
516 );
517 $this->assertEquals(
518 'wrongpassword',
519 $ret->message->getKey(),
520 'new password should fail'
521 );
522 }
523
524 $this->assertSame(
525 $expectExpiry,
526 wfTimestampOrNull(
527 TS_MW,
528 $dbw->selectField( 'user', 'user_password_expires', [ 'user_name' => $cuser ] )
529 )
530 );
531 }
532
533 public static function provideProviderChangeAuthenticationData() {
534 return [
535 [ false, AuthenticationRequest::class, false, false ],
536 [ false, PasswordAuthenticationRequest::class, false, true ],
537 [ false, AuthenticationRequest::class, true, false ],
538 [ false, PasswordAuthenticationRequest::class, true, true ],
539 [ 'ucfirst', PasswordAuthenticationRequest::class, false, true ],
540 [ 'ucfirst', PasswordAuthenticationRequest::class, true, true ],
541 ];
542 }
543
544 public function testTestForAccountCreation() {
545 $user = \User::newFromName( 'foo' );
546 $req = new PasswordAuthenticationRequest();
547 $req->action = AuthManager::ACTION_CREATE;
548 $req->username = 'Foo';
549 $req->password = 'Bar';
550 $req->retype = 'Bar';
551 $reqs = [ PasswordAuthenticationRequest::class => $req ];
552
553 $provider = $this->getProvider();
554 $this->assertEquals(
555 \StatusValue::newGood(),
556 $provider->testForAccountCreation( $user, $user, [] ),
557 'No password request'
558 );
559
560 $this->assertEquals(
561 \StatusValue::newGood(),
562 $provider->testForAccountCreation( $user, $user, $reqs ),
563 'Password request, validated'
564 );
565
566 $req->retype = 'Baz';
567 $this->assertEquals(
568 \StatusValue::newFatal( 'badretype' ),
569 $provider->testForAccountCreation( $user, $user, $reqs ),
570 'Password request, bad retype'
571 );
572 $req->retype = 'Bar';
573
574 $this->validity->error( 'arbitrary warning' );
575 $expect = \StatusValue::newGood();
576 $expect->error( 'arbitrary warning' );
577 $this->assertEquals(
578 $expect,
579 $provider->testForAccountCreation( $user, $user, $reqs ),
580 'Password request, not validated'
581 );
582
583 $provider = $this->getProvider( true );
584 $this->validity->error( 'arbitrary warning' );
585 $this->assertEquals(
586 \StatusValue::newGood(),
587 $provider->testForAccountCreation( $user, $user, $reqs ),
588 'Password request, not validated, loginOnly'
589 );
590 }
591
592 public function testAccountCreation() {
593 $user = \User::newFromName( 'Foo' );
594
595 $req = new PasswordAuthenticationRequest();
596 $req->action = AuthManager::ACTION_CREATE;
597 $reqs = [ PasswordAuthenticationRequest::class => $req ];
598
599 $provider = $this->getProvider( true );
600 try {
601 $provider->beginPrimaryAccountCreation( $user, $user, [] );
602 $this->fail( 'Expected exception was not thrown' );
603 } catch ( \BadMethodCallException $ex ) {
604 $this->assertSame(
605 'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
606 );
607 }
608
609 try {
610 $provider->finishAccountCreation( $user, $user, AuthenticationResponse::newPass() );
611 $this->fail( 'Expected exception was not thrown' );
612 } catch ( \BadMethodCallException $ex ) {
613 $this->assertSame(
614 'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
615 );
616 }
617
618 $provider = $this->getProvider( false );
619
620 $this->assertEquals(
621 AuthenticationResponse::newAbstain(),
622 $provider->beginPrimaryAccountCreation( $user, $user, [] )
623 );
624
625 $req->username = 'foo';
626 $req->password = null;
627 $this->assertEquals(
628 AuthenticationResponse::newAbstain(),
629 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
630 );
631
632 $req->username = null;
633 $req->password = 'bar';
634 $this->assertEquals(
635 AuthenticationResponse::newAbstain(),
636 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
637 );
638
639 $req->username = 'foo';
640 $req->password = 'bar';
641
642 $expect = AuthenticationResponse::newPass( 'Foo' );
643 $expect->createRequest = clone $req;
644 $expect->createRequest->username = 'Foo';
645 $this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
646
647 // We have to cheat a bit to avoid having to add a new user to
648 // the database to test the actual setting of the password works right
649 $dbw = wfGetDB( DB_MASTER );
650
651 $user = \User::newFromName( 'UTSysop' );
652 $req->username = $user->getName();
653 $req->password = 'NewPassword';
654 $expect = AuthenticationResponse::newPass( 'UTSysop' );
655 $expect->createRequest = $req;
656
657 $res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
658 $this->assertEquals( $expect, $res2, 'Sanity check' );
659
660 $ret = $provider->beginPrimaryAuthentication( $reqs );
661 $this->assertEquals( AuthenticationResponse::FAIL, $ret->status, 'sanity check' );
662
663 $this->assertNull( $provider->finishAccountCreation( $user, $user, $res2 ) );
664 $ret = $provider->beginPrimaryAuthentication( $reqs );
665 $this->assertEquals( AuthenticationResponse::PASS, $ret->status, 'new password is set' );
666 }
667
668 }