3 namespace MediaWiki\Auth
;
5 use MediaWiki\MediaWikiServices
;
6 use Wikimedia\ScopedCallback
;
7 use Wikimedia\TestingAccessWrapper
;
12 * @covers \MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider
14 class TemporaryPasswordPrimaryAuthenticationProviderTest
extends \MediaWikiTestCase
{
16 private $manager = null;
17 private $config = null;
18 private $validity = null;
21 * Get an instance of the provider
23 * $provider->checkPasswordValidity is mocked to return $this->validity,
24 * because we don't need to test that here.
26 * @param array $params
27 * @return TemporaryPasswordPrimaryAuthenticationProvider
29 protected function getProvider( $params = [] ) {
30 if ( !$this->config
) {
31 $this->config
= new \
HashConfig( [
32 'EmailEnabled' => true,
35 $config = new \
MultiConfig( [
37 MediaWikiServices
::getInstance()->getMainConfig()
40 if ( !$this->manager
) {
41 $this->manager
= new AuthManager( new \
FauxRequest(), $config );
43 $this->validity
= \Status
::newGood();
45 $mockedMethods[] = 'checkPasswordValidity';
46 $provider = $this->getMockBuilder( TemporaryPasswordPrimaryAuthenticationProvider
::class )
47 ->setMethods( $mockedMethods )
48 ->setConstructorArgs( [ $params ] )
50 $provider->expects( $this->any() )->method( 'checkPasswordValidity' )
51 ->will( $this->returnCallback( function () {
52 return $this->validity
;
54 $provider->setConfig( $config );
55 $provider->setLogger( new \Psr\Log\
NullLogger() );
56 $provider->setManager( $this->manager
);
61 protected function hookMailer( $func = null ) {
62 \Hooks
::clear( 'AlternateUserMailer' );
64 \Hooks
::register( 'AlternateUserMailer', $func );
66 \Hooks
::register( 'AlternateUserMailer', function () {
70 \Hooks
::register( 'AlternateUserMailer', function () {
71 $this->fail( 'AlternateUserMailer hook called unexpectedly' );
76 return new ScopedCallback( function () {
77 \Hooks
::clear( 'AlternateUserMailer' );
78 \Hooks
::register( 'AlternateUserMailer', function () {
84 public function testBasics() {
85 $provider = new TemporaryPasswordPrimaryAuthenticationProvider();
88 PrimaryAuthenticationProvider
::TYPE_CREATE
,
89 $provider->accountCreationType()
92 $this->assertTrue( $provider->testUserExists( 'UTSysop' ) );
93 $this->assertTrue( $provider->testUserExists( 'uTSysop' ) );
94 $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
95 $this->assertFalse( $provider->testUserExists( '<invalid>' ) );
97 $req = new PasswordAuthenticationRequest
;
98 $req->action
= AuthManager
::ACTION_CHANGE
;
99 $req->username
= '<invalid>';
100 $provider->providerChangeAuthenticationData( $req );
103 public function testConfig() {
104 $config = new \
HashConfig( [
105 'EnableEmail' => false,
106 'NewPasswordExpiry' => 100,
107 'PasswordReminderResendTime' => 101,
110 $p = TestingAccessWrapper
::newFromObject( new TemporaryPasswordPrimaryAuthenticationProvider() );
111 $p->setConfig( $config );
112 $this->assertSame( false, $p->emailEnabled
);
113 $this->assertSame( 100, $p->newPasswordExpiry
);
114 $this->assertSame( 101, $p->passwordReminderResendTime
);
116 $p = TestingAccessWrapper
::newFromObject( new TemporaryPasswordPrimaryAuthenticationProvider( [
117 'emailEnabled' => true,
118 'newPasswordExpiry' => 42,
119 'passwordReminderResendTime' => 43,
121 $p->setConfig( $config );
122 $this->assertSame( true, $p->emailEnabled
);
123 $this->assertSame( 42, $p->newPasswordExpiry
);
124 $this->assertSame( 43, $p->passwordReminderResendTime
);
127 public function testTestUserCanAuthenticate() {
128 $user = self
::getMutableTestUser()->getUser();
130 $dbw = wfGetDB( DB_MASTER
);
131 $config = MediaWikiServices
::getInstance()->getMainConfig();
132 // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
133 $passwordFactory = new \
PasswordFactory( $config->get( 'PasswordConfig' ), 'A' );
135 $pwhash = $passwordFactory->newFromPlaintext( 'password' )->toString();
137 $provider = $this->getProvider();
138 $providerPriv = TestingAccessWrapper
::newFromObject( $provider );
140 $this->assertFalse( $provider->testUserCanAuthenticate( '<invalid>' ) );
141 $this->assertFalse( $provider->testUserCanAuthenticate( 'DoesNotExist' ) );
146 'user_newpassword' => \PasswordFactory
::newInvalidPassword()->toString(),
147 'user_newpass_time' => null,
149 [ 'user_id' => $user->getId() ]
151 $this->assertFalse( $provider->testUserCanAuthenticate( $user->getName() ) );
156 'user_newpassword' => $pwhash,
157 'user_newpass_time' => null,
159 [ 'user_id' => $user->getId() ]
161 $this->assertTrue( $provider->testUserCanAuthenticate( $user->getName() ) );
162 $this->assertTrue( $provider->testUserCanAuthenticate( lcfirst( $user->getName() ) ) );
167 'user_newpassword' => $pwhash,
168 'user_newpass_time' => $dbw->timestamp( time() - 10 ),
170 [ 'user_id' => $user->getId() ]
172 $providerPriv->newPasswordExpiry
= 100;
173 $this->assertTrue( $provider->testUserCanAuthenticate( $user->getName() ) );
174 $providerPriv->newPasswordExpiry
= 1;
175 $this->assertFalse( $provider->testUserCanAuthenticate( $user->getName() ) );
180 'user_newpassword' => \PasswordFactory
::newInvalidPassword()->toString(),
181 'user_newpass_time' => null,
183 [ 'user_id' => $user->getId() ]
188 * @dataProvider provideGetAuthenticationRequests
189 * @param string $action
190 * @param array $options
191 * @param array $expected
193 public function testGetAuthenticationRequests( $action, $options, $expected ) {
194 $actual = $this->getProvider( [ 'emailEnabled' => true ] )
195 ->getAuthenticationRequests( $action, $options );
196 foreach ( $actual as $req ) {
197 if ( $req instanceof TemporaryPasswordAuthenticationRequest
&& $req->password
!== null ) {
198 $req->password
= 'random';
201 $this->assertEquals( $expected, $actual );
204 public static function provideGetAuthenticationRequests() {
205 $anon = [ 'username' => null ];
206 $loggedIn = [ 'username' => 'UTSysop' ];
209 [ AuthManager
::ACTION_LOGIN
, $anon, [
210 new PasswordAuthenticationRequest
212 [ AuthManager
::ACTION_LOGIN
, $loggedIn, [
213 new PasswordAuthenticationRequest
215 [ AuthManager
::ACTION_CREATE
, $anon, [] ],
216 [ AuthManager
::ACTION_CREATE
, $loggedIn, [
217 new TemporaryPasswordAuthenticationRequest( 'random' )
219 [ AuthManager
::ACTION_LINK
, $anon, [] ],
220 [ AuthManager
::ACTION_LINK
, $loggedIn, [] ],
221 [ AuthManager
::ACTION_CHANGE
, $anon, [
222 new TemporaryPasswordAuthenticationRequest( 'random' )
224 [ AuthManager
::ACTION_CHANGE
, $loggedIn, [
225 new TemporaryPasswordAuthenticationRequest( 'random' )
227 [ AuthManager
::ACTION_REMOVE
, $anon, [
228 new TemporaryPasswordAuthenticationRequest
230 [ AuthManager
::ACTION_REMOVE
, $loggedIn, [
231 new TemporaryPasswordAuthenticationRequest
236 public function testAuthentication() {
237 $user = self
::getMutableTestUser()->getUser();
239 $password = 'TemporaryPassword';
240 $hash = ':A:' . md5( $password );
241 $dbw = wfGetDB( DB_MASTER
);
244 [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() - 10 ) ],
245 [ 'user_id' => $user->getId() ]
248 $req = new PasswordAuthenticationRequest();
249 $req->action
= AuthManager
::ACTION_LOGIN
;
250 $reqs = [ PasswordAuthenticationRequest
::class => $req ];
252 $provider = $this->getProvider();
253 $providerPriv = TestingAccessWrapper
::newFromObject( $provider );
255 $providerPriv->newPasswordExpiry
= 100;
259 AuthenticationResponse
::newAbstain(),
260 $provider->beginPrimaryAuthentication( [] )
263 $req->username
= 'foo';
264 $req->password
= null;
266 AuthenticationResponse
::newAbstain(),
267 $provider->beginPrimaryAuthentication( $reqs )
270 $req->username
= null;
271 $req->password
= 'bar';
273 AuthenticationResponse
::newAbstain(),
274 $provider->beginPrimaryAuthentication( $reqs )
277 $req->username
= '<invalid>';
278 $req->password
= 'WhoCares';
279 $ret = $provider->beginPrimaryAuthentication( $reqs );
281 AuthenticationResponse
::newAbstain(),
282 $provider->beginPrimaryAuthentication( $reqs )
285 $req->username
= 'DoesNotExist';
286 $req->password
= 'DoesNotExist';
287 $ret = $provider->beginPrimaryAuthentication( $reqs );
289 AuthenticationResponse
::newAbstain(),
290 $provider->beginPrimaryAuthentication( $reqs )
293 // Validation failure
294 $req->username
= $user->getName();
295 $req->password
= $password;
296 $this->validity
= \Status
::newFatal( 'arbitrary-failure' );
297 $ret = $provider->beginPrimaryAuthentication( $reqs );
299 AuthenticationResponse
::FAIL
,
304 $ret->message
->getKey()
308 $this->manager
->removeAuthenticationSessionData( null );
309 $this->validity
= \Status
::newGood();
311 AuthenticationResponse
::newPass( $user->getName() ),
312 $provider->beginPrimaryAuthentication( $reqs )
314 $this->assertNotNull( $this->manager
->getAuthenticationSessionData( 'reset-pass' ) );
316 $this->manager
->removeAuthenticationSessionData( null );
317 $this->validity
= \Status
::newGood();
318 $req->username
= lcfirst( $user->getName() );
320 AuthenticationResponse
::newPass( $user->getName() ),
321 $provider->beginPrimaryAuthentication( $reqs )
323 $this->assertNotNull( $this->manager
->getAuthenticationSessionData( 'reset-pass' ) );
324 $req->username
= $user->getName();
327 $providerPriv->newPasswordExpiry
= 1;
328 $ret = $provider->beginPrimaryAuthentication( $reqs );
330 AuthenticationResponse
::FAIL
,
335 $ret->message
->getKey()
339 $providerPriv->newPasswordExpiry
= 100;
340 $this->validity
= \Status
::newGood();
341 $req->password
= 'Wrong';
342 $ret = $provider->beginPrimaryAuthentication( $reqs );
344 AuthenticationResponse
::FAIL
,
349 $ret->message
->getKey()
354 * @dataProvider provideProviderAllowsAuthenticationDataChange
355 * @param string $type
356 * @param string $user
357 * @param \Status $validity Result of the password validity check
358 * @param \StatusValue $expect1 Expected result with $checkData = false
359 * @param \StatusValue $expect2 Expected result with $checkData = true
361 public function testProviderAllowsAuthenticationDataChange( $type, $user, \Status
$validity,
362 \StatusValue
$expect1, \StatusValue
$expect2
364 if ( $type === PasswordAuthenticationRequest
::class ||
365 $type === TemporaryPasswordAuthenticationRequest
::class
369 $req = $this->createMock( $type );
371 $req->action
= AuthManager
::ACTION_CHANGE
;
372 $req->username
= $user;
373 $req->password
= 'NewPassword';
375 $provider = $this->getProvider();
376 $this->validity
= $validity;
377 $this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
378 $this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
381 public static function provideProviderAllowsAuthenticationDataChange() {
382 $err = \StatusValue
::newGood();
383 $err->error( 'arbitrary-warning' );
386 [ AuthenticationRequest
::class, 'UTSysop', \Status
::newGood(),
387 \StatusValue
::newGood( 'ignored' ), \StatusValue
::newGood( 'ignored' ) ],
388 [ PasswordAuthenticationRequest
::class, 'UTSysop', \Status
::newGood(),
389 \StatusValue
::newGood( 'ignored' ), \StatusValue
::newGood( 'ignored' ) ],
390 [ TemporaryPasswordAuthenticationRequest
::class, 'UTSysop', \Status
::newGood(),
391 \StatusValue
::newGood(), \StatusValue
::newGood() ],
392 [ TemporaryPasswordAuthenticationRequest
::class, 'uTSysop', \Status
::newGood(),
393 \StatusValue
::newGood(), \StatusValue
::newGood() ],
394 [ TemporaryPasswordAuthenticationRequest
::class, 'UTSysop', \Status
::wrap( $err ),
395 \StatusValue
::newGood(), $err ],
396 [ TemporaryPasswordAuthenticationRequest
::class, 'UTSysop',
397 \Status
::newFatal( 'arbitrary-error' ), \StatusValue
::newGood(),
398 \StatusValue
::newFatal( 'arbitrary-error' ) ],
399 [ TemporaryPasswordAuthenticationRequest
::class, 'DoesNotExist', \Status
::newGood(),
400 \StatusValue
::newGood(), \StatusValue
::newGood( 'ignored' ) ],
401 [ TemporaryPasswordAuthenticationRequest
::class, '<invalid>', \Status
::newGood(),
402 \StatusValue
::newGood(), \StatusValue
::newGood( 'ignored' ) ],
407 * @dataProvider provideProviderChangeAuthenticationData
408 * @param string $user
409 * @param string $type
410 * @param bool $changed
412 public function testProviderChangeAuthenticationData( $user, $type, $changed ) {
413 $cuser = ucfirst( $user );
414 $oldpass = 'OldTempPassword';
415 $newpass = 'NewTempPassword';
417 $dbw = wfGetDB( DB_MASTER
);
418 $oldHash = $dbw->selectField( 'user', 'user_newpassword', [ 'user_name' => $cuser ] );
419 $cb = new ScopedCallback( function () use ( $dbw, $cuser, $oldHash ) {
420 $dbw->update( 'user', [ 'user_newpassword' => $oldHash ], [ 'user_name' => $cuser ] );
423 $hash = ':A:' . md5( $oldpass );
426 [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() +
10 ) ],
427 [ 'user_name' => $cuser ]
430 $provider = $this->getProvider();
433 $loginReq = new PasswordAuthenticationRequest();
434 $loginReq->action
= AuthManager
::ACTION_CHANGE
;
435 $loginReq->username
= $user;
436 $loginReq->password
= $oldpass;
437 $loginReqs = [ PasswordAuthenticationRequest
::class => $loginReq ];
439 AuthenticationResponse
::newPass( $cuser ),
440 $provider->beginPrimaryAuthentication( $loginReqs ),
444 if ( $type === PasswordAuthenticationRequest
::class ||
445 $type === TemporaryPasswordAuthenticationRequest
::class
447 $changeReq = new $type();
449 $changeReq = $this->createMock( $type );
451 $changeReq->action
= AuthManager
::ACTION_CHANGE
;
452 $changeReq->username
= $user;
453 $changeReq->password
= $newpass;
454 $resetMailer = $this->hookMailer();
455 $provider->providerChangeAuthenticationData( $changeReq );
456 ScopedCallback
::consume( $resetMailer );
458 $loginReq->password
= $oldpass;
459 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
461 AuthenticationResponse
::FAIL
,
463 'old password should fail'
467 $ret->message
->getKey(),
468 'old password should fail'
471 $loginReq->password
= $newpass;
472 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
475 AuthenticationResponse
::newPass( $cuser ),
477 'new password should pass'
479 $this->assertNotNull(
480 $dbw->selectField( 'user', 'user_newpass_time', [ 'user_name' => $cuser ] )
484 AuthenticationResponse
::FAIL
,
486 'new password should fail'
490 $ret->message
->getKey(),
491 'new password should fail'
494 $dbw->selectField( 'user', 'user_newpass_time', [ 'user_name' => $cuser ] )
499 public static function provideProviderChangeAuthenticationData() {
501 [ 'UTSysop', AuthenticationRequest
::class, false ],
502 [ 'UTSysop', PasswordAuthenticationRequest
::class, false ],
503 [ 'UTSysop', TemporaryPasswordAuthenticationRequest
::class, true ],
507 public function testProviderChangeAuthenticationDataEmail() {
508 $user = self
::getMutableTestUser()->getUser();
510 $dbw = wfGetDB( DB_MASTER
);
513 [ 'user_newpass_time' => $dbw->timestamp( time() - 5 * 3600 ) ],
514 [ 'user_id' => $user->getId() ]
517 $req = TemporaryPasswordAuthenticationRequest
::newRandom();
518 $req->username
= $user->getName();
519 $req->mailpassword
= true;
521 $provider = $this->getProvider( [ 'emailEnabled' => false ] );
522 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
523 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-emaildisabled' ), $status );
525 $provider = $this->getProvider( [
526 'emailEnabled' => true, 'passwordReminderResendTime' => 10
528 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
529 $this->assertEquals( \StatusValue
::newFatal( 'throttled-mailpassword', 10 ), $status );
531 $provider = $this->getProvider( [
532 'emailEnabled' => true, 'passwordReminderResendTime' => 3
534 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
535 $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
539 [ 'user_newpass_time' => $dbw->timestamp( time() +
5 * 3600 ) ],
540 [ 'user_id' => $user->getId() ]
542 $provider = $this->getProvider( [
543 'emailEnabled' => true, 'passwordReminderResendTime' => 0
545 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
546 $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
549 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
550 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-nocaller' ), $status );
552 $req->caller
= '127.0.0.256';
553 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
554 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-nosuchcaller', '127.0.0.256' ),
557 $req->caller
= '<Invalid>';
558 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
559 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-nosuchcaller', '<Invalid>' ),
562 $req->caller
= '127.0.0.1';
563 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
564 $this->assertEquals( \StatusValue
::newGood(), $status );
566 $req->caller
= $user->getName();
567 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
568 $this->assertEquals( \StatusValue
::newGood(), $status );
571 $resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
572 use ( &$mailed, $req, $user )
575 $this->assertSame( $user->getEmail(), $to[0]->address
);
576 $this->assertContains( $req->password
, $body );
579 $provider->providerChangeAuthenticationData( $req );
580 ScopedCallback
::consume( $resetMailer );
581 $this->assertTrue( $mailed );
583 $priv = TestingAccessWrapper
::newFromObject( $provider );
584 $req->username
= '<invalid>';
585 $status = $priv->sendPasswordResetEmail( $req );
586 $this->assertEquals( \Status
::newFatal( 'noname' ), $status );
589 public function testTestForAccountCreation() {
590 $user = \User
::newFromName( 'foo' );
591 $req = new TemporaryPasswordAuthenticationRequest();
592 $req->username
= 'Foo';
593 $req->password
= 'Bar';
594 $reqs = [ TemporaryPasswordAuthenticationRequest
::class => $req ];
596 $provider = $this->getProvider();
598 \StatusValue
::newGood(),
599 $provider->testForAccountCreation( $user, $user, [] ),
600 'No password request'
604 \StatusValue
::newGood(),
605 $provider->testForAccountCreation( $user, $user, $reqs ),
606 'Password request, validated'
609 $this->validity
->error( 'arbitrary warning' );
610 $expect = \StatusValue
::newGood();
611 $expect->error( 'arbitrary warning' );
614 $provider->testForAccountCreation( $user, $user, $reqs ),
615 'Password request, not validated'
619 public function testAccountCreation() {
620 $resetMailer = $this->hookMailer();
622 $user = \User
::newFromName( 'Foo' );
624 $req = new TemporaryPasswordAuthenticationRequest();
625 $reqs = [ TemporaryPasswordAuthenticationRequest
::class => $req ];
627 $authreq = new PasswordAuthenticationRequest();
628 $authreq->action
= AuthManager
::ACTION_CREATE
;
629 $authreqs = [ PasswordAuthenticationRequest
::class => $authreq ];
631 $provider = $this->getProvider();
634 AuthenticationResponse
::newAbstain(),
635 $provider->beginPrimaryAccountCreation( $user, $user, [] )
638 $req->username
= 'foo';
639 $req->password
= null;
641 AuthenticationResponse
::newAbstain(),
642 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
645 $req->username
= null;
646 $req->password
= 'bar';
648 AuthenticationResponse
::newAbstain(),
649 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
652 $req->username
= 'foo';
653 $req->password
= 'bar';
655 $expect = AuthenticationResponse
::newPass( 'Foo' );
656 $expect->createRequest
= clone $req;
657 $expect->createRequest
->username
= 'Foo';
658 $this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
659 $this->assertNull( $this->manager
->getAuthenticationSessionData( 'no-email' ) );
661 $user = self
::getMutableTestUser()->getUser();
662 $req->username
= $authreq->username
= $user->getName();
663 $req->password
= $authreq->password
= 'NewPassword';
664 $expect = AuthenticationResponse
::newPass( $user->getName() );
665 $expect->createRequest
= $req;
667 $res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
668 $this->assertEquals( $expect, $res2, 'Sanity check' );
670 $ret = $provider->beginPrimaryAuthentication( $authreqs );
671 $this->assertEquals( AuthenticationResponse
::FAIL
, $ret->status
, 'sanity check' );
673 $this->assertSame( null, $provider->finishAccountCreation( $user, $user, $res2 ) );
675 $ret = $provider->beginPrimaryAuthentication( $authreqs );
676 $this->assertEquals( AuthenticationResponse
::PASS
, $ret->status
, 'new password is set' );
679 public function testAccountCreationEmail() {
680 $creator = \User
::newFromName( 'Foo' );
682 $user = self
::getMutableTestUser()->getUser();
683 $user->setEmail( null );
685 $req = TemporaryPasswordAuthenticationRequest
::newRandom();
686 $req->username
= $user->getName();
687 $req->mailpassword
= true;
689 $provider = $this->getProvider( [ 'emailEnabled' => false ] );
690 $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
691 $this->assertEquals( \StatusValue
::newFatal( 'emaildisabled' ), $status );
693 $provider = $this->getProvider( [ 'emailEnabled' => true ] );
694 $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
695 $this->assertEquals( \StatusValue
::newFatal( 'noemailcreate' ), $status );
697 $user->setEmail( 'test@localhost.localdomain' );
698 $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
699 $this->assertEquals( \StatusValue
::newGood(), $status );
702 $resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
703 use ( &$mailed, $req )
706 $this->assertSame( 'test@localhost.localdomain', $to[0]->address
);
707 $this->assertContains( $req->password
, $body );
711 $expect = AuthenticationResponse
::newPass( $user->getName() );
712 $expect->createRequest
= clone $req;
713 $expect->createRequest
->username
= $user->getName();
714 $res = $provider->beginPrimaryAccountCreation( $user, $creator, [ $req ] );
715 $this->assertEquals( $expect, $res );
716 $this->assertTrue( $this->manager
->getAuthenticationSessionData( 'no-email' ) );
717 $this->assertFalse( $mailed );
719 $this->assertSame( 'byemail', $provider->finishAccountCreation( $user, $creator, $res ) );
720 $this->assertTrue( $mailed );
722 ScopedCallback
::consume( $resetMailer );
723 $this->assertTrue( $mailed );