wiki.techinc.nl/tests/phpunit/includes/auth/ConfirmLinkSecondaryAuthenticationProviderTest.php
Thiemo Kreuz 9e6e3f8d08 Inline a few more trivial createMock() calls in tests
createMock() is still relatively new. This code was using more
complicated mock builders before. This was changed just recently.
createMock() is now so short, the extra helper methods don't make
the code more readable, I would argue.

Change-Id: Ia7e24827157d5f49fc7da102418c79ae33c8e053
2022-08-08 09:50:50 +02:00

329 lines
11 KiB
PHP

<?php
namespace MediaWiki\Auth;
use MediaWiki\Tests\Unit\Auth\AuthenticationProviderTestTrait;
use MediaWiki\User\UserNameUtils;
use Psr\Container\ContainerInterface;
use Wikimedia\ObjectFactory\ObjectFactory;
use Wikimedia\TestingAccessWrapper;
/**
* @group AuthManager
* @covers \MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
*/
class ConfirmLinkSecondaryAuthenticationProviderTest extends \MediaWikiIntegrationTestCase {
use AuthenticationProviderTestTrait;
/**
* @dataProvider provideGetAuthenticationRequests
* @param string $action
* @param array $response
*/
public function testGetAuthenticationRequests( $action, $response ) {
$provider = new ConfirmLinkSecondaryAuthenticationProvider();
$this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
}
public static function provideGetAuthenticationRequests() {
return [
[ AuthManager::ACTION_LOGIN, [] ],
[ AuthManager::ACTION_CREATE, [] ],
[ AuthManager::ACTION_LINK, [] ],
[ AuthManager::ACTION_CHANGE, [] ],
[ AuthManager::ACTION_REMOVE, [] ],
];
}
public function testBeginSecondaryAuthentication() {
$user = \User::newFromName( 'UTSysop' );
$obj = new \stdClass;
$mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
->onlyMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
->getMock();
$mock->expects( $this->once() )->method( 'beginLinkAttempt' )
->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::authnState' ) )
->willReturn( $obj );
$mock->expects( $this->never() )->method( 'continueLinkAttempt' );
$this->assertSame( $obj, $mock->beginSecondaryAuthentication( $user, [] ) );
}
public function testContinueSecondaryAuthentication() {
$user = \User::newFromName( 'UTSysop' );
$obj = new \stdClass;
$reqs = [ new \stdClass ];
$mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
->onlyMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
->getMock();
$mock->expects( $this->never() )->method( 'beginLinkAttempt' );
$mock->expects( $this->once() )->method( 'continueLinkAttempt' )
->with(
$this->identicalTo( $user ),
$this->identicalTo( 'AuthManager::authnState' ),
$this->identicalTo( $reqs )
)
->willReturn( $obj );
$this->assertSame( $obj, $mock->continueSecondaryAuthentication( $user, $reqs ) );
}
public function testBeginSecondaryAccountCreation() {
$user = \User::newFromName( 'UTSysop' );
$obj = new \stdClass;
$mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
->onlyMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
->getMock();
$mock->expects( $this->once() )->method( 'beginLinkAttempt' )
->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::accountCreationState' ) )
->willReturn( $obj );
$mock->expects( $this->never() )->method( 'continueLinkAttempt' );
$this->assertSame( $obj, $mock->beginSecondaryAccountCreation( $user, $user, [] ) );
}
public function testContinueSecondaryAccountCreation() {
$user = \User::newFromName( 'UTSysop' );
$obj = new \stdClass;
$reqs = [ new \stdClass ];
$mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
->onlyMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
->getMock();
$mock->expects( $this->never() )->method( 'beginLinkAttempt' );
$mock->expects( $this->once() )->method( 'continueLinkAttempt' )
->with(
$this->identicalTo( $user ),
$this->identicalTo( 'AuthManager::accountCreationState' ),
$this->identicalTo( $reqs )
)
->willReturn( $obj );
$this->assertSame( $obj, $mock->continueSecondaryAccountCreation( $user, $user, $reqs ) );
}
/**
* Get requests for testing
* @return AuthenticationRequest[]
*/
private function getLinkRequests() {
$reqs = [];
$mb = $this->getMockBuilder( AuthenticationRequest::class )
->onlyMethods( [ 'getUniqueId' ] );
for ( $i = 1; $i <= 3; $i++ ) {
$uid = "Request$i";
$req = $mb->getMockForAbstractClass();
$req->method( 'getUniqueId' )->willReturn( $uid );
$req->id = $i - 1;
$reqs[$uid] = $req;
}
return $reqs;
}
public function testBeginLinkAttempt() {
$badReq = $this->getMockBuilder( AuthenticationRequest::class )
->onlyMethods( [ 'getUniqueId' ] )
->getMockForAbstractClass();
$badReq->method( 'getUniqueId' )
->willReturn( "BadReq" );
$user = \User::newFromName( 'UTSysop' );
$provider = new ConfirmLinkSecondaryAuthenticationProvider;
$providerPriv = TestingAccessWrapper::newFromObject( $provider );
$request = new \FauxRequest();
$mwServices = $this->getServiceContainer();
$manager = $this->getMockBuilder( AuthManager::class )
->onlyMethods( [ 'allowsAuthenticationDataChange' ] )
->setConstructorArgs( [
$request,
$mwServices->getMainConfig(),
$mwServices->getObjectFactory(),
$mwServices->getHookContainer(),
$mwServices->getReadOnlyMode(),
$this->createNoOpMock( UserNameUtils::class ),
$mwServices->getBlockManager(),
$mwServices->getWatchlistManager(),
$mwServices->getDBLoadBalancer(),
$mwServices->getContentLanguage(),
$mwServices->getLanguageConverterFactory(),
$mwServices->getBotPasswordStore(),
$mwServices->getUserFactory(),
$mwServices->getUserIdentityLookup(),
$mwServices->getUserOptionsManager()
] )
->getMock();
$manager->method( 'allowsAuthenticationDataChange' )
->willReturnCallback( static function ( $req ) {
return $req->getUniqueId() !== 'BadReq'
? \StatusValue::newGood()
: \StatusValue::newFatal( 'no' );
} );
$this->initProvider( $provider, null, null, $manager );
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$providerPriv->beginLinkAttempt( $user, 'state' )
);
$request->getSession()->setSecret( 'state', [
'maybeLink' => [],
] );
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$providerPriv->beginLinkAttempt( $user, 'state' )
);
$reqs = $this->getLinkRequests();
$request->getSession()->setSecret( 'state', [
'maybeLink' => $reqs + [ 'BadReq' => $badReq ]
] );
$res = $providerPriv->beginLinkAttempt( $user, 'state' );
$this->assertInstanceOf( AuthenticationResponse::class, $res );
$this->assertSame( AuthenticationResponse::UI, $res->status );
$this->assertSame( 'authprovider-confirmlink-message', $res->message->getKey() );
$this->assertCount( 1, $res->neededRequests );
$req = $res->neededRequests[0];
$this->assertInstanceOf( ConfirmLinkAuthenticationRequest::class, $req );
$expectReqs = $this->getLinkRequests();
foreach ( $expectReqs as $r ) {
$r->action = AuthManager::ACTION_CHANGE;
$r->username = $user->getName();
}
$this->assertEquals( $expectReqs, TestingAccessWrapper::newFromObject( $req )->linkRequests );
}
public function testContinueLinkAttempt() {
$user = \User::newFromName( 'UTSysop' );
$obj = new \stdClass;
$reqs = $this->getLinkRequests();
$done = [ false, false, false ];
// First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest
$mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
->onlyMethods( [ 'beginLinkAttempt' ] )
->getMock();
$mock->expects( $this->once() )->method( 'beginLinkAttempt' )
->with( $this->identicalTo( $user ), $this->identicalTo( 'state' ) )
->willReturn( $obj );
$this->assertSame(
$obj,
TestingAccessWrapper::newFromObject( $mock )->continueLinkAttempt( $user, 'state', $reqs )
);
// Now test the actual functioning
$provider = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
->onlyMethods( [
'beginLinkAttempt', 'providerAllowsAuthenticationDataChange',
'providerChangeAuthenticationData'
] )
->getMock();
$provider->expects( $this->never() )->method( 'beginLinkAttempt' );
$provider->method( 'providerAllowsAuthenticationDataChange' )
->willReturnCallback( static function ( $req ) {
return $req->getUniqueId() === 'Request3'
? \StatusValue::newFatal( 'foo' ) : \StatusValue::newGood();
} );
$provider->method( 'providerChangeAuthenticationData' )
->willReturnCallback( static function ( $req ) use ( &$done ) {
$done[$req->id] = true;
} );
$config = new \HashConfig( [
'AuthManagerConfig' => [
'preauth' => [],
'primaryauth' => [],
'secondaryauth' => [
[ 'factory' => static function () use ( $provider ) {
return $provider;
} ],
],
],
] );
$request = new \FauxRequest();
$mwServices = $this->getServiceContainer();
$manager = new AuthManager(
$request,
$config,
new ObjectFactory( $this->createNoOpMock( ContainerInterface::class ) ),
$mwServices->getHookContainer(),
$mwServices->getReadOnlyMode(),
$mwServices->getUserNameUtils(),
$mwServices->getBlockManager(),
$mwServices->getWatchlistManager(),
$mwServices->getDBLoadBalancer(),
$mwServices->getContentLanguage(),
$mwServices->getLanguageConverterFactory(),
$mwServices->getBotPasswordStore(),
$mwServices->getUserFactory(),
$mwServices->getUserIdentityLookup(),
$mwServices->getUserOptionsManager()
);
$this->initProvider( $provider, null, null, $manager );
$provider = TestingAccessWrapper::newFromObject( $provider );
$req = new ConfirmLinkAuthenticationRequest( $reqs );
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->continueLinkAttempt( $user, 'state', [ $req ] )
);
$request->getSession()->setSecret( 'state', [
'maybeLink' => [],
] );
$this->assertEquals(
AuthenticationResponse::newAbstain(),
$provider->continueLinkAttempt( $user, 'state', [ $req ] )
);
$request->getSession()->setSecret( 'state', [
'maybeLink' => $reqs
] );
$this->assertEquals(
AuthenticationResponse::newPass(),
$res = $provider->continueLinkAttempt( $user, 'state', [ $req ] )
);
$this->assertSame( [ false, false, false ], $done );
$request->getSession()->setSecret( 'state', [
'maybeLink' => [ $reqs['Request2'] ],
] );
$req->confirmedLinkIDs = [ 'Request1', 'Request2' ];
$res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
$this->assertEquals( AuthenticationResponse::newPass(), $res );
$this->assertSame( [ false, true, false ], $done );
$done = [ false, false, false ];
$request->getSession()->setSecret( 'state', [
'maybeLink' => $reqs,
] );
$req->confirmedLinkIDs = [ 'Request1', 'Request2' ];
$res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
$this->assertEquals( AuthenticationResponse::newPass(), $res );
$this->assertSame( [ true, true, false ], $done );
$done = [ false, false, false ];
$request->getSession()->setSecret( 'state', [
'maybeLink' => $reqs,
] );
$req->confirmedLinkIDs = [ 'Request1', 'Request3' ];
$res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
$this->assertEquals( AuthenticationResponse::UI, $res->status );
$this->assertCount( 1, $res->neededRequests );
$this->assertInstanceOf( ButtonAuthenticationRequest::class, $res->neededRequests[0] );
$this->assertSame( [ true, false, false ], $done );
$done = [ false, false, false ];
$res = $provider->continueLinkAttempt( $user, 'state', [ $res->neededRequests[0] ] );
$this->assertEquals( AuthenticationResponse::newPass(), $res );
$this->assertSame( [ false, false, false ], $done );
}
}