3 namespace MediaWiki\Session
;
11 * @covers MediaWiki\Session\BotPasswordSessionProvider
13 class BotPasswordSessionProviderTest
extends MediaWikiTestCase
{
17 private function getProvider( $name = null, $prefix = null ) {
18 global $wgSessionProviders;
22 'sessionCookieName' => $name,
23 'sessionCookieOptions' => [],
25 if ( $prefix !== null ) {
26 $params['sessionCookieOptions']['prefix'] = $prefix;
29 if ( !$this->config
) {
30 $this->config
= new \
HashConfig( [
31 'CookiePrefix' => 'wgCookiePrefix',
32 'EnableBotPasswords' => true,
33 'BotPasswordsDatabase' => false,
34 'SessionProviders' => $wgSessionProviders +
[
35 BotPasswordSessionProvider
::class => [
36 'class' => BotPasswordSessionProvider
::class,
37 'args' => [ $params ],
42 $manager = new SessionManager( [
43 'config' => new \
MultiConfig( [ $this->config
, \RequestContext
::getMain()->getConfig() ] ),
44 'logger' => new \Psr\Log\NullLogger
,
45 'store' => new TestBagOStuff
,
48 return $manager->getProvider( BotPasswordSessionProvider
::class );
51 protected function setUp() {
54 $this->setMwGlobals( [
55 'wgEnableBotPasswords' => true,
56 'wgBotPasswordsDatabase' => false,
57 'wgCentralIdLookupProvider' => 'local',
58 'wgGrantPermissions' => [
59 'test' => [ 'read' => true ],
64 public function addDBDataOnce() {
65 $passwordFactory = new \
PasswordFactory();
66 $passwordFactory->init( \RequestContext
::getMain()->getConfig() );
67 $passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
69 $sysop = static::getTestSysop()->getUser();
70 $userId = \CentralIdLookup
::factory( 'local' )->centralIdFromName( $sysop->getName() );
72 $dbw = wfGetDB( DB_MASTER
);
75 [ 'bp_user' => $userId, 'bp_app_id' => 'BotPasswordSessionProvider' ],
82 'bp_app_id' => 'BotPasswordSessionProvider',
83 'bp_password' => $passwordHash->toString(),
84 'bp_token' => 'token!',
85 'bp_restrictions' => '{"IPAddresses":["127.0.0.0/8"]}',
86 'bp_grants' => '["test"]',
92 public function testConstructor() {
94 $provider = new BotPasswordSessionProvider();
95 $this->fail( 'Expected exception not thrown' );
96 } catch ( \InvalidArgumentException
$ex ) {
98 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: priority must be specified',
104 $provider = new BotPasswordSessionProvider( [
105 'priority' => SessionInfo
::MIN_PRIORITY
- 1
107 $this->fail( 'Expected exception not thrown' );
108 } catch ( \InvalidArgumentException
$ex ) {
110 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
116 $provider = new BotPasswordSessionProvider( [
117 'priority' => SessionInfo
::MAX_PRIORITY +
1
119 $this->fail( 'Expected exception not thrown' );
120 } catch ( \InvalidArgumentException
$ex ) {
122 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
127 $provider = new BotPasswordSessionProvider( [
130 $priv = \TestingAccessWrapper
::newFromObject( $provider );
131 $this->assertSame( 40, $priv->priority
);
132 $this->assertSame( '_BPsession', $priv->sessionCookieName
);
133 $this->assertSame( [], $priv->sessionCookieOptions
);
135 $provider = new BotPasswordSessionProvider( [
137 'sessionCookieName' => null,
139 $priv = \TestingAccessWrapper
::newFromObject( $provider );
140 $this->assertSame( '_BPsession', $priv->sessionCookieName
);
142 $provider = new BotPasswordSessionProvider( [
144 'sessionCookieName' => 'Foo',
145 'sessionCookieOptions' => [ 'Bar' ],
147 $priv = \TestingAccessWrapper
::newFromObject( $provider );
148 $this->assertSame( 'Foo', $priv->sessionCookieName
);
149 $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions
);
152 public function testBasics() {
153 $provider = $this->getProvider();
155 $this->assertTrue( $provider->persistsSessionId() );
156 $this->assertFalse( $provider->canChangeUser() );
158 $this->assertNull( $provider->newSessionInfo() );
159 $this->assertNull( $provider->newSessionInfo( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) );
162 public function testProvideSessionInfo() {
163 $provider = $this->getProvider();
164 $request = new \FauxRequest
;
165 $request->setCookie( '_BPsession', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'wgCookiePrefix' );
167 if ( !defined( 'MW_API' ) ) {
168 $this->assertNull( $provider->provideSessionInfo( $request ) );
169 define( 'MW_API', 1 );
172 $info = $provider->provideSessionInfo( $request );
173 $this->assertInstanceOf( SessionInfo
::class, $info );
174 $this->assertSame( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $info->getId() );
176 $this->config
->set( 'EnableBotPasswords', false );
177 $this->assertNull( $provider->provideSessionInfo( $request ) );
178 $this->config
->set( 'EnableBotPasswords', true );
180 $this->assertNull( $provider->provideSessionInfo( new \FauxRequest
) );
183 public function testNewSessionInfoForRequest() {
184 $provider = $this->getProvider();
185 $user = static::getTestSysop()->getUser();
186 $request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
187 $request->expects( $this->any() )->method( 'getIP' )
188 ->will( $this->returnValue( '127.0.0.1' ) );
189 $bp = \BotPassword
::newFromUser( $user, 'BotPasswordSessionProvider' );
191 $session = $provider->newSessionForRequest( $user, $bp, $request );
192 $this->assertInstanceOf( Session
::class, $session );
194 $this->assertEquals( $session->getId(), $request->getSession()->getId() );
195 $this->assertEquals( $user->getName(), $session->getUser()->getName() );
197 $this->assertEquals( [
198 'centralId' => $bp->getUserCentralId(),
199 'appId' => $bp->getAppId(),
200 'token' => $bp->getToken(),
201 'rights' => [ 'read' ],
202 ], $session->getProviderMetadata() );
204 $this->assertEquals( [ 'read' ], $session->getAllowedUserRights() );
207 public function testCheckSessionInfo() {
208 $logger = new \
TestLogger( true );
209 $provider = $this->getProvider();
210 $provider->setLogger( $logger );
212 $user = static::getTestSysop()->getUser();
213 $request = $this->getMock( 'FauxRequest', [ 'getIP' ] );
214 $request->expects( $this->any() )->method( 'getIP' )
215 ->will( $this->returnValue( '127.0.0.1' ) );
216 $bp = \BotPassword
::newFromUser( $user, 'BotPasswordSessionProvider' );
219 'provider' => $provider,
220 'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
221 'userInfo' => UserInfo
::newFromUser( $user, true ),
222 'persisted' => false,
224 'centralId' => $bp->getUserCentralId(),
225 'appId' => $bp->getAppId(),
226 'token' => $bp->getToken(),
229 $dataMD = $data['metadata'];
231 foreach ( array_keys( $data['metadata'] ) as $key ) {
232 $data['metadata'] = $dataMD;
233 unset( $data['metadata'][$key] );
234 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
235 $metadata = $info->getProviderMetadata();
237 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
239 [ LogLevel
::INFO
, 'Session "{session}": Missing metadata: {missing}' ]
240 ], $logger->getBuffer() );
241 $logger->clearBuffer();
244 $data['metadata'] = $dataMD;
245 $data['metadata']['appId'] = 'Foobar';
246 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
247 $metadata = $info->getProviderMetadata();
248 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
250 [ LogLevel
::INFO
, 'Session "{session}": No BotPassword for {centralId} {appId}' ],
251 ], $logger->getBuffer() );
252 $logger->clearBuffer();
254 $data['metadata'] = $dataMD;
255 $data['metadata']['token'] = 'Foobar';
256 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
257 $metadata = $info->getProviderMetadata();
258 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
260 [ LogLevel
::INFO
, 'Session "{session}": BotPassword token check failed' ],
261 ], $logger->getBuffer() );
262 $logger->clearBuffer();
264 $request2 = $this->getMock( 'FauxRequest', [ 'getIP' ] );
265 $request2->expects( $this->any() )->method( 'getIP' )
266 ->will( $this->returnValue( '10.0.0.1' ) );
267 $data['metadata'] = $dataMD;
268 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
269 $metadata = $info->getProviderMetadata();
270 $this->assertFalse( $provider->refreshSessionInfo( $info, $request2, $metadata ) );
272 [ LogLevel
::INFO
, 'Session "{session}": Restrictions check failed' ],
273 ], $logger->getBuffer() );
274 $logger->clearBuffer();
276 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, $data );
277 $metadata = $info->getProviderMetadata();
278 $this->assertTrue( $provider->refreshSessionInfo( $info, $request, $metadata ) );
279 $this->assertSame( [], $logger->getBuffer() );
280 $this->assertEquals( $dataMD +
[ 'rights' => [ 'read' ] ], $metadata );
283 public function testGetAllowedUserRights() {
284 $logger = new \
TestLogger( true );
285 $provider = $this->getProvider();
286 $provider->setLogger( $logger );
288 $backend = TestUtils
::getDummySessionBackend();
289 $backendPriv = \TestingAccessWrapper
::newFromObject( $backend );
292 $provider->getAllowedUserRights( $backend );
293 $this->fail( 'Expected exception not thrown' );
294 } catch ( \InvalidArgumentException
$ex ) {
295 $this->assertSame( 'Backend\'s provider isn\'t $this', $ex->getMessage() );
298 $backendPriv->provider
= $provider;
299 $backendPriv->providerMetadata
= [ 'rights' => [ 'foo', 'bar', 'baz' ] ];
300 $this->assertSame( [ 'foo', 'bar', 'baz' ], $provider->getAllowedUserRights( $backend ) );
301 $this->assertSame( [], $logger->getBuffer() );
303 $backendPriv->providerMetadata
= [ 'foo' => 'bar' ];
304 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
308 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
309 'No provider metadata, returning no rights allowed'
311 ], $logger->getBuffer() );
312 $logger->clearBuffer();
314 $backendPriv->providerMetadata
= [ 'rights' => 'bar' ];
315 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
319 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
320 'No provider metadata, returning no rights allowed'
322 ], $logger->getBuffer() );
323 $logger->clearBuffer();
325 $backendPriv->providerMetadata
= null;
326 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
330 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
331 'No provider metadata, returning no rights allowed'
333 ], $logger->getBuffer() );
334 $logger->clearBuffer();