]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - tests/phpunit/includes/session/BotPasswordSessionProviderTest.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / tests / phpunit / includes / session / BotPasswordSessionProviderTest.php
1 <?php
2
3 namespace MediaWiki\Session;
4
5 use Psr\Log\LogLevel;
6 use MediaWikiTestCase;
7 use Wikimedia\TestingAccessWrapper;
8
9 /**
10  * @group Session
11  * @group Database
12  * @covers MediaWiki\Session\BotPasswordSessionProvider
13  */
14 class BotPasswordSessionProviderTest extends MediaWikiTestCase {
15
16         private $config;
17
18         private function getProvider( $name = null, $prefix = null ) {
19                 global $wgSessionProviders;
20
21                 $params = [
22                         'priority' => 40,
23                         'sessionCookieName' => $name,
24                         'sessionCookieOptions' => [],
25                 ];
26                 if ( $prefix !== null ) {
27                         $params['sessionCookieOptions']['prefix'] = $prefix;
28                 }
29
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 ],
39                                         ]
40                                 ],
41                         ] );
42                 }
43                 $manager = new SessionManager( [
44                         'config' => new \MultiConfig( [ $this->config, \RequestContext::getMain()->getConfig() ] ),
45                         'logger' => new \Psr\Log\NullLogger,
46                         'store' => new TestBagOStuff,
47                 ] );
48
49                 return $manager->getProvider( BotPasswordSessionProvider::class );
50         }
51
52         protected function setUp() {
53                 parent::setUp();
54
55                 $this->setMwGlobals( [
56                         'wgEnableBotPasswords' => true,
57                         'wgBotPasswordsDatabase' => false,
58                         'wgCentralIdLookupProvider' => 'local',
59                         'wgGrantPermissions' => [
60                                 'test' => [ 'read' => true ],
61                         ],
62                 ] );
63         }
64
65         public function addDBDataOnce() {
66                 $passwordFactory = new \PasswordFactory();
67                 $passwordFactory->init( \RequestContext::getMain()->getConfig() );
68                 $passwordHash = $passwordFactory->newFromPlaintext( 'foobaz' );
69
70                 $sysop = static::getTestSysop()->getUser();
71                 $userId = \CentralIdLookup::factory( 'local' )->centralIdFromName( $sysop->getName() );
72
73                 $dbw = wfGetDB( DB_MASTER );
74                 $dbw->delete(
75                         'bot_passwords',
76                         [ 'bp_user' => $userId, 'bp_app_id' => 'BotPasswordSessionProvider' ],
77                         __METHOD__
78                 );
79                 $dbw->insert(
80                         'bot_passwords',
81                         [
82                                 'bp_user' => $userId,
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"]',
88                         ],
89                         __METHOD__
90                 );
91         }
92
93         public function testConstructor() {
94                 try {
95                         $provider = new BotPasswordSessionProvider();
96                         $this->fail( 'Expected exception not thrown' );
97                 } catch ( \InvalidArgumentException $ex ) {
98                         $this->assertSame(
99                                 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: priority must be specified',
100                                 $ex->getMessage()
101                         );
102                 }
103
104                 try {
105                         $provider = new BotPasswordSessionProvider( [
106                                 'priority' => SessionInfo::MIN_PRIORITY - 1
107                         ] );
108                         $this->fail( 'Expected exception not thrown' );
109                 } catch ( \InvalidArgumentException $ex ) {
110                         $this->assertSame(
111                                 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
112                                 $ex->getMessage()
113                         );
114                 }
115
116                 try {
117                         $provider = new BotPasswordSessionProvider( [
118                                 'priority' => SessionInfo::MAX_PRIORITY + 1
119                         ] );
120                         $this->fail( 'Expected exception not thrown' );
121                 } catch ( \InvalidArgumentException $ex ) {
122                         $this->assertSame(
123                                 'MediaWiki\\Session\\BotPasswordSessionProvider::__construct: Invalid priority',
124                                 $ex->getMessage()
125                         );
126                 }
127
128                 $provider = new BotPasswordSessionProvider( [
129                         'priority' => 40
130                 ] );
131                 $priv = TestingAccessWrapper::newFromObject( $provider );
132                 $this->assertSame( 40, $priv->priority );
133                 $this->assertSame( '_BPsession', $priv->sessionCookieName );
134                 $this->assertSame( [], $priv->sessionCookieOptions );
135
136                 $provider = new BotPasswordSessionProvider( [
137                         'priority' => 40,
138                         'sessionCookieName' => null,
139                 ] );
140                 $priv = TestingAccessWrapper::newFromObject( $provider );
141                 $this->assertSame( '_BPsession', $priv->sessionCookieName );
142
143                 $provider = new BotPasswordSessionProvider( [
144                         'priority' => 40,
145                         'sessionCookieName' => 'Foo',
146                         'sessionCookieOptions' => [ 'Bar' ],
147                 ] );
148                 $priv = TestingAccessWrapper::newFromObject( $provider );
149                 $this->assertSame( 'Foo', $priv->sessionCookieName );
150                 $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions );
151         }
152
153         public function testBasics() {
154                 $provider = $this->getProvider();
155
156                 $this->assertTrue( $provider->persistsSessionId() );
157                 $this->assertFalse( $provider->canChangeUser() );
158
159                 $this->assertNull( $provider->newSessionInfo() );
160                 $this->assertNull( $provider->newSessionInfo( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) );
161         }
162
163         public function testProvideSessionInfo() {
164                 $provider = $this->getProvider();
165                 $request = new \FauxRequest;
166                 $request->setCookie( '_BPsession', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'wgCookiePrefix' );
167
168                 if ( !defined( 'MW_API' ) ) {
169                         $this->assertNull( $provider->provideSessionInfo( $request ) );
170                         define( 'MW_API', 1 );
171                 }
172
173                 $info = $provider->provideSessionInfo( $request );
174                 $this->assertInstanceOf( SessionInfo::class, $info );
175                 $this->assertSame( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $info->getId() );
176
177                 $this->config->set( 'EnableBotPasswords', false );
178                 $this->assertNull( $provider->provideSessionInfo( $request ) );
179                 $this->config->set( 'EnableBotPasswords', true );
180
181                 $this->assertNull( $provider->provideSessionInfo( new \FauxRequest ) );
182         }
183
184         public function testNewSessionInfoForRequest() {
185                 $provider = $this->getProvider();
186                 $user = static::getTestSysop()->getUser();
187                 $request = $this->getMockBuilder( 'FauxRequest' )
188                         ->setMethods( [ 'getIP' ] )->getMock();
189                 $request->expects( $this->any() )->method( 'getIP' )
190                         ->will( $this->returnValue( '127.0.0.1' ) );
191                 $bp = \BotPassword::newFromUser( $user, 'BotPasswordSessionProvider' );
192
193                 $session = $provider->newSessionForRequest( $user, $bp, $request );
194                 $this->assertInstanceOf( Session::class, $session );
195
196                 $this->assertEquals( $session->getId(), $request->getSession()->getId() );
197                 $this->assertEquals( $user->getName(), $session->getUser()->getName() );
198
199                 $this->assertEquals( [
200                         'centralId' => $bp->getUserCentralId(),
201                         'appId' => $bp->getAppId(),
202                         'token' => $bp->getToken(),
203                         'rights' => [ 'read' ],
204                 ], $session->getProviderMetadata() );
205
206                 $this->assertEquals( [ 'read' ], $session->getAllowedUserRights() );
207         }
208
209         public function testCheckSessionInfo() {
210                 $logger = new \TestLogger( true );
211                 $provider = $this->getProvider();
212                 $provider->setLogger( $logger );
213
214                 $user = static::getTestSysop()->getUser();
215                 $request = $this->getMockBuilder( 'FauxRequest' )
216                         ->setMethods( [ 'getIP' ] )->getMock();
217                 $request->expects( $this->any() )->method( 'getIP' )
218                         ->will( $this->returnValue( '127.0.0.1' ) );
219                 $bp = \BotPassword::newFromUser( $user, 'BotPasswordSessionProvider' );
220
221                 $data = [
222                         'provider' => $provider,
223                         'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
224                         'userInfo' => UserInfo::newFromUser( $user, true ),
225                         'persisted' => false,
226                         'metadata' => [
227                                 'centralId' => $bp->getUserCentralId(),
228                                 'appId' => $bp->getAppId(),
229                                 'token' => $bp->getToken(),
230                         ],
231                 ];
232                 $dataMD = $data['metadata'];
233
234                 foreach ( array_keys( $data['metadata'] ) as $key ) {
235                         $data['metadata'] = $dataMD;
236                         unset( $data['metadata'][$key] );
237                         $info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
238                         $metadata = $info->getProviderMetadata();
239
240                         $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
241                         $this->assertSame( [
242                                 [ LogLevel::INFO, 'Session "{session}": Missing metadata: {missing}' ]
243                         ], $logger->getBuffer() );
244                         $logger->clearBuffer();
245                 }
246
247                 $data['metadata'] = $dataMD;
248                 $data['metadata']['appId'] = 'Foobar';
249                 $info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
250                 $metadata = $info->getProviderMetadata();
251                 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
252                 $this->assertSame( [
253                         [ LogLevel::INFO, 'Session "{session}": No BotPassword for {centralId} {appId}' ],
254                 ], $logger->getBuffer() );
255                 $logger->clearBuffer();
256
257                 $data['metadata'] = $dataMD;
258                 $data['metadata']['token'] = 'Foobar';
259                 $info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
260                 $metadata = $info->getProviderMetadata();
261                 $this->assertFalse( $provider->refreshSessionInfo( $info, $request, $metadata ) );
262                 $this->assertSame( [
263                         [ LogLevel::INFO, 'Session "{session}": BotPassword token check failed' ],
264                 ], $logger->getBuffer() );
265                 $logger->clearBuffer();
266
267                 $request2 = $this->getMockBuilder( 'FauxRequest' )
268                         ->setMethods( [ 'getIP' ] )->getMock();
269                 $request2->expects( $this->any() )->method( 'getIP' )
270                         ->will( $this->returnValue( '10.0.0.1' ) );
271                 $data['metadata'] = $dataMD;
272                 $info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
273                 $metadata = $info->getProviderMetadata();
274                 $this->assertFalse( $provider->refreshSessionInfo( $info, $request2, $metadata ) );
275                 $this->assertSame( [
276                         [ LogLevel::INFO, 'Session "{session}": Restrictions check failed' ],
277                 ], $logger->getBuffer() );
278                 $logger->clearBuffer();
279
280                 $info = new SessionInfo( SessionInfo::MIN_PRIORITY, $data );
281                 $metadata = $info->getProviderMetadata();
282                 $this->assertTrue( $provider->refreshSessionInfo( $info, $request, $metadata ) );
283                 $this->assertSame( [], $logger->getBuffer() );
284                 $this->assertEquals( $dataMD + [ 'rights' => [ 'read' ] ], $metadata );
285         }
286
287         public function testGetAllowedUserRights() {
288                 $logger = new \TestLogger( true );
289                 $provider = $this->getProvider();
290                 $provider->setLogger( $logger );
291
292                 $backend = TestUtils::getDummySessionBackend();
293                 $backendPriv = TestingAccessWrapper::newFromObject( $backend );
294
295                 try {
296                         $provider->getAllowedUserRights( $backend );
297                         $this->fail( 'Expected exception not thrown' );
298                 } catch ( \InvalidArgumentException $ex ) {
299                         $this->assertSame( 'Backend\'s provider isn\'t $this', $ex->getMessage() );
300                 }
301
302                 $backendPriv->provider = $provider;
303                 $backendPriv->providerMetadata = [ 'rights' => [ 'foo', 'bar', 'baz' ] ];
304                 $this->assertSame( [ 'foo', 'bar', 'baz' ], $provider->getAllowedUserRights( $backend ) );
305                 $this->assertSame( [], $logger->getBuffer() );
306
307                 $backendPriv->providerMetadata = [ 'foo' => 'bar' ];
308                 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
309                 $this->assertSame( [
310                         [
311                                 LogLevel::DEBUG,
312                                 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
313                                         'No provider metadata, returning no rights allowed'
314                         ]
315                 ], $logger->getBuffer() );
316                 $logger->clearBuffer();
317
318                 $backendPriv->providerMetadata = [ 'rights' => 'bar' ];
319                 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
320                 $this->assertSame( [
321                         [
322                                 LogLevel::DEBUG,
323                                 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
324                                         'No provider metadata, returning no rights allowed'
325                         ]
326                 ], $logger->getBuffer() );
327                 $logger->clearBuffer();
328
329                 $backendPriv->providerMetadata = null;
330                 $this->assertSame( [], $provider->getAllowedUserRights( $backend ) );
331                 $this->assertSame( [
332                         [
333                                 LogLevel::DEBUG,
334                                 'MediaWiki\\Session\\BotPasswordSessionProvider::getAllowedUserRights: ' .
335                                         'No provider metadata, returning no rights allowed'
336                         ]
337                 ], $logger->getBuffer() );
338                 $logger->clearBuffer();
339         }
340 }