The default will remain PHPUnit 4.x due to PHP 5.5 support. But, we should allow developers to run tests with newer PHPUnit versions which are noticably faster (especially for code coverage reports). * <https://github.com/sebastianbergmann/phpunit/wiki/Release-Announcement-for-PHPUnit-5.4.0> PHPUnit 5 deprecates the getMock() shortcut for getMockBuilder()->getMock(). It instead introduces the shortcut createMock() which has better defaults than getMockBuilder(). For example, it sets 'disableArgumentCloning' and other things by default. Going forward, code should either use getMockBuilder directly and configure it using the setter methods (instead of the confusing variadic arguments of getMock) or simply use the new minimalistic createMock method. This patch backports the createMock method to MediaWikiTestCase so that we can start using it. Change-Id: I091c0289b21d2b1c876adba89529dc3e72b99af2
339 lines
11 KiB
PHP
339 lines
11 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Session;
|
|
|
|
use Psr\Log\LogLevel;
|
|
use MediaWikiTestCase;
|
|
|
|
/**
|
|
* @group Session
|
|
* @group Database
|
|
* @covers MediaWiki\Session\BotPasswordSessionProvider
|
|
*/
|
|
class BotPasswordSessionProviderTest extends MediaWikiTestCase {
|
|
|
|
private $config;
|
|
|
|
private function getProvider( $name = null, $prefix = null ) {
|
|
global $wgSessionProviders;
|
|
|
|
$params = [
|
|
'priority' => 40,
|
|
'sessionCookieName' => $name,
|
|
'sessionCookieOptions' => [],
|
|
];
|
|
if ( $prefix !== null ) {
|
|
$params['sessionCookieOptions']['prefix'] = $prefix;
|
|
}
|
|
|
|
if ( !$this->config ) {
|
|
$this->config = new \HashConfig( [
|
|
'CookiePrefix' => 'wgCookiePrefix',
|
|
'EnableBotPasswords' => true,
|
|
'BotPasswordsDatabase' => false,
|
|
'SessionProviders' => $wgSessionProviders + [
|
|
BotPasswordSessionProvider::class => [
|
|
'class' => BotPasswordSessionProvider::class,
|
|
'args' => [ $params ],
|
|
]
|
|
],
|
|
] );
|
|
}
|
|
$manager = new SessionManager( [
|
|
'config' => new \MultiConfig( [ $this->config, \RequestContext::getMain()->getConfig() ] ),
|
|
'logger' => new \Psr\Log\NullLogger,
|
|
'store' => new TestBagOStuff,
|
|
] );
|
|
|
|
return $manager->getProvider( BotPasswordSessionProvider::class );
|
|
}
|
|
|
|
protected function setUp() {
|
|
parent::setUp();
|
|
|
|
$this->setMwGlobals( [
|
|
'wgEnableBotPasswords' => true,
|
|
'wgBotPasswordsDatabase' => false,
|
|
'wgCentralIdLookupProvider' => 'local',
|
|
'wgGrantPermissions' => [
|
|
'test' => [ 'read' => true ],
|
|
],
|
|
] );
|
|
}
|
|
|
|
public function addDBDataOnce() {
|
|
$passwordFactory = new \PasswordFactory();
|
|
$passwordFactory->init( \RequestContext::getMain()->getConfig() );
|
|
$passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
|
|
|
|
$sysop = static::getTestSysop()->getUser();
|
|
$userId = \CentralIdLookup::factory( 'local' )->centralIdFromName( $sysop->getName() );
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
$dbw->delete(
|
|
'bot_passwords',
|
|
[ 'bp_user' => $userId, 'bp_app_id' => 'BotPasswordSessionProvider' ],
|
|
__METHOD__
|
|
);
|
|
$dbw->insert(
|
|
'bot_passwords',
|
|
[
|
|
'bp_user' => $userId,
|
|
'bp_app_id' => 'BotPasswordSessionProvider',
|
|
'bp_password' => $passwordHash->toString(),
|
|
'bp_token' => 'token!',
|
|
'bp_restrictions' => '{"IPAddresses":["127.0.0.0/8"]}',
|
|
'bp_grants' => '["test"]',
|
|
],
|
|
__METHOD__
|
|
);
|
|
}
|
|
|
|
public function testConstructor() {
|
|
try {
|
|
$provider = new BotPasswordSessionProvider();
|
|
$this->fail( 'Expected exception not thrown' );
|
|
} catch ( \InvalidArgumentException $ex ) {
|
|
$this->assertSame(
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: priority must be specified',
|
|
$ex->getMessage()
|
|
);
|
|
}
|
|
|
|
try {
|
|
$provider = new BotPasswordSessionProvider( [
|
|
'priority' => SessionInfo::MIN_PRIORITY - 1
|
|
] );
|
|
$this->fail( 'Expected exception not thrown' );
|
|
} catch ( \InvalidArgumentException $ex ) {
|
|
$this->assertSame(
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
|
|
$ex->getMessage()
|
|
);
|
|
}
|
|
|
|
try {
|
|
$provider = new BotPasswordSessionProvider( [
|
|
'priority' => SessionInfo::MAX_PRIORITY + 1
|
|
] );
|
|
$this->fail( 'Expected exception not thrown' );
|
|
} catch ( \InvalidArgumentException $ex ) {
|
|
$this->assertSame(
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
|
|
$ex->getMessage()
|
|
);
|
|
}
|
|
|
|
$provider = new BotPasswordSessionProvider( [
|
|
'priority' => 40
|
|
] );
|
|
$priv = \TestingAccessWrapper::newFromObject( $provider );
|
|
$this->assertSame( 40, $priv->priority );
|
|
$this->assertSame( '_BPsession', $priv->sessionCookieName );
|
|
$this->assertSame( [], $priv->sessionCookieOptions );
|
|
|
|
$provider = new BotPasswordSessionProvider( [
|
|
'priority' => 40,
|
|
'sessionCookieName' => null,
|
|
] );
|
|
$priv = \TestingAccessWrapper::newFromObject( $provider );
|
|
$this->assertSame( '_BPsession', $priv->sessionCookieName );
|
|
|
|
$provider = new BotPasswordSessionProvider( [
|
|
'priority' => 40,
|
|
'sessionCookieName' => 'Foo',
|
|
'sessionCookieOptions' => [ 'Bar' ],
|
|
] );
|
|
$priv = \TestingAccessWrapper::newFromObject( $provider );
|
|
$this->assertSame( 'Foo', $priv->sessionCookieName );
|
|
$this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions );
|
|
}
|
|
|
|
public function testBasics() {
|
|
$provider = $this->getProvider();
|
|
|
|
$this->assertTrue( $provider->persistsSessionId() );
|
|
$this->assertFalse( $provider->canChangeUser() );
|
|
|
|
$this->assertNull( $provider->newSessionInfo() );
|
|
$this->assertNull( $provider->newSessionInfo( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) );
|
|
}
|
|
|
|
public function testProvideSessionInfo() {
|
|
$provider = $this->getProvider();
|
|
$request = new \FauxRequest;
|
|
$request->setCookie( '_BPsession', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'wgCookiePrefix' );
|
|
|
|
if ( !defined( 'MW_API' ) ) {
|
|
$this->assertNull( $provider->provideSessionInfo( $request ) );
|
|
define( 'MW_API', 1 );
|
|
}
|
|
|
|
$info = $provider->provideSessionInfo( $request );
|
|
$this->assertInstanceOf( SessionInfo::class, $info );
|
|
$this->assertSame( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $info->getId() );
|
|
|
|
$this->config->set( 'EnableBotPasswords', false );
|
|
$this->assertNull( $provider->provideSessionInfo( $request ) );
|
|
$this->config->set( 'EnableBotPasswords', true );
|
|
|
|
$this->assertNull( $provider->provideSessionInfo( new \FauxRequest ) );
|
|
}
|
|
|
|
public function testNewSessionInfoForRequest() {
|
|
$provider = $this->getProvider();
|
|
$user = static::getTestSysop()->getUser();
|
|
$request = $this->getMockBuilder( 'FauxRequest' )
|
|
->setMethods( [ 'getIP' ] )->getMock();
|
|
$request->expects( $this->any() )->method( 'getIP' )
|
|
->will( $this->returnValue( '127.0.0.1' ) );
|
|
$bp = \BotPassword::newFromUser( $user, 'BotPasswordSessionProvider' );
|
|
|
|
$session = $provider->newSessionForRequest( $user, $bp, $request );
|
|
$this->assertInstanceOf( Session::class, $session );
|
|
|
|
$this->assertEquals( $session->getId(), $request->getSession()->getId() );
|
|
$this->assertEquals( $user->getName(), $session->getUser()->getName() );
|
|
|
|
$this->assertEquals( [
|
|
'centralId' => $bp->getUserCentralId(),
|
|
'appId' => $bp->getAppId(),
|
|
'token' => $bp->getToken(),
|
|
'rights' => [ 'read' ],
|
|
], $session->getProviderMetadata() );
|
|
|
|
$this->assertEquals( [ 'read' ], $session->getAllowedUserRights() );
|
|
}
|
|
|
|
public function testCheckSessionInfo() {
|
|
$logger = new \TestLogger( true );
|
|
$provider = $this->getProvider();
|
|
$provider->setLogger( $logger );
|
|
|
|
$user = static::getTestSysop()->getUser();
|
|
$request = $this->getMockBuilder( 'FauxRequest' )
|
|
->setMethods( [ 'getIP' ] )->getMock();
|
|
$request->expects( $this->any() )->method( 'getIP' )
|
|
->will( $this->returnValue( '127.0.0.1' ) );
|
|
$bp = \BotPassword::newFromUser( $user, 'BotPasswordSessionProvider' );
|
|
|
|
$data = [
|
|
'provider' => $provider,
|
|
'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
'userInfo' => UserInfo::newFromUser( $user, true ),
|
|
'persisted' => false,
|
|
'metadata' => [
|
|
'centralId' => $bp->getUserCentralId(),
|
|
'appId' => $bp->getAppId(),
|
|
'token' => $bp->getToken(),
|
|
],
|
|
];
|
|
$dataMD = $data['metadata'];
|
|
|
|
foreach ( array_keys( $data['metadata'] ) as $key ) {
|
|
$data['metadata'] = $dataMD;
|
|
unset( $data['metadata'][$key] );
|
|
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
|
|
$metadata = $info->getProviderMetadata();
|
|
|
|
$this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
|
|
$this->assertSame( [
|
|
[ LogLevel::INFO, 'Session "{session}": Missing metadata: {missing}' ]
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
}
|
|
|
|
$data['metadata'] = $dataMD;
|
|
$data['metadata']['appId'] = 'Foobar';
|
|
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
|
|
$metadata = $info->getProviderMetadata();
|
|
$this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
|
|
$this->assertSame( [
|
|
[ LogLevel::INFO, 'Session "{session}": No BotPassword for {centralId} {appId}' ],
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
|
|
$data['metadata'] = $dataMD;
|
|
$data['metadata']['token'] = 'Foobar';
|
|
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
|
|
$metadata = $info->getProviderMetadata();
|
|
$this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
|
|
$this->assertSame( [
|
|
[ LogLevel::INFO, 'Session "{session}": BotPassword token check failed' ],
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
|
|
$request2 = $this->getMockBuilder( 'FauxRequest' )
|
|
->setMethods( [ 'getIP' ] )->getMock();
|
|
$request2->expects( $this->any() )->method( 'getIP' )
|
|
->will( $this->returnValue( '10.0.0.1' ) );
|
|
$data['metadata'] = $dataMD;
|
|
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
|
|
$metadata = $info->getProviderMetadata();
|
|
$this->assertFalse( $provider->refreshSessionInfo( $info, $request2, $metadata ) );
|
|
$this->assertSame( [
|
|
[ LogLevel::INFO, 'Session "{session}": Restrictions check failed' ],
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
|
|
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
|
|
$metadata = $info->getProviderMetadata();
|
|
$this->assertTrue( $provider->refreshSessionInfo( $info, $request, $metadata ) );
|
|
$this->assertSame( [], $logger->getBuffer() );
|
|
$this->assertEquals( $dataMD + [ 'rights' => [ 'read' ] ], $metadata );
|
|
}
|
|
|
|
public function testGetAllowedUserRights() {
|
|
$logger = new \TestLogger( true );
|
|
$provider = $this->getProvider();
|
|
$provider->setLogger( $logger );
|
|
|
|
$backend = TestUtils::getDummySessionBackend();
|
|
$backendPriv = \TestingAccessWrapper::newFromObject( $backend );
|
|
|
|
try {
|
|
$provider->getAllowedUserRights( $backend );
|
|
$this->fail( 'Expected exception not thrown' );
|
|
} catch ( \InvalidArgumentException $ex ) {
|
|
$this->assertSame( 'Backend\'s provider isn\'t $this', $ex->getMessage() );
|
|
}
|
|
|
|
$backendPriv->provider = $provider;
|
|
$backendPriv->providerMetadata = [ 'rights' => [ 'foo', 'bar', 'baz' ] ];
|
|
$this->assertSame( [ 'foo', 'bar', 'baz' ], $provider->getAllowedUserRights( $backend ) );
|
|
$this->assertSame( [], $logger->getBuffer() );
|
|
|
|
$backendPriv->providerMetadata = [ 'foo' => 'bar' ];
|
|
$this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
|
|
$this->assertSame( [
|
|
[
|
|
LogLevel::DEBUG,
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
|
|
'No provider metadata, returning no rights allowed'
|
|
]
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
|
|
$backendPriv->providerMetadata = [ 'rights' => 'bar' ];
|
|
$this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
|
|
$this->assertSame( [
|
|
[
|
|
LogLevel::DEBUG,
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
|
|
'No provider metadata, returning no rights allowed'
|
|
]
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
|
|
$backendPriv->providerMetadata = null;
|
|
$this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
|
|
$this->assertSame( [
|
|
[
|
|
LogLevel::DEBUG,
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
|
|
'No provider metadata, returning no rights allowed'
|
|
]
|
|
], $logger->getBuffer() );
|
|
$logger->clearBuffer();
|
|
}
|
|
}
|