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