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