This reduces the runtime of database-bound tests by about 40% (on my system, from 4:55 to 2:47; results from Jenkins are inconclusive). The basic idea is to call addCoreDBData() only once, and have a addDBDataOnce() that is called once per test class, not for every test method lie addDBData() is. Most tests could be trivially be changed to implement addDBDataOnce() instead of addDBData(). The ones for which this did not work immediately were left out for now. A closer look at the tests that still implement addDBData() may reveal additional potential for improvement. TODO: Once this is merged, try to change addDBData() to addDBDataOnce() where possible in extensions. Change-Id: Iec4ed4c8419fb4ad87e6710de808863ede9998b7
338 lines
11 KiB
PHP
338 lines
11 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Session;
|
|
|
|
use Psr\Log\LogLevel;
|
|
use MediaWikiTestCase;
|
|
use User;
|
|
|
|
/**
|
|
* @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 + [
|
|
'MediaWiki\\Session\\BotPasswordSessionProvider' => [
|
|
'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider',
|
|
'args' => [ $params ],
|
|
]
|
|
],
|
|
] );
|
|
}
|
|
$manager = new SessionManager( [
|
|
'config' => new \MultiConfig( [ $this->config, \RequestContext::getMain()->getConfig() ] ),
|
|
'logger' => new \Psr\Log\NullLogger,
|
|
'store' => new TestBagOStuff,
|
|
] );
|
|
|
|
return $manager->getProvider( 'MediaWiki\\Session\\BotPasswordSessionProvider' );
|
|
}
|
|
|
|
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() );
|
|
// A is unsalted MD5 (thus fast) ... we don't care about security here, this is test only
|
|
$passwordFactory->setDefaultType( 'A' );
|
|
$pwhash = $passwordFactory->newFromPlaintext( 'foobaz' );
|
|
|
|
$userId = \CentralIdLookup::factory( 'local' )->centralIdFromName( 'UTSysop' );
|
|
|
|
$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' => $pwhash->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( 'MediaWiki\\Session\\SessionInfo', $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 = \User::newFromName( 'UTSysop' );
|
|
$request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
|
|
$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( 'MediaWiki\\Session\\Session', $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 = \User::newFromName( 'UTSysop' );
|
|
$request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
|
|
$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->getMock( 'FauxRequest', [ 'getIP' ] );
|
|
$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();
|
|
}
|
|
}
|