wiki.techinc.nl/tests/phpunit/includes/auth/TemporaryPasswordPrimaryAuthenticationProviderTest.php
Bartosz Dziewoński 4aebcfe097 Change more uses of getDBLoadBalancerFactory() to getConnectionProvider()
Some less trivial cases. Also update variable names.

This doesn't really change anything, but I hope it helps promote
getConnectionProvider() as the common way to do this.

Follow-up to 8604c384f6.

Change-Id: I6657d783375fac5c7fa856b884ff1fb09285e94c
2024-01-23 16:34:45 +01:00

822 lines
26 KiB
PHP

<?php
namespace MediaWiki\Auth;
use MediaWiki\Config\HashConfig;
use MediaWiki\Config\MultiConfig;
use MediaWiki\MainConfigNames;
use MediaWiki\Status\Status;
use MediaWiki\Tests\Unit\Auth\AuthenticationProviderTestTrait;
use MediaWiki\Tests\Unit\DummyServicesTrait;
use MediaWiki\User\User;
use MediaWiki\User\UserNameUtils;
use PasswordFactory;
use StatusValue;
use Wikimedia\ScopedCallback;
use Wikimedia\TestingAccessWrapper;
/**
* TODO clean up and reduce duplication
*
* @group AuthManager
* @group Database
* @covers \MediaWiki\Auth\TemporaryPasswordPrimaryAuthenticationProvider
*/
class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiIntegrationTestCase {
use AuthenticationProviderTestTrait;
use DummyServicesTrait;
private $manager = null;
private $config = null;
private $validity = null;
/**
* Get an instance of the provider
*
* $provider->checkPasswordValidity is mocked to return $this->validity,
* because we don't need to test that here.
*
* @param array $params
* @return TemporaryPasswordPrimaryAuthenticationProvider
*/
protected function getProvider( $params = [] ) {
$mwServices = $this->getServiceContainer();
if ( !$this->config ) {
$this->config = new HashConfig( [
MainConfigNames::EnableEmail
] );
}
$config = new MultiConfig( [
$this->config,
$mwServices->getMainConfig()
] );
$hookContainer = $this->createHookContainer();
if ( !$this->manager ) {
$userNameUtils = $this->createNoOpMock( UserNameUtils::class );
$this->manager = new AuthManager(
new \MediaWiki\Request\FauxRequest(),
$config,
$this->getDummyObjectFactory(),
$hookContainer,
$mwServices->getReadOnlyMode(),
$userNameUtils,
$mwServices->getBlockManager(),
$mwServices->getWatchlistManager(),
$mwServices->getDBLoadBalancer(),
$mwServices->getContentLanguage(),
$mwServices->getLanguageConverterFactory(),
$mwServices->getBotPasswordStore(),
$mwServices->getUserFactory(),
$mwServices->getUserIdentityLookup(),
$mwServices->getUserOptionsManager()
);
}
$this->validity = \MediaWiki\Status\Status::newGood();
$mockedMethods[] = 'checkPasswordValidity';
$provider = $this->getMockBuilder( TemporaryPasswordPrimaryAuthenticationProvider::class )
->onlyMethods( $mockedMethods )
->setConstructorArgs( [
$mwServices->getConnectionProvider(),
$mwServices->getUserOptionsLookup(),
$params
] )
->getMock();
$provider->method( 'checkPasswordValidity' )
->willReturnCallback( function () {
return $this->validity;
} );
$this->initProvider(
$provider, $config, null, $this->manager, null, $this->getServiceContainer()->getUserNameUtils()
);
return $provider;
}
protected function hookMailer( $func = null ) {
$hookContainer = $this->getServiceContainer()->getHookContainer();
$this->clearHook( 'AlternateUserMailer' );
if ( $func ) {
$reset = $hookContainer->scopedRegister( 'AlternateUserMailer', $func );
} else {
$reset = $hookContainer->scopedRegister( 'AlternateUserMailer', function () {
$this->fail( 'AlternateUserMailer hook called unexpectedly' );
return false;
} );
}
return $reset;
}
public function testBasics() {
$provider = $this->getProvider();
$this->assertSame(
PrimaryAuthenticationProvider::TYPE_CREATE,
$provider->accountCreationType()
);
$existingUserName = $this->getTestUser()->getUserIdentity()->getName();
$this->assertTrue( $provider->testUserExists( $existingUserName ) );
$this->assertTrue( $provider->testUserExists( lcfirst( $existingUserName ) ) );
$this->assertFalse( $provider->testUserExists( 'DoesNotExist' ) );
$this->assertFalse( $provider->testUserExists( '<invalid>' ) );
$req = new PasswordAuthenticationRequest;
$req->action = AuthManager::ACTION_CHANGE;
$req->username = '<invalid>';
$provider->providerChangeAuthenticationData( $req );
}
public function testConfig() {
$config = new HashConfig( [
MainConfigNames::EnableEmail => false,
MainConfigNames::NewPasswordExpiry => 100,
MainConfigNames::PasswordReminderResendTime => 101,
MainConfigNames::AllowRequiringEmailForResets => false,
] );
$provider = new TemporaryPasswordPrimaryAuthenticationProvider(
$this->getServiceContainer()->getConnectionProvider(),
$this->getServiceContainer()->getUserOptionsLookup()
);
$providerPriv = TestingAccessWrapper::newFromObject( $provider );
$this->initProvider( $provider, $config );
$this->assertSame( false, $providerPriv->emailEnabled );
$this->assertSame( 100, $providerPriv->newPasswordExpiry );
$this->assertSame( 101, $providerPriv->passwordReminderResendTime );
$provider = new TemporaryPasswordPrimaryAuthenticationProvider(
$this->getServiceContainer()->getConnectionProvider(),
$this->getServiceContainer()->getUserOptionsLookup(),
[
'emailEnabled' => true,
'newPasswordExpiry' => 42,
'passwordReminderResendTime' => 43,
'allowRequiringEmailForResets' => true,
]
);
$providerPriv = TestingAccessWrapper::newFromObject( $provider );
$this->initProvider( $provider, $config );
$this->assertSame( true, $providerPriv->emailEnabled );
$this->assertSame( 42, $providerPriv->newPasswordExpiry );
$this->assertSame( 43, $providerPriv->passwordReminderResendTime );
$this->assertSame( true, $providerPriv->allowRequiringEmail );
}
public function testTestUserCanAuthenticate() {
$user = self::getMutableTestUser()->getUser();
$dbw = $this->getDb();
$config = $this->getServiceContainer()->getMainConfig();
// A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
$passwordFactory = new PasswordFactory( $config->get( MainConfigNames::PasswordConfig ), 'A' );
$pwhash = $passwordFactory->newFromPlaintext( 'password' )->toString();
$provider = $this->getProvider();
$providerPriv = TestingAccessWrapper::newFromObject( $provider );
$this->assertFalse( $provider->testUserCanAuthenticate( '<invalid>' ) );
$this->assertFalse( $provider->testUserCanAuthenticate( 'DoesNotExist' ) );
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [
'user_newpassword' => \PasswordFactory::newInvalidPassword()->toString(),
'user_newpass_time' => null,
] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
$this->assertFalse( $provider->testUserCanAuthenticate( $user->getName() ) );
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpassword' => $pwhash, 'user_newpass_time' => null, ] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
$this->assertTrue( $provider->testUserCanAuthenticate( $user->getName() ) );
$this->assertTrue( $provider->testUserCanAuthenticate( lcfirst( $user->getName() ) ) );
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpassword' => $pwhash, 'user_newpass_time' => $dbw->timestamp( time() - 10 ) ] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
$providerPriv->newPasswordExpiry = 100;
$this->assertTrue( $provider->testUserCanAuthenticate( $user->getName() ) );
$providerPriv->newPasswordExpiry = 1;
$this->assertFalse( $provider->testUserCanAuthenticate( $user->getName() ) );
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [
'user_newpassword' => \PasswordFactory::newInvalidPassword()->toString(),
'user_newpass_time' => null,
] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
}
/**
* @dataProvider provideGetAuthenticationRequests
* @param string $action
* @param bool $registered
* @param array $expected
*/
public function testGetAuthenticationRequests( $action, bool $registered, $expected ) {
$options = [ 'username' => $registered ? 'TestGetAuthenticationRequests' : null ];
$actual = $this->getProvider( [ 'emailEnabled' => true ] )
->getAuthenticationRequests( $action, $options );
foreach ( $actual as $req ) {
if ( $req instanceof TemporaryPasswordAuthenticationRequest && $req->password !== null ) {
$req->password = 'random';
}
}
$this->assertEquals( $expected, $actual );
}
public static function provideGetAuthenticationRequests() {
$anon = false;
$registered = true;
return [
[ AuthManager::ACTION_LOGIN, $anon, [
new PasswordAuthenticationRequest
] ],
[ AuthManager::ACTION_LOGIN, $registered, [
new PasswordAuthenticationRequest
] ],
[ AuthManager::ACTION_CREATE, $anon, [] ],
[ AuthManager::ACTION_CREATE, $registered, [
new TemporaryPasswordAuthenticationRequest( 'random' )
] ],
[ AuthManager::ACTION_LINK, $anon, [] ],
[ AuthManager::ACTION_LINK, $registered, [] ],
[ AuthManager::ACTION_CHANGE, $anon, [
new TemporaryPasswordAuthenticationRequest( 'random' )
] ],
[ AuthManager::ACTION_CHANGE, $registered, [
new TemporaryPasswordAuthenticationRequest( 'random' )
] ],
[ AuthManager::ACTION_REMOVE, $anon, [
new TemporaryPasswordAuthenticationRequest
] ],
[ AuthManager::ACTION_REMOVE, $registered, [
new TemporaryPasswordAuthenticationRequest
] ],
];
}
public function testAuthentication() {
$user = self::getMutableTestUser()->getUser();
$password = 'TemporaryPassword';
$hash = ':A:' . md5( $password );
$dbw = $this->getDb();
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() - 10 ) ] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
$req = new PasswordAuthenticationRequest();
$req->action = AuthManager::ACTION_LOGIN;
$reqs = [ PasswordAuthenticationRequest::class => $req ];
$provider = $this->getProvider();
$providerPriv = TestingAccessWrapper::newFromObject( $provider );
$providerPriv->newPasswordExpiry = 100;
// General failures
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAuthentication( [] )
);
$req->username = 'foo';
$req->password = null;
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAuthentication( $reqs )
);
$req->username = null;
$req->password = 'bar';
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAuthentication( $reqs )
);
$req->username = '<invalid>';
$req->password = 'WhoCares';
$ret = $provider->beginPrimaryAuthentication( $reqs );
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAuthentication( $reqs )
);
$req->username = 'DoesNotExist';
$req->password = 'DoesNotExist';
$ret = $provider->beginPrimaryAuthentication( $reqs );
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAuthentication( $reqs )
);
// Validation failure
$req->username = $user->getName();
$req->password = $password;
$this->validity = \MediaWiki\Status\Status::newFatal( 'arbitrary-failure' );
$ret = $provider->beginPrimaryAuthentication( $reqs );
$this->assertEquals(
AuthenticationResponse::FAIL,
$ret->status
);
$this->assertEquals(
'fatalpassworderror',
$ret->message->getKey()
);
$this->assertEquals(
'arbitrary-failure',
$ret->message->getParams()[0]->getKey()
);
// Successful auth
$this->manager->removeAuthenticationSessionData( null );
$this->validity = \MediaWiki\Status\Status::newGood();
$this->assertEquals(
AuthenticationResponse::newPass( $user->getName() ),
$provider->beginPrimaryAuthentication( $reqs )
);
$this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
$this->manager->removeAuthenticationSessionData( null );
$this->validity = \MediaWiki\Status\Status::newGood();
$req->username = lcfirst( $user->getName() );
$this->assertEquals(
AuthenticationResponse::newPass( $user->getName() ),
$provider->beginPrimaryAuthentication( $reqs )
);
$this->assertNotNull( $this->manager->getAuthenticationSessionData( 'reset-pass' ) );
$req->username = $user->getName();
// Expired password
$providerPriv->newPasswordExpiry = 1;
$ret = $provider->beginPrimaryAuthentication( $reqs );
$this->assertEquals(
AuthenticationResponse::FAIL,
$ret->status
);
$this->assertEquals(
'wrongpassword',
$ret->message->getKey()
);
// Bad password
$providerPriv->newPasswordExpiry = 100;
$this->validity = \MediaWiki\Status\Status::newGood();
$req->password = 'Wrong';
$ret = $provider->beginPrimaryAuthentication( $reqs );
$this->assertEquals(
AuthenticationResponse::FAIL,
$ret->status
);
$this->assertEquals(
'wrongpassword',
$ret->message->getKey()
);
}
/**
* @dataProvider provideProviderAllowsAuthenticationDataChange
* @param string $type
* @param callable $usernameGetter Function that takes the username of a sysop user and returns the username to
* use for testing.
* @param \MediaWiki\Status\Status $validity Result of the password validity check
* @param \StatusValue $expect1 Expected result with $checkData = false
* @param \StatusValue $expect2 Expected result with $checkData = true
*/
public function testProviderAllowsAuthenticationDataChange( $type, callable $usernameGetter, \MediaWiki\Status\Status $validity,
\StatusValue $expect1, \StatusValue $expect2
) {
$user = $usernameGetter( $this->getTestSysop()->getUserIdentity()->getName() );
if ( $type === PasswordAuthenticationRequest::class ||
$type === TemporaryPasswordAuthenticationRequest::class
) {
$req = new $type();
$req->password = 'NewPassword';
} else {
$req = $this->createMock( $type );
}
$req->action = AuthManager::ACTION_CHANGE;
$req->username = $user;
$provider = $this->getProvider();
$this->validity = $validity;
$this->assertEquals( $expect1, $provider->providerAllowsAuthenticationDataChange( $req, false ) );
$this->assertEquals( $expect2, $provider->providerAllowsAuthenticationDataChange( $req, true ) );
}
public static function provideProviderAllowsAuthenticationDataChange() {
$err = \StatusValue::newGood();
$err->error( 'arbitrary-warning' );
return [
[
AuthenticationRequest::class,
static fn ( $sysopUsername ) => $sysopUsername,
Status::newGood(),
StatusValue::newGood( 'ignored' ),
StatusValue::newGood( 'ignored' )
],
[
PasswordAuthenticationRequest::class,
static fn ( $sysopUsername ) => $sysopUsername,
Status::newGood(),
StatusValue::newGood( 'ignored' ),
StatusValue::newGood( 'ignored' )
],
[
TemporaryPasswordAuthenticationRequest::class,
static fn ( $sysopUsername ) => $sysopUsername,
Status::newGood(),
StatusValue::newGood(),
StatusValue::newGood()
],
[
TemporaryPasswordAuthenticationRequest::class,
'lcfirst',
Status::newGood(),
StatusValue::newGood(),
StatusValue::newGood()
],
[
TemporaryPasswordAuthenticationRequest::class,
static fn ( $sysopUsername ) => $sysopUsername,
Status::wrap( $err ),
StatusValue::newGood(),
$err
],
[
TemporaryPasswordAuthenticationRequest::class,
static fn ( $sysopUsername ) => $sysopUsername,
Status::newFatal( 'arbitrary-error' ),
StatusValue::newGood(),
StatusValue::newFatal( 'arbitrary-error' )
],
[
TemporaryPasswordAuthenticationRequest::class,
static fn () => 'DoesNotExist',
Status::newGood(),
StatusValue::newGood(),
StatusValue::newGood( 'ignored' )
],
[
TemporaryPasswordAuthenticationRequest::class,
static fn () => '<invalid>',
Status::newGood(),
StatusValue::newGood(),
StatusValue::newGood( 'ignored' )
],
];
}
/**
* @dataProvider provideProviderChangeAuthenticationData
* @param string $type
* @param bool $changed
*/
public function testProviderChangeAuthenticationData( $type, $changed ) {
$user = $this->getTestSysop()->getUserIdentity()->getName();
$oldpass = 'OldTempPassword';
$newpass = 'NewTempPassword';
$dbw = $this->getDb();
$oldHash = $dbw->newSelectQueryBuilder()
->select( 'user_newpassword' )
->from( 'user' )
->where( [ 'user_name' => $user ] )
->fetchField();
$cb = new ScopedCallback( static function () use ( $dbw, $user, $oldHash ) {
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpassword' => $oldHash ] )
->where( [ 'user_name' => $user ] )
->execute();
} );
$hash = ':A:' . md5( $oldpass );
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpassword' => $hash, 'user_newpass_time' => $dbw->timestamp( time() + 10 ) ] )
->where( [ 'user_name' => $user ] )
->execute();
$provider = $this->getProvider();
$loginReq = new PasswordAuthenticationRequest();
$loginReq->action = AuthManager::ACTION_CHANGE;
$loginReq->username = $user;
$loginReq->password = $oldpass;
$loginReqs = [ PasswordAuthenticationRequest::class => $loginReq ];
$this->assertEquals(
AuthenticationResponse::newPass( $user ),
$provider->beginPrimaryAuthentication( $loginReqs )
);
if ( $type === PasswordAuthenticationRequest::class ||
$type === TemporaryPasswordAuthenticationRequest::class
) {
$changeReq = new $type();
$changeReq->password = $newpass;
} else {
$changeReq = $this->createMock( $type );
}
$changeReq->action = AuthManager::ACTION_CHANGE;
$changeReq->username = $user;
$resetMailer = $this->hookMailer();
$provider->providerChangeAuthenticationData( $changeReq );
ScopedCallback::consume( $resetMailer );
$loginReq->password = $oldpass;
$ret = $provider->beginPrimaryAuthentication( $loginReqs );
$this->assertEquals(
AuthenticationResponse::FAIL,
$ret->status,
'old password should fail'
);
$this->assertEquals(
'wrongpassword',
$ret->message->getKey(),
'old password should fail'
);
$loginReq->password = $newpass;
$ret = $provider->beginPrimaryAuthentication( $loginReqs );
if ( $changed ) {
$this->assertEquals(
AuthenticationResponse::newPass( $user ),
$ret,
'new password should pass'
);
$this->assertNotNull(
$dbw->newSelectQueryBuilder()
->select( 'user_newpass_time' )
->from( 'user' )
->where( [ 'user_name' => $user ] )
->fetchField()
);
} else {
$this->assertEquals(
AuthenticationResponse::FAIL,
$ret->status,
'new password should fail'
);
$this->assertEquals(
'wrongpassword',
$ret->message->getKey(),
'new password should fail'
);
$this->assertNull(
$dbw->newSelectQueryBuilder()
->select( 'user_newpass_time' )
->from( 'user' )
->where( [ 'user_name' => $user ] )
->fetchField()
);
}
}
public static function provideProviderChangeAuthenticationData() {
return [
[ AuthenticationRequest::class, false ],
[ PasswordAuthenticationRequest::class, false ],
[ TemporaryPasswordAuthenticationRequest::class, true ],
];
}
public function testProviderChangeAuthenticationDataEmail() {
$user = self::getMutableTestUser()->getUser();
$dbw = $this->getDb();
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpass_time' => $dbw->timestamp( time() - 5 * 3600 ) ] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
$req = TemporaryPasswordAuthenticationRequest::newRandom();
$req->username = $user->getName();
$req->mailpassword = true;
$provider = $this->getProvider( [ 'emailEnabled' => false ] );
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newFatal( 'passwordreset-emaildisabled' ), $status );
$provider = $this->getProvider( [
'emailEnabled' => true, 'passwordReminderResendTime' => 10
] );
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newFatal( 'throttled-mailpassword', 10 ), $status );
$provider = $this->getProvider( [
'emailEnabled' => true, 'passwordReminderResendTime' => 3
] );
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
$dbw->newUpdateQueryBuilder()
->update( 'user' )
->set( [ 'user_newpass_time' => $dbw->timestamp( time() + 5 * 3600 ) ] )
->where( [ 'user_id' => $user->getId() ] )
->execute();
$provider = $this->getProvider( [
'emailEnabled' => true, 'passwordReminderResendTime' => 0
] );
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertFalse( $status->hasMessage( 'throttled-mailpassword' ) );
$req->caller = null;
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newFatal( 'passwordreset-nocaller' ), $status );
$req->caller = '127.0.0.256';
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newFatal( 'passwordreset-nosuchcaller', '127.0.0.256' ),
$status );
$req->caller = '<Invalid>';
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newFatal( 'passwordreset-nosuchcaller', '<Invalid>' ),
$status );
$req->caller = '127.0.0.1';
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newGood(), $status );
$req->caller = $user->getName();
$status = $provider->providerAllowsAuthenticationDataChange( $req, true );
$this->assertEquals( \StatusValue::newGood(), $status );
$mailed = false;
$resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
use ( &$mailed, $req, $user )
{
$mailed = true;
$this->assertSame( $user->getEmail(), $to[0]->address );
$this->assertStringContainsString( $req->password, $body );
return false;
} );
$provider->providerChangeAuthenticationData( $req );
ScopedCallback::consume( $resetMailer );
$this->assertTrue( $mailed );
$priv = TestingAccessWrapper::newFromObject( $provider );
$req->username = '<invalid>';
$status = $priv->sendPasswordResetEmail( $req );
$this->assertEquals( \MediaWiki\Status\Status::newFatal( 'noname' ), $status );
}
public function testTestForAccountCreation() {
$user = User::newFromName( 'foo' );
$req = new TemporaryPasswordAuthenticationRequest();
$req->username = 'Foo';
$req->password = 'Bar';
$reqs = [ TemporaryPasswordAuthenticationRequest::class => $req ];
$provider = $this->getProvider();
$this->assertEquals(
\StatusValue::newGood(),
$provider->testForAccountCreation( $user, $user, [] ),
'No password request'
);
$this->assertEquals(
\StatusValue::newGood(),
$provider->testForAccountCreation( $user, $user, $reqs ),
'Password request, validated'
);
$this->validity->error( 'arbitrary warning' );
$expect = \StatusValue::newGood();
$expect->error( 'arbitrary warning' );
$this->assertEquals(
$expect,
$provider->testForAccountCreation( $user, $user, $reqs ),
'Password request, not validated'
);
}
public function testAccountCreation() {
$resetMailer = $this->hookMailer();
$user = User::newFromName( 'Foo' );
$req = new TemporaryPasswordAuthenticationRequest();
$reqs = [ TemporaryPasswordAuthenticationRequest::class => $req ];
$authreq = new PasswordAuthenticationRequest();
$authreq->action = AuthManager::ACTION_CREATE;
$authreqs = [ PasswordAuthenticationRequest::class => $authreq ];
$provider = $this->getProvider();
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAccountCreation( $user, $user, [] )
);
$req->username = 'foo';
$req->password = null;
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAccountCreation( $user, $user, $reqs )
);
$req->username = null;
$req->password = 'bar';
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->beginPrimaryAccountCreation( $user, $user, $reqs )
);
$req->username = 'foo';
$req->password = 'bar';
$expect = AuthenticationResponse::newPass( 'Foo' );
$expect->createRequest = clone $req;
$expect->createRequest->username = 'Foo';
$this->assertEquals( $expect, $provider->beginPrimaryAccountCreation( $user, $user, $reqs ) );
$this->assertNull( $this->manager->getAuthenticationSessionData( 'no-email' ) );
$user = self::getMutableTestUser()->getUser();
$req->username = $authreq->username = $user->getName();
$req->password = $authreq->password = 'NewPassword';
$expect = AuthenticationResponse::newPass( $user->getName() );
$expect->createRequest = $req;
$res2 = $provider->beginPrimaryAccountCreation( $user, $user, $reqs );
$this->assertEquals( $expect, $res2 );
$ret = $provider->beginPrimaryAuthentication( $authreqs );
$this->assertEquals( AuthenticationResponse::FAIL, $ret->status );
$this->assertSame( null, $provider->finishAccountCreation( $user, $user, $res2 ) );
$ret = $provider->beginPrimaryAuthentication( $authreqs );
$this->assertEquals( AuthenticationResponse::PASS, $ret->status, 'new password is set' );
}
public function testAccountCreationEmail() {
$creator = User::newFromName( 'Foo' );
$user = self::getMutableTestUser()->getUser();
$user->setEmail( '' );
$req = TemporaryPasswordAuthenticationRequest::newRandom();
$req->username = $user->getName();
$req->mailpassword = true;
$provider = $this->getProvider( [ 'emailEnabled' => false ] );
$status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
$this->assertEquals( \StatusValue::newFatal( 'emaildisabled' ), $status );
$provider = $this->getProvider( [ 'emailEnabled' => true ] );
$status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
$this->assertEquals( \StatusValue::newFatal( 'noemailcreate' ), $status );
$user->setEmail( 'test@localhost.localdomain' );
$status = $provider->testForAccountCreation( $user, $creator, [ $req ] );
$this->assertEquals( \StatusValue::newGood(), $status );
$mailed = false;
$resetMailer = $this->hookMailer( function ( $headers, $to, $from, $subject, $body )
use ( &$mailed, $req )
{
$mailed = true;
$this->assertSame( 'test@localhost.localdomain', $to[0]->address );
$this->assertStringContainsString( $req->password, $body );
return false;
} );
$expect = AuthenticationResponse::newPass( $user->getName() );
$expect->createRequest = clone $req;
$expect->createRequest->username = $user->getName();
$res = $provider->beginPrimaryAccountCreation( $user, $creator, [ $req ] );
$this->assertEquals( $expect, $res );
$this->assertTrue( $this->manager->getAuthenticationSessionData( 'no-email' ) );
$this->assertFalse( $mailed );
$this->assertSame( 'byemail', $provider->finishAccountCreation( $user, $creator, $res ) );
$this->assertTrue( $mailed );
ScopedCallback::consume( $resetMailer );
$this->assertTrue( $mailed );
}
}