6d831f6a0abe123ef168f4ed69a6d499949cad82
[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 $provider = $this->getMockBuilder( LocalPasswordPrimaryAuthenticationProvider::class )
42 ->setMethods( [ 'checkPasswordValidity' ] )
43 ->setConstructorArgs( [ [ 'loginOnly' => $loginOnly ] ] )
44 ->getMock();
45
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( [ 'suggestChangeOnLogin' => true ] );
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 $this->manager->removeAuthenticationSessionData( null );
189 $row->user_password_expires = null;
190 $status = \Status::newGood( [ 'suggestChangeOnLogin' => false, ] );
191 $status->error( 'testing' );
192 $providerPriv->setPasswordResetFlag( $userName, $status, $row );
193 $ret = $this->manager->getAuthenticationSessionData( 'reset-pass' );
194 $this->assertNull( $ret );
195 }
196
197 public function testAuthentication() {
198 $testUser = $this->getMutableTestUser();
199 $userName = $testUser->getUser()->getName();
200
201 $dbw = wfGetDB( DB_MASTER );
202 $id = \User::idFromName( $userName );
203
204 $req = new PasswordAuthenticationRequest();
205 $req->action = AuthManager::ACTION_LOGIN;
206 $reqs = [ PasswordAuthenticationRequest::class => $req ];
207
208 $provider = $this->getProvider();
209
210 // General failures
211 $this->assertEquals(
212 AuthenticationResponse::newAbstain(),
213 $provider->beginPrimaryAuthentication( [] )
214 );
215
216 $req->username = 'foo';
217 $req->password = null;
218 $this->assertEquals(
219 AuthenticationResponse::newAbstain(),
220 $provider->beginPrimaryAuthentication( $reqs )
221 );
222
223 $req->username = null;
224 $req->password = 'bar';
225 $this->assertEquals(
226 AuthenticationResponse::newAbstain(),
227 $provider->beginPrimaryAuthentication( $reqs )
228 );
229
230 $req->username = '<invalid>';
231 $req->password = 'WhoCares';
232 $ret = $provider->beginPrimaryAuthentication( $reqs );
233 $this->assertEquals(
234 AuthenticationResponse::newAbstain(),
235 $provider->beginPrimaryAuthentication( $reqs )
236 );
237
238 $req->username = 'DoesNotExist';
239 $req->password = 'DoesNotExist';
240 $ret = $provider->beginPrimaryAuthentication( $reqs );
241 $this->assertEquals(
242 AuthenticationResponse::FAIL,
243 $ret->status
244 );
245 $this->assertEquals(
246 'wrongpassword',
247 $ret->message->getKey()
248 );
249
250 // Validation failure
251 $req->username = $userName;
252 $req->password = $testUser->getPassword();
253 $this->validity = \Status::newFatal( 'arbitrary-failure' );
254 $ret = $provider->beginPrimaryAuthentication( $reqs );
255 $this->assertEquals(
256 AuthenticationResponse::FAIL,
257 $ret->status
258 );
259 $this->assertEquals(
260 'arbitrary-failure',
261 $ret->message->getKey()
262 );
263
264 // Successful auth
265 $this->manager->removeAuthenticationSessionData( null );
266 $this->validity = \Status::newGood();
267 $this->assertEquals(
268 AuthenticationResponse::newPass( $userName ),
269 $provider->beginPrimaryAuthentication( $reqs )
270 );
271 $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
272
273 // Successful auth after normalizing name
274 $this->manager->removeAuthenticationSessionData( null );
275 $this->validity = \Status::newGood();
276 $req->username = mb_strtolower( $userName[0] ) . substr( $userName, 1 );
277 $this->assertEquals(
278 AuthenticationResponse::newPass( $userName ),
279 $provider->beginPrimaryAuthentication( $reqs )
280 );
281 $this->assertNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
282 $req->username = $userName;
283
284 // Successful auth with reset
285 $this->manager->removeAuthenticationSessionData( null );
286 $this->validity = \Status::newGood( [ 'suggestChangeOnLogin' => true ] );
287 $this->validity->error( 'arbitrary-warning' );
288 $this->assertEquals(
289 AuthenticationResponse::newPass( $userName ),
290 $provider->beginPrimaryAuthentication( $reqs )
291 );
292 $this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
293
294 // Wrong password
295 $this->validity = \Status::newGood();
296 $req->password = 'Wrong';
297 $ret = $provider->beginPrimaryAuthentication( $reqs );
298 $this->assertEquals(
299 AuthenticationResponse::FAIL,
300 $ret->status
301 );
302 $this->assertEquals(
303 'wrongpassword',
304 $ret->message->getKey()
305 );
306
307 // Correct handling of legacy encodings
308 $password = ':B:salt:' . md5( 'salt-' . md5( "\xe1\xe9\xed\xf3\xfa" ) );
309 $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
310 $req->password = 'áéíóú';
311 $ret = $provider->beginPrimaryAuthentication( $reqs );
312 $this->assertEquals(
313 AuthenticationResponse::FAIL,
314 $ret->status
315 );
316 $this->assertEquals(
317 'wrongpassword',
318 $ret->message->getKey()
319 );
320
321 $this->config->set( 'LegacyEncoding', true );
322 $this->assertEquals(
323 AuthenticationResponse::newPass( $userName ),
324 $provider->beginPrimaryAuthentication( $reqs )
325 );
326
327 $req->password = 'áéíóú Wrong';
328 $ret = $provider->beginPrimaryAuthentication( $reqs );
329 $this->assertEquals(
330 AuthenticationResponse::FAIL,
331 $ret->status
332 );
333 $this->assertEquals(
334 'wrongpassword',
335 $ret->message->getKey()
336 );
337
338 // Correct handling of really old password hashes
339 $this->config->set( 'PasswordSalt', false );
340 $password = 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 $this->config->set( 'PasswordSalt', true );
349 $password = md5( "$id-" . md5( 'FooBar' ) );
350 $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
351 $req->password = 'FooBar';
352 $this->assertEquals(
353 AuthenticationResponse::newPass( $userName ),
354 $provider->beginPrimaryAuthentication( $reqs )
355 );
356 }
357
358 /**
359 * @dataProvider provideProviderAllowsAuthenticationDataChange
360 * @param string $type
361 * @param string $user
362 * @param \Status $validity Result of the password validity check
363 * @param \StatusValue $expect1 Expected result with $checkData = false
364 * @param \StatusValue $expect2 Expected result with $checkData = true
365 */
366 public function testProviderAllowsAuthenticationDataChange( $type, $user, \Status $validity,
367 \StatusValue $expect1, \StatusValue $expect2
368 ) {
369 if ( $type === PasswordAuthenticationRequest::class ) {
370 $req = new $type();
371 } elseif ( $type === PasswordDomainAuthenticationRequest::class ) {
372 $req = new $type( [] );
373 } else {
374 $req = $this->createMock( $type );
375 }
376 $req->action = AuthManager::ACTION_CHANGE;
377 $req->username = $user;
378 $req->password = 'NewPassword';
379 $req->retype = 'NewPassword';
380
381 $provider = $this->getProvider();
382 $this->validity = $validity;
383 $this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
384 $this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
385
386 $req->retype = 'BadRetype';
387 $this->assertEquals(
388 $expect1,
389 $provider->providerAllowsAuthenticationDataChange( $req, false )
390 );
391 $this->assertEquals(
392 $expect2->getValue() === 'ignored' ? $expect2 : \StatusValue::newFatal( 'badretype' ),
393 $provider->providerAllowsAuthenticationDataChange( $req, true )
394 );
395
396 $provider = $this->getProvider( true );
397 $this->assertEquals(
398 \StatusValue::newGood( 'ignored' ),
399 $provider->providerAllowsAuthenticationDataChange( $req, true ),
400 'loginOnly mode should claim to ignore all changes'
401 );
402 }
403
404 public static function provideProviderAllowsAuthenticationDataChange() {
405 $err = \StatusValue::newGood();
406 $err->error( 'arbitrary-warning' );
407
408 return [
409 [ AuthenticationRequest::class, 'UTSysop', \Status::newGood(),
410 \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
411 [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
412 \StatusValue::newGood(), \StatusValue::newGood() ],
413 [ PasswordAuthenticationRequest::class, 'uTSysop', \Status::newGood(),
414 \StatusValue::newGood(), \StatusValue::newGood() ],
415 [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::wrap( $err ),
416 \StatusValue::newGood(), $err ],
417 [ PasswordAuthenticationRequest::class, 'UTSysop', \Status::newFatal( 'arbitrary-error' ),
418 \StatusValue::newGood(), \StatusValue::newFatal( 'arbitrary-error' ) ],
419 [ PasswordAuthenticationRequest::class, 'DoesNotExist', \Status::newGood(),
420 \StatusValue::newGood(), \StatusValue::newGood( 'ignored' ) ],
421 [ PasswordDomainAuthenticationRequest::class, 'UTSysop', \Status::newGood(),
422 \StatusValue::newGood( 'ignored' ), \StatusValue::newGood( 'ignored' ) ],
423 ];
424 }
425
426 /**
427 * @dataProvider provideProviderChangeAuthenticationData
428 * @param callable|bool $usernameTransform
429 * @param string $type
430 * @param bool $loginOnly
431 * @param bool $changed
432 */
433 public function testProviderChangeAuthenticationData(
434 $usernameTransform, $type, $loginOnly, $changed ) {
435 $testUser = $this->getMutableTestUser();
436 $user = $testUser->getUser()->getName();
437 if ( is_callable( $usernameTransform ) ) {
438 $user = call_user_func( $usernameTransform, $user );
439 }
440 $cuser = ucfirst( $user );
441 $oldpass = $testUser->getPassword();
442 $newpass = 'NewPassword';
443
444 $dbw = wfGetDB( DB_MASTER );
445 $oldExpiry = $dbw->selectField( 'user', 'user_password_expires', [ 'user_name' => $cuser ] );
446
447 $this->mergeMwGlobalArrayValue( 'wgHooks', [
448 'ResetPasswordExpiration' => [ function ( $user, &$expires ) {
449 $expires = '30001231235959';
450 } ]
451 ] );
452
453 $provider = $this->getProvider( $loginOnly );
454
455 // Sanity check
456 $loginReq = new PasswordAuthenticationRequest();
457 $loginReq->action = AuthManager::ACTION_LOGIN;
458 $loginReq->username = $user;
459 $loginReq->password = $oldpass;
460 $loginReqs = [ PasswordAuthenticationRequest::class => $loginReq ];
461 $this->assertEquals(
462 AuthenticationResponse::newPass( $cuser ),
463 $provider->beginPrimaryAuthentication( $loginReqs ),
464 'Sanity check'
465 );
466
467 if ( $type === PasswordAuthenticationRequest::class ) {
468 $changeReq = new $type();
469 } else {
470 $changeReq = $this->createMock( $type );
471 }
472 $changeReq->action = AuthManager::ACTION_CHANGE;
473 $changeReq->username = $user;
474 $changeReq->password = $newpass;
475 $provider->providerChangeAuthenticationData( $changeReq );
476
477 if ( $loginOnly && $changed ) {
478 $old = 'fail';
479 $new = 'fail';
480 $expectExpiry = null;
481 } elseif ( $changed ) {
482 $old = 'fail';
483 $new = 'pass';
484 $expectExpiry = '30001231235959';
485 } else {
486 $old = 'pass';
487 $new = 'fail';
488 $expectExpiry = $oldExpiry;
489 }
490
491 $loginReq->password = $oldpass;
492 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
493 if ( $old === 'pass' ) {
494 $this->assertEquals(
495 AuthenticationResponse::newPass( $cuser ),
496 $ret,
497 'old password should pass'
498 );
499 } else {
500 $this->assertEquals(
501 AuthenticationResponse::FAIL,
502 $ret->status,
503 'old password should fail'
504 );
505 $this->assertEquals(
506 'wrongpassword',
507 $ret->message->getKey(),
508 'old password should fail'
509 );
510 }
511
512 $loginReq->password = $newpass;
513 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
514 if ( $new === 'pass' ) {
515 $this->assertEquals(
516 AuthenticationResponse::newPass( $cuser ),
517 $ret,
518 'new password should pass'
519 );
520 } else {
521 $this->assertEquals(
522 AuthenticationResponse::FAIL,
523 $ret->status,
524 'new password should fail'
525 );
526 $this->assertEquals(
527 'wrongpassword',
528 $ret->message->getKey(),
529 'new password should fail'
530 );
531 }
532
533 $this->assertSame(
534 $expectExpiry,
535 wfTimestampOrNull(
536 TS_MW,
537 $dbw->selectField( 'user', 'user_password_expires', [ 'user_name' => $cuser ] )
538 )
539 );
540 }
541
542 public static function provideProviderChangeAuthenticationData() {
543 return [
544 [ false, AuthenticationRequest::class, false, false ],
545 [ false, PasswordAuthenticationRequest::class, false, true ],
546 [ false, AuthenticationRequest::class, true, false ],
547 [ false, PasswordAuthenticationRequest::class, true, true ],
548 [ 'ucfirst', PasswordAuthenticationRequest::class, false, true ],
549 [ 'ucfirst', PasswordAuthenticationRequest::class, true, true ],
550 ];
551 }
552
553 public function testTestForAccountCreation() {
554 $user = \User::newFromName( 'foo' );
555 $req = new PasswordAuthenticationRequest();
556 $req->action = AuthManager::ACTION_CREATE;
557 $req->username = 'Foo';
558 $req->password = 'Bar';
559 $req->retype = 'Bar';
560 $reqs = [ PasswordAuthenticationRequest::class => $req ];
561
562 $provider = $this->getProvider();
563 $this->assertEquals(
564 \StatusValue::newGood(),
565 $provider->testForAccountCreation( $user, $user, [] ),
566 'No password request'
567 );
568
569 $this->assertEquals(
570 \StatusValue::newGood(),
571 $provider->testForAccountCreation( $user, $user, $reqs ),
572 'Password request, validated'
573 );
574
575 $req->retype = 'Baz';
576 $this->assertEquals(
577 \StatusValue::newFatal( 'badretype' ),
578 $provider->testForAccountCreation( $user, $user, $reqs ),
579 'Password request, bad retype'
580 );
581 $req->retype = 'Bar';
582
583 $this->validity->error( 'arbitrary warning' );
584 $expect = \StatusValue::newGood();
585 $expect->error( 'arbitrary warning' );
586 $this->assertEquals(
587 $expect,
588 $provider->testForAccountCreation( $user, $user, $reqs ),
589 'Password request, not validated'
590 );
591
592 $provider = $this->getProvider( true );
593 $this->validity->error( 'arbitrary warning' );
594 $this->assertEquals(
595 \StatusValue::newGood(),
596 $provider->testForAccountCreation( $user, $user, $reqs ),
597 'Password request, not validated, loginOnly'
598 );
599 }
600
601 public function testAccountCreation() {
602 $user = \User::newFromName( 'Foo' );
603
604 $req = new PasswordAuthenticationRequest();
605 $req->action = AuthManager::ACTION_CREATE;
606 $reqs = [ PasswordAuthenticationRequest::class => $req ];
607
608 $provider = $this->getProvider( true );
609 try {
610 $provider->beginPrimaryAccountCreation( $user, $user, [] );
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 try {
619 $provider->finishAccountCreation( $user, $user, AuthenticationResponse::newPass() );
620 $this->fail( 'Expected exception was not thrown' );
621 } catch ( \BadMethodCallException $ex ) {
622 $this->assertSame(
623 'Shouldn\'t call this when accountCreationType() is NONE', $ex->getMessage()
624 );
625 }
626
627 $provider = $this->getProvider( false );
628
629 $this->assertEquals(
630 AuthenticationResponse::newAbstain(),
631 $provider->beginPrimaryAccountCreation( $user, $user, [] )
632 );
633
634 $req->username = 'foo';
635 $req->password = null;
636 $this->assertEquals(
637 AuthenticationResponse::newAbstain(),
638 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
639 );
640
641 $req->username = null;
642 $req->password = 'bar';
643 $this->assertEquals(
644 AuthenticationResponse::newAbstain(),
645 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
646 );
647
648 $req->username = 'foo';
649 $req->password = 'bar';
650
651 $expect = AuthenticationResponse::newPass( 'Foo' );
652 $expect->createRequest = clone $req;
653 $expect->createRequest->username = 'Foo';
654 $this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
655
656 // We have to cheat a bit to avoid having to add a new user to
657 // the database to test the actual setting of the password works right
658 $dbw = wfGetDB( DB_MASTER );
659
660 $user = \User::newFromName( 'UTSysop' );
661 $req->username = $user->getName();
662 $req->password = 'NewPassword';
663 $expect = AuthenticationResponse::newPass( 'UTSysop' );
664 $expect->createRequest = $req;
665
666 $res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
667 $this->assertEquals( $expect, $res2, 'Sanity check' );
668
669 $ret = $provider->beginPrimaryAuthentication( $reqs );
670 $this->assertEquals( AuthenticationResponse::FAIL, $ret->status, 'sanity check' );
671
672 $this->assertNull( $provider->finishAccountCreation( $user, $user, $res2 ) );
673 $ret = $provider->beginPrimaryAuthentication( $reqs );
674 $this->assertEquals( AuthenticationResponse::PASS, $ret->status, 'new password is set' );
675 }
676 }