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