3 namespace MediaWiki\Session
;
12 * @covers MediaWiki\Session\BotPasswordSessionProvider
14 class BotPasswordSessionProviderTest
extends MediaWikiTestCase
{
18 private function getProvider( $name = null, $prefix = null ) {
19 global $wgSessionProviders;
23 'sessionCookieName' => $name,
24 'sessionCookieOptions' => [],
26 if ( $prefix !== null ) {
27 $params['sessionCookieOptions']['prefix'] = $prefix;
30 if ( !$this->config
) {
31 $this->config
= new \
HashConfig( [
32 'CookiePrefix' => 'wgCookiePrefix',
33 'EnableBotPasswords' => true,
34 'BotPasswordsDatabase' => false,
35 'SessionProviders' => $wgSessionProviders +
[
36 BotPasswordSessionProvider
::class => [
37 'class' => BotPasswordSessionProvider
::class,
38 'args' => [ $params ],
43 $manager = new SessionManager( [
44 'config' => new \
MultiConfig( [ $this->config
, \RequestContext
::getMain()->getConfig() ] ),
45 'logger' => new \Psr\Log\NullLogger
,
46 'store' => new TestBagOStuff
,
49 return $manager->getProvider( BotPasswordSessionProvider
::class );
52 protected function setUp() {
55 $this->setMwGlobals( [
56 'wgEnableBotPasswords' => true,
57 'wgBotPasswordsDatabase' => false,
58 'wgCentralIdLookupProvider' => 'local',
59 'wgGrantPermissions' => [
60 'test' => [ 'read' => true ],
65 public function addDBDataOnce() {
66 $passwordFactory = new \
PasswordFactory();
67 $passwordFactory->init( \RequestContext
::getMain()->getConfig() );
68 $passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
70 $sysop = static::getTestSysop()->getUser();
71 $userId = \CentralIdLookup
::factory( 'local' )->centralIdFromName( $sysop->getName() );
73 $dbw = wfGetDB( DB_MASTER
);
76 [ 'bp_user' => $userId, 'bp_app_id' => 'BotPasswordSessionProvider' ],
83 'bp_app_id' => 'BotPasswordSessionProvider',
84 'bp_password' => $passwordHash->toString(),
85 'bp_token' => 'token!',
86 'bp_restrictions' => '{"IPAddresses":["127.0.0.0/8"]}',
87 'bp_grants' => '["test"]',
93 public function testConstructor() {
95 $provider = new BotPasswordSessionProvider();
96 $this->fail( 'Expected exception not thrown' );
97 } catch ( \InvalidArgumentException
$ex ) {
99 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: priority must be specified',
105 $provider = new BotPasswordSessionProvider( [
106 'priority' => SessionInfo
::MIN_PRIORITY
- 1
108 $this->fail( 'Expected exception not thrown' );
109 } catch ( \InvalidArgumentException
$ex ) {
111 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
117 $provider = new BotPasswordSessionProvider( [
118 'priority' => SessionInfo
::MAX_PRIORITY +
1
120 $this->fail( 'Expected exception not thrown' );
121 } catch ( \InvalidArgumentException
$ex ) {
123 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
128 $provider = new BotPasswordSessionProvider( [
131 $priv = \TestingAccessWrapper
::newFromObject( $provider );
132 $this->assertSame( 40, $priv->priority
);
133 $this->assertSame( '_BPsession', $priv->sessionCookieName
);
134 $this->assertSame( [], $priv->sessionCookieOptions
);
136 $provider = new BotPasswordSessionProvider( [
138 'sessionCookieName' => null,
140 $priv = \TestingAccessWrapper
::newFromObject( $provider );
141 $this->assertSame( '_BPsession', $priv->sessionCookieName
);
143 $provider = new BotPasswordSessionProvider( [
145 'sessionCookieName' => 'Foo',
146 'sessionCookieOptions' => [ 'Bar' ],
148 $priv = \TestingAccessWrapper
::newFromObject( $provider );
149 $this->assertSame( 'Foo', $priv->sessionCookieName
);
150 $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions
);
153 public function testBasics() {
154 $provider = $this->getProvider();
156 $this->assertTrue( $provider->persistsSessionId() );
157 $this->assertFalse( $provider->canChangeUser() );
159 $this->assertNull( $provider->newSessionInfo() );
160 $this->assertNull( $provider->newSessionInfo( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) );
163 public function testProvideSessionInfo() {
164 $provider = $this->getProvider();
165 $request = new \FauxRequest
;
166 $request->setCookie( '_BPsession', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'wgCookiePrefix' );
168 if ( !defined( 'MW_API' ) ) {
169 $this->assertNull( $provider->provideSessionInfo( $request ) );
170 define( 'MW_API', 1 );
173 $info = $provider->provideSessionInfo( $request );
174 $this->assertInstanceOf( SessionInfo
::class, $info );
175 $this->assertSame( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $info->getId() );
177 $this->config
->set( 'EnableBotPasswords', false );
178 $this->assertNull( $provider->provideSessionInfo( $request ) );
179 $this->config
->set( 'EnableBotPasswords', true );
181 $this->assertNull( $provider->provideSessionInfo( new \FauxRequest
) );
184 public function testNewSessionInfoForRequest() {
185 $provider = $this->getProvider();
186 $user = static::getTestSysop()->getUser();
187 $request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
188 $request->expects( $this->any() )->method( 'getIP' )
189 ->will( $this->returnValue( '127.0.0.1' ) );
190 $bp = \BotPassword
::newFromUser( $user, 'BotPasswordSessionProvider' );
192 $session = $provider->newSessionForRequest( $user, $bp, $request );
193 $this->assertInstanceOf( Session
::class, $session );
195 $this->assertEquals( $session->getId(), $request->getSession()->getId() );
196 $this->assertEquals( $user->getName(), $session->getUser()->getName() );
198 $this->assertEquals( [
199 'centralId' => $bp->getUserCentralId(),
200 'appId' => $bp->getAppId(),
201 'token' => $bp->getToken(),
202 'rights' => [ 'read' ],
203 ], $session->getProviderMetadata() );
205 $this->assertEquals( [ 'read' ], $session->getAllowedUserRights() );
208 public function testCheckSessionInfo() {
209 $logger = new \
TestLogger( true );
210 $provider = $this->getProvider();
211 $provider->setLogger( $logger );
213 $user = static::getTestSysop()->getUser();
214 $request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
215 $request->expects( $this->any() )->method( 'getIP' )
216 ->will( $this->returnValue( '127.0.0.1' ) );
217 $bp = \BotPassword
::newFromUser( $user, 'BotPasswordSessionProvider' );
220 'provider' => $provider,
221 'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
222 'userInfo' => UserInfo
::newFromUser( $user, true ),
223 'persisted' => false,
225 'centralId' => $bp->getUserCentralId(),
226 'appId' => $bp->getAppId(),
227 'token' => $bp->getToken(),
230 $dataMD = $data['metadata'];
232 foreach ( array_keys( $data['metadata'] ) as $key ) {
233 $data['metadata'] = $dataMD;
234 unset( $data['metadata'][$key] );
235 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
236 $metadata = $info->getProviderMetadata();
238 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
240 [ LogLevel
::INFO
, 'Session "{session}": Missing metadata: {missing}' ]
241 ], $logger->getBuffer() );
242 $logger->clearBuffer();
245 $data['metadata'] = $dataMD;
246 $data['metadata']['appId'] = 'Foobar';
247 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
248 $metadata = $info->getProviderMetadata();
249 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
251 [ LogLevel
::INFO
, 'Session "{session}": No BotPassword for {centralId} {appId}' ],
252 ], $logger->getBuffer() );
253 $logger->clearBuffer();
255 $data['metadata'] = $dataMD;
256 $data['metadata']['token'] = 'Foobar';
257 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
258 $metadata = $info->getProviderMetadata();
259 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
261 [ LogLevel
::INFO
, 'Session "{session}": BotPassword token check failed' ],
262 ], $logger->getBuffer() );
263 $logger->clearBuffer();
265 $request2 = $this->getMock( 'FauxRequest', [ 'getIP' ] );
266 $request2->expects( $this->any() )->method( 'getIP' )
267 ->will( $this->returnValue( '10.0.0.1' ) );
268 $data['metadata'] = $dataMD;
269 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
270 $metadata = $info->getProviderMetadata();
271 $this->assertFalse( $provider->refreshSessionInfo( $info, $request2, $metadata ) );
273 [ LogLevel
::INFO
, 'Session "{session}": Restrictions check failed' ],
274 ], $logger->getBuffer() );
275 $logger->clearBuffer();
277 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
278 $metadata = $info->getProviderMetadata();
279 $this->assertTrue( $provider->refreshSessionInfo( $info, $request, $metadata ) );
280 $this->assertSame( [], $logger->getBuffer() );
281 $this->assertEquals( $dataMD +
[ 'rights' => [ 'read' ] ], $metadata );
284 public function testGetAllowedUserRights() {
285 $logger = new \
TestLogger( true );
286 $provider = $this->getProvider();
287 $provider->setLogger( $logger );
289 $backend = TestUtils
::getDummySessionBackend();
290 $backendPriv = \TestingAccessWrapper
::newFromObject( $backend );
293 $provider->getAllowedUserRights( $backend );
294 $this->fail( 'Expected exception not thrown' );
295 } catch ( \InvalidArgumentException
$ex ) {
296 $this->assertSame( 'Backend\'s provider isn\'t $this', $ex->getMessage() );
299 $backendPriv->provider
= $provider;
300 $backendPriv->providerMetadata
= [ 'rights' => [ 'foo', 'bar', 'baz' ] ];
301 $this->assertSame( [ 'foo', 'bar', 'baz' ], $provider->getAllowedUserRights( $backend ) );
302 $this->assertSame( [], $logger->getBuffer() );
304 $backendPriv->providerMetadata
= [ 'foo' => 'bar' ];
305 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
309 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
310 'No provider metadata, returning no rights allowed'
312 ], $logger->getBuffer() );
313 $logger->clearBuffer();
315 $backendPriv->providerMetadata
= [ 'rights' => 'bar' ];
316 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
320 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
321 'No provider metadata, returning no rights allowed'
323 ], $logger->getBuffer() );
324 $logger->clearBuffer();
326 $backendPriv->providerMetadata
= null;
327 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
331 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
332 'No provider metadata, returning no rights allowed'
334 ], $logger->getBuffer() );
335 $logger->clearBuffer();