3 namespace MediaWiki\Auth
;
5 use MediaWiki\MediaWikiServices
;
6 use Wikimedia\ScopedCallback
;
11 * @covers MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider
13 class TemporaryPasswordPrimaryAuthenticationProviderTest
extends \MediaWikiTestCase
{
15 private $manager = null;
16 private $config = null;
17 private $validity = null;
20 * Get an instance of the provider
22 * $provider->checkPasswordValidity is mocked to return $this->validity,
23 * because we don't need to test that here.
25 * @param array $params
26 * @return TemporaryPasswordPrimaryAuthenticationProvider
28 protected function getProvider( $params = [] ) {
29 if ( !$this->config
) {
30 $this->config
= new \
HashConfig( [
31 'EmailEnabled' => true,
34 $config = new \
MultiConfig( [
36 MediaWikiServices
::getInstance()->getMainConfig()
39 if ( !$this->manager
) {
40 $this->manager
= new AuthManager( new \
FauxRequest(), $config );
42 $this->validity
= \Status
::newGood();
44 $mockedMethods[] = 'checkPasswordValidity';
45 $provider = $this->getMockBuilder( TemporaryPasswordPrimaryAuthenticationProvider
::class )
46 ->setMethods( $mockedMethods )
47 ->setConstructorArgs( [ $params ] )
49 $provider->expects( $this->any() )->method( 'checkPasswordValidity' )
50 ->will( $this->returnCallback( function () {
51 return $this->validity
;
53 $provider->setConfig( $config );
54 $provider->setLogger( new \Psr\Log\
NullLogger() );
55 $provider->setManager( $this->manager
);
60 protected function hookMailer( $func = null ) {
61 \Hooks
::clear( 'AlternateUserMailer' );
63 \Hooks
::register( 'AlternateUserMailer', $func );
65 \Hooks
::register( 'AlternateUserMailer', function () {
69 \Hooks
::register( 'AlternateUserMailer', function () {
70 $this->fail( 'AlternateUserMailer hook called unexpectedly' );
75 return new ScopedCallback( function () {
76 \Hooks
::clear( 'AlternateUserMailer' );
77 \Hooks
::register( 'AlternateUserMailer', function () {
83 public function testBasics() {
84 $provider = new TemporaryPasswordPrimaryAuthenticationProvider();
87 PrimaryAuthenticationProvider
::TYPE_CREATE
,
88 $provider->accountCreationType()
91 $this->assertTrue( $provider->testUserExists( 'UTSysop' ) );
92 $this->assertTrue( $provider->testUserExists( 'uTSysop' ) );
93 $this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
94 $this->assertFalse( $provider->testUserExists( '<invalid>' ) );
96 $req = new PasswordAuthenticationRequest
;
97 $req->action
= AuthManager
::ACTION_CHANGE
;
98 $req->username
= '<invalid>';
99 $provider->providerChangeAuthenticationData( $req );
102 public function testConfig() {
103 $config = new \
HashConfig( [
104 'EnableEmail' => false,
105 'NewPasswordExpiry' => 100,
106 'PasswordReminderResendTime' => 101,
109 $p = \TestingAccessWrapper
::newFromObject( new TemporaryPasswordPrimaryAuthenticationProvider() );
110 $p->setConfig( $config );
111 $this->assertSame( false, $p->emailEnabled
);
112 $this->assertSame( 100, $p->newPasswordExpiry
);
113 $this->assertSame( 101, $p->passwordReminderResendTime
);
115 $p = \TestingAccessWrapper
::newFromObject( new TemporaryPasswordPrimaryAuthenticationProvider( [
116 'emailEnabled' => true,
117 'newPasswordExpiry' => 42,
118 'passwordReminderResendTime' => 43,
120 $p->setConfig( $config );
121 $this->assertSame( true, $p->emailEnabled
);
122 $this->assertSame( 42, $p->newPasswordExpiry
);
123 $this->assertSame( 43, $p->passwordReminderResendTime
);
126 public function testTestUserCanAuthenticate() {
127 $user = self
::getMutableTestUser()->getUser();
129 $dbw = wfGetDB( DB_MASTER
);
131 $passwordFactory = new \
PasswordFactory();
132 $passwordFactory->init( \RequestContext
::getMain()->getConfig() );
133 // A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
134 $passwordFactory->setDefaultType( '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()->getAuthenticationRequests( $action, $options );
195 foreach ( $actual as $req ) {
196 if ( $req instanceof TemporaryPasswordAuthenticationRequest
&& $req->password
!== null ) {
197 $req->password
= 'random';
200 $this->assertEquals( $expected, $actual );
203 public static function provideGetAuthenticationRequests() {
204 $anon = [ 'username' => null ];
205 $loggedIn = [ 'username' => 'UTSysop' ];
208 [ AuthManager
::ACTION_LOGIN
, $anon, [
209 new PasswordAuthenticationRequest
211 [ AuthManager
::ACTION_LOGIN
, $loggedIn, [
212 new PasswordAuthenticationRequest
214 [ AuthManager
::ACTION_CREATE
, $anon, [] ],
215 [ AuthManager
::ACTION_CREATE
, $loggedIn, [
216 new TemporaryPasswordAuthenticationRequest( 'random' )
218 [ AuthManager
::ACTION_LINK
, $anon, [] ],
219 [ AuthManager
::ACTION_LINK
, $loggedIn, [] ],
220 [ AuthManager
::ACTION_CHANGE
, $anon, [
221 new TemporaryPasswordAuthenticationRequest( 'random' )
223 [ AuthManager
::ACTION_CHANGE
, $loggedIn, [
224 new TemporaryPasswordAuthenticationRequest( 'random' )
226 [ AuthManager
::ACTION_REMOVE
, $anon, [
227 new TemporaryPasswordAuthenticationRequest
229 [ AuthManager
::ACTION_REMOVE
, $loggedIn, [
230 new TemporaryPasswordAuthenticationRequest
235 public function testAuthentication() {
236 $user = self
::getMutableTestUser()->getUser();
238 $password = 'TemporaryPassword';
239 $hash = ':A:' . md5( $password );
240 $dbw = wfGetDB( DB_MASTER
);
243 [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() - 10 ) ],
244 [ 'user_id' => $user->getId() ]
247 $req = new PasswordAuthenticationRequest();
248 $req->action
= AuthManager
::ACTION_LOGIN
;
249 $reqs = [ PasswordAuthenticationRequest
::class => $req ];
251 $provider = $this->getProvider();
252 $providerPriv = \TestingAccessWrapper
::newFromObject( $provider );
254 $providerPriv->newPasswordExpiry
= 100;
258 AuthenticationResponse
::newAbstain(),
259 $provider->beginPrimaryAuthentication( [] )
262 $req->username
= 'foo';
263 $req->password
= null;
265 AuthenticationResponse
::newAbstain(),
266 $provider->beginPrimaryAuthentication( $reqs )
269 $req->username
= null;
270 $req->password
= 'bar';
272 AuthenticationResponse
::newAbstain(),
273 $provider->beginPrimaryAuthentication( $reqs )
276 $req->username
= '<invalid>';
277 $req->password
= 'WhoCares';
278 $ret = $provider->beginPrimaryAuthentication( $reqs );
280 AuthenticationResponse
::newAbstain(),
281 $provider->beginPrimaryAuthentication( $reqs )
284 $req->username
= 'DoesNotExist';
285 $req->password
= 'DoesNotExist';
286 $ret = $provider->beginPrimaryAuthentication( $reqs );
288 AuthenticationResponse
::newAbstain(),
289 $provider->beginPrimaryAuthentication( $reqs )
292 // Validation failure
293 $req->username
= $user->getName();
294 $req->password
= $password;
295 $this->validity
= \Status
::newFatal( 'arbitrary-failure' );
296 $ret = $provider->beginPrimaryAuthentication( $reqs );
298 AuthenticationResponse
::FAIL
,
303 $ret->message
->getKey()
307 $this->manager
->removeAuthenticationSessionData( null );
308 $this->validity
= \Status
::newGood();
310 AuthenticationResponse
::newPass( $user->getName() ),
311 $provider->beginPrimaryAuthentication( $reqs )
313 $this->assertNotNull( $this->manager
->getAuthenticationSessionData( 'reset-pass' ) );
315 $this->manager
->removeAuthenticationSessionData( null );
316 $this->validity
= \Status
::newGood();
317 $req->username
= lcfirst( $user->getName() );
319 AuthenticationResponse
::newPass( $user->getName() ),
320 $provider->beginPrimaryAuthentication( $reqs )
322 $this->assertNotNull( $this->manager
->getAuthenticationSessionData( 'reset-pass' ) );
323 $req->username
= $user->getName();
326 $providerPriv->newPasswordExpiry
= 1;
327 $ret = $provider->beginPrimaryAuthentication( $reqs );
329 AuthenticationResponse
::FAIL
,
334 $ret->message
->getKey()
338 $providerPriv->newPasswordExpiry
= 100;
339 $this->validity
= \Status
::newGood();
340 $req->password
= 'Wrong';
341 $ret = $provider->beginPrimaryAuthentication( $reqs );
343 AuthenticationResponse
::FAIL
,
348 $ret->message
->getKey()
353 * @dataProvider provideProviderAllowsAuthenticationDataChange
354 * @param string $type
355 * @param string $user
356 * @param \Status $validity Result of the password validity check
357 * @param \StatusValue $expect1 Expected result with $checkData = false
358 * @param \StatusValue $expect2 Expected result with $checkData = true
360 public function testProviderAllowsAuthenticationDataChange( $type, $user, \Status
$validity,
361 \StatusValue
$expect1, \StatusValue
$expect2
363 if ( $type === PasswordAuthenticationRequest
::class ||
364 $type === TemporaryPasswordAuthenticationRequest
::class
368 $req = $this->createMock( $type );
370 $req->action
= AuthManager
::ACTION_CHANGE
;
371 $req->username
= $user;
372 $req->password
= 'NewPassword';
374 $provider = $this->getProvider();
375 $this->validity
= $validity;
376 $this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
377 $this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
380 public static function provideProviderAllowsAuthenticationDataChange() {
381 $err = \StatusValue
::newGood();
382 $err->error( 'arbitrary-warning' );
385 [ AuthenticationRequest
::class, 'UTSysop', \Status
::newGood(),
386 \StatusValue
::newGood( 'ignored' ), \StatusValue
::newGood( 'ignored' ) ],
387 [ PasswordAuthenticationRequest
::class, 'UTSysop', \Status
::newGood(),
388 \StatusValue
::newGood( 'ignored' ), \StatusValue
::newGood( 'ignored' ) ],
389 [ TemporaryPasswordAuthenticationRequest
::class, 'UTSysop', \Status
::newGood(),
390 \StatusValue
::newGood(), \StatusValue
::newGood() ],
391 [ TemporaryPasswordAuthenticationRequest
::class, 'uTSysop', \Status
::newGood(),
392 \StatusValue
::newGood(), \StatusValue
::newGood() ],
393 [ TemporaryPasswordAuthenticationRequest
::class, 'UTSysop', \Status
::wrap( $err ),
394 \StatusValue
::newGood(), $err ],
395 [ TemporaryPasswordAuthenticationRequest
::class, 'UTSysop',
396 \Status
::newFatal( 'arbitrary-error' ), \StatusValue
::newGood(),
397 \StatusValue
::newFatal( 'arbitrary-error' ) ],
398 [ TemporaryPasswordAuthenticationRequest
::class, 'DoesNotExist', \Status
::newGood(),
399 \StatusValue
::newGood(), \StatusValue
::newGood( 'ignored' ) ],
400 [ TemporaryPasswordAuthenticationRequest
::class, '<invalid>', \Status
::newGood(),
401 \StatusValue
::newGood(), \StatusValue
::newGood( 'ignored' ) ],
406 * @dataProvider provideProviderChangeAuthenticationData
407 * @param string $user
408 * @param string $type
409 * @param bool $changed
411 public function testProviderChangeAuthenticationData( $user, $type, $changed ) {
412 $cuser = ucfirst( $user );
413 $oldpass = 'OldTempPassword';
414 $newpass = 'NewTempPassword';
416 $dbw = wfGetDB( DB_MASTER
);
417 $oldHash = $dbw->selectField( 'user', 'user_newpassword', [ 'user_name' => $cuser ] );
418 $cb = new ScopedCallback( function () use ( $dbw, $cuser, $oldHash ) {
419 $dbw->update( 'user', [ 'user_newpassword' => $oldHash ], [ 'user_name' => $cuser ] );
422 $hash = ':A:' . md5( $oldpass );
425 [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() +
10 ) ],
426 [ 'user_name' => $cuser ]
429 $provider = $this->getProvider();
432 $loginReq = new PasswordAuthenticationRequest();
433 $loginReq->action
= AuthManager
::ACTION_CHANGE
;
434 $loginReq->username
= $user;
435 $loginReq->password
= $oldpass;
436 $loginReqs = [ PasswordAuthenticationRequest
::class => $loginReq ];
438 AuthenticationResponse
::newPass( $cuser ),
439 $provider->beginPrimaryAuthentication( $loginReqs ),
443 if ( $type === PasswordAuthenticationRequest
::class ||
444 $type === TemporaryPasswordAuthenticationRequest
::class
446 $changeReq = new $type();
448 $changeReq = $this->createMock( $type );
450 $changeReq->action
= AuthManager
::ACTION_CHANGE
;
451 $changeReq->username
= $user;
452 $changeReq->password
= $newpass;
453 $resetMailer = $this->hookMailer();
454 $provider->providerChangeAuthenticationData( $changeReq );
455 ScopedCallback
::consume( $resetMailer );
457 $loginReq->password
= $oldpass;
458 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
460 AuthenticationResponse
::FAIL
,
462 'old password should fail'
466 $ret->message
->getKey(),
467 'old password should fail'
470 $loginReq->password
= $newpass;
471 $ret = $provider->beginPrimaryAuthentication( $loginReqs );
474 AuthenticationResponse
::newPass( $cuser ),
476 'new password should pass'
478 $this->assertNotNull(
479 $dbw->selectField( 'user', 'user_newpass_time', [ 'user_name' => $cuser ] )
483 AuthenticationResponse
::FAIL
,
485 'new password should fail'
489 $ret->message
->getKey(),
490 'new password should fail'
493 $dbw->selectField( 'user', 'user_newpass_time', [ 'user_name' => $cuser ] )
498 public static function provideProviderChangeAuthenticationData() {
500 [ 'UTSysop', AuthenticationRequest
::class, false ],
501 [ 'UTSysop', PasswordAuthenticationRequest
::class, false ],
502 [ 'UTSysop', TemporaryPasswordAuthenticationRequest
::class, true ],
506 public function testProviderChangeAuthenticationDataEmail() {
507 $user = self
::getMutableTestUser()->getUser();
509 $dbw = wfGetDB( DB_MASTER
);
512 [ 'user_newpass_time' => $dbw->timestamp( time() - 5 * 3600 ) ],
513 [ 'user_id' => $user->getId() ]
516 $req = TemporaryPasswordAuthenticationRequest
::newRandom();
517 $req->username
= $user->getName();
518 $req->mailpassword
= true;
520 $provider = $this->getProvider( [ 'emailEnabled' => false ] );
521 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
522 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-emaildisabled' ), $status );
524 $provider = $this->getProvider( [ 'passwordReminderResendTime' => 10 ] );
525 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
526 $this->assertEquals( \StatusValue
::newFatal( 'throttled-mailpassword', 10 ), $status );
528 $provider = $this->getProvider( [ 'passwordReminderResendTime' => 3 ] );
529 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
530 $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
534 [ 'user_newpass_time' => $dbw->timestamp( time() +
5 * 3600 ) ],
535 [ 'user_id' => $user->getId() ]
537 $provider = $this->getProvider( [ 'passwordReminderResendTime' => 0 ] );
538 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
539 $this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
542 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
543 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-nocaller' ), $status );
545 $req->caller
= '127.0.0.256';
546 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
547 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-nosuchcaller', '127.0.0.256' ),
550 $req->caller
= '<Invalid>';
551 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
552 $this->assertEquals( \StatusValue
::newFatal( 'passwordreset-nosuchcaller', '<Invalid>' ),
555 $req->caller
= '127.0.0.1';
556 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
557 $this->assertEquals( \StatusValue
::newGood(), $status );
559 $req->caller
= $user->getName();
560 $status = $provider->providerAllowsAuthenticationDataChange( $req, true );
561 $this->assertEquals( \StatusValue
::newGood(), $status );
564 $resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
565 use ( &$mailed, $req, $user )
568 $this->assertSame( $user->getEmail(), $to[0]->address
);
569 $this->assertContains( $req->password
, $body );
572 $provider->providerChangeAuthenticationData( $req );
573 ScopedCallback
::consume( $resetMailer );
574 $this->assertTrue( $mailed );
576 $priv = \TestingAccessWrapper
::newFromObject( $provider );
577 $req->username
= '<invalid>';
578 $status = $priv->sendPasswordResetEmail( $req );
579 $this->assertEquals( \Status
::newFatal( 'noname' ), $status );
582 public function testTestForAccountCreation() {
583 $user = \User
::newFromName( 'foo' );
584 $req = new TemporaryPasswordAuthenticationRequest();
585 $req->username
= 'Foo';
586 $req->password
= 'Bar';
587 $reqs = [ TemporaryPasswordAuthenticationRequest
::class => $req ];
589 $provider = $this->getProvider();
591 \StatusValue
::newGood(),
592 $provider->testForAccountCreation( $user, $user, [] ),
593 'No password request'
597 \StatusValue
::newGood(),
598 $provider->testForAccountCreation( $user, $user, $reqs ),
599 'Password request, validated'
602 $this->validity
->error( 'arbitrary warning' );
603 $expect = \StatusValue
::newGood();
604 $expect->error( 'arbitrary warning' );
607 $provider->testForAccountCreation( $user, $user, $reqs ),
608 'Password request, not validated'
612 public function testAccountCreation() {
613 $resetMailer = $this->hookMailer();
615 $user = \User
::newFromName( 'Foo' );
617 $req = new TemporaryPasswordAuthenticationRequest();
618 $reqs = [ TemporaryPasswordAuthenticationRequest
::class => $req ];
620 $authreq = new PasswordAuthenticationRequest();
621 $authreq->action
= AuthManager
::ACTION_CREATE
;
622 $authreqs = [ PasswordAuthenticationRequest
::class => $authreq ];
624 $provider = $this->getProvider();
627 AuthenticationResponse
::newAbstain(),
628 $provider->beginPrimaryAccountCreation( $user, $user, [] )
631 $req->username
= 'foo';
632 $req->password
= null;
634 AuthenticationResponse
::newAbstain(),
635 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
638 $req->username
= null;
639 $req->password
= 'bar';
641 AuthenticationResponse
::newAbstain(),
642 $provider->beginPrimaryAccountCreation( $user, $user, $reqs )
645 $req->username
= 'foo';
646 $req->password
= 'bar';
648 $expect = AuthenticationResponse
::newPass( 'Foo' );
649 $expect->createRequest
= clone( $req );
650 $expect->createRequest
->username
= 'Foo';
651 $this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
652 $this->assertNull( $this->manager
->getAuthenticationSessionData( 'no-email' ) );
654 $user = self
::getMutableTestUser()->getUser();
655 $req->username
= $authreq->username
= $user->getName();
656 $req->password
= $authreq->password
= 'NewPassword';
657 $expect = AuthenticationResponse
::newPass( $user->getName() );
658 $expect->createRequest
= $req;
660 $res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
661 $this->assertEquals( $expect, $res2, 'Sanity check' );
663 $ret = $provider->beginPrimaryAuthentication( $authreqs );
664 $this->assertEquals( AuthenticationResponse
::FAIL
, $ret->status
, 'sanity check' );
666 $this->assertSame( null, $provider->finishAccountCreation( $user, $user, $res2 ) );
668 $ret = $provider->beginPrimaryAuthentication( $authreqs );
669 $this->assertEquals( AuthenticationResponse
::PASS
, $ret->status
, 'new password is set' );
672 public function testAccountCreationEmail() {
673 $creator = \User
::newFromName( 'Foo' );
675 $user = self
::getMutableTestUser()->getUser();
676 $user->setEmail( null );
678 $req = TemporaryPasswordAuthenticationRequest
::newRandom();
679 $req->username
= $user->getName();
680 $req->mailpassword
= true;
682 $provider = $this->getProvider( [ 'emailEnabled' => false ] );
683 $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
684 $this->assertEquals( \StatusValue
::newFatal( 'emaildisabled' ), $status );
686 $provider = $this->getProvider( [ 'emailEnabled' => true ] );
687 $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
688 $this->assertEquals( \StatusValue
::newFatal( 'noemailcreate' ), $status );
690 $user->setEmail( 'test@localhost.localdomain' );
691 $status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
692 $this->assertEquals( \StatusValue
::newGood(), $status );
695 $resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
696 use ( &$mailed, $req )
699 $this->assertSame( 'test@localhost.localdomain', $to[0]->address
);
700 $this->assertContains( $req->password
, $body );
704 $expect = AuthenticationResponse
::newPass( $user->getName() );
705 $expect->createRequest
= clone( $req );
706 $expect->createRequest
->username
= $user->getName();
707 $res = $provider->beginPrimaryAccountCreation( $user, $creator, [ $req ] );
708 $this->assertEquals( $expect, $res );
709 $this->assertTrue( $this->manager
->getAuthenticationSessionData( 'no-email' ) );
710 $this->assertFalse( $mailed );
712 $this->assertSame( 'byemail', $provider->finishAccountCreation( $user, $creator, $res ) );
713 $this->assertTrue( $mailed );
715 ScopedCallback
::consume( $resetMailer );
716 $this->assertTrue( $mailed );