Merge "Pass in ServiceOptions to BlockManager"
[lhc/web/wiklou.git] / tests / phpunit / includes / block / BlockManagerTest.php
1 <?php
2
3 use MediaWiki\Block\BlockManager;
4 use MediaWiki\Block\DatabaseBlock;
5 use MediaWiki\Block\SystemBlock;
6 use MediaWiki\Config\ServiceOptions;
7 use MediaWiki\MediaWikiServices;
8
9 /**
10 * @group Blocking
11 * @group Database
12 * @coversDefaultClass \MediaWiki\Block\BlockManager
13 */
14 class BlockManagerTest extends MediaWikiTestCase {
15
16 /** @var User */
17 protected $user;
18
19 /** @var int */
20 protected $sysopId;
21
22 protected function setUp() {
23 parent::setUp();
24
25 $this->user = $this->getTestUser()->getUser();
26 $this->sysopId = $this->getTestSysop()->getUser()->getId();
27 $this->blockManagerConfig = [
28 'wgApplyIpBlocksToXff' => true,
29 'wgCookieSetOnAutoblock' => true,
30 'wgCookieSetOnIpBlock' => true,
31 'wgDnsBlacklistUrls' => [],
32 'wgEnableDnsBlacklist' => true,
33 'wgProxyList' => [],
34 'wgProxyWhitelist' => [],
35 'wgSecretKey' => false,
36 'wgSoftBlockRanges' => [],
37 ];
38 }
39
40 private function getBlockManager( $overrideConfig ) {
41 return new BlockManager(
42 ...$this->getBlockManagerConstructorArgs( $overrideConfig )
43 );
44 }
45
46 private function getBlockManagerConstructorArgs( $overrideConfig ) {
47 $blockManagerConfig = array_merge( $this->blockManagerConfig, $overrideConfig );
48 $this->setMwGlobals( $blockManagerConfig );
49 $this->overrideMwServices();
50 return [
51 new ServiceOptions(
52 BlockManager::$constructorOptions,
53 MediaWikiServices::getInstance()->getMainConfig()
54 ),
55 $this->user,
56 $this->user->getRequest()
57 ];
58 }
59
60 /**
61 * @dataProvider provideGetBlockFromCookieValue
62 * @covers ::getBlockFromCookieValue
63 * @covers ::shouldApplyCookieBlock
64 */
65 public function testGetBlockFromCookieValue( $options, $expected ) {
66 $blockManager = $this->getBlockManager( [
67 'wgCookieSetOnAutoblock' => true,
68 'wgCookieSetOnIpBlock' => true,
69 ] );
70
71 $block = new DatabaseBlock( array_merge( [
72 'address' => $options[ 'target' ] ?: $this->user,
73 'by' => $this->sysopId,
74 ], $options[ 'blockOptions' ] ) );
75 $block->insert();
76
77 $class = new ReflectionClass( BlockManager::class );
78 $method = $class->getMethod( 'getBlockFromCookieValue' );
79 $method->setAccessible( true );
80
81 $user = $options[ 'loggedIn' ] ? $this->user : new User();
82 $user->getRequest()->setCookie( 'BlockID', $block->getCookieValue() );
83
84 $this->assertSame( $expected, (bool)$method->invoke(
85 $blockManager,
86 $user,
87 $user->getRequest()
88 ) );
89
90 $block->delete();
91 }
92
93 public static function provideGetBlockFromCookieValue() {
94 return [
95 'Autoblocking user block' => [
96 [
97 'target' => '',
98 'loggedIn' => true,
99 'blockOptions' => [
100 'enableAutoblock' => true
101 ],
102 ],
103 true,
104 ],
105 'Non-autoblocking user block' => [
106 [
107 'target' => '',
108 'loggedIn' => true,
109 'blockOptions' => [],
110 ],
111 false,
112 ],
113 'IP block for anonymous user' => [
114 [
115 'target' => '127.0.0.1',
116 'loggedIn' => false,
117 'blockOptions' => [],
118 ],
119 true,
120 ],
121 'IP block for logged in user' => [
122 [
123 'target' => '127.0.0.1',
124 'loggedIn' => true,
125 'blockOptions' => [],
126 ],
127 false,
128 ],
129 'IP range block for anonymous user' => [
130 [
131 'target' => '127.0.0.0/8',
132 'loggedIn' => false,
133 'blockOptions' => [],
134 ],
135 true,
136 ],
137 ];
138 }
139
140 /**
141 * @dataProvider provideIsLocallyBlockedProxy
142 * @covers ::isLocallyBlockedProxy
143 */
144 public function testIsLocallyBlockedProxy( $proxyList, $expected ) {
145 $class = new ReflectionClass( BlockManager::class );
146 $method = $class->getMethod( 'isLocallyBlockedProxy' );
147 $method->setAccessible( true );
148
149 $blockManager = $this->getBlockManager( [
150 'wgProxyList' => $proxyList
151 ] );
152
153 $ip = '1.2.3.4';
154 $this->assertSame( $expected, $method->invoke( $blockManager, $ip ) );
155 }
156
157 public static function provideIsLocallyBlockedProxy() {
158 return [
159 'Proxy list is empty' => [ [], false ],
160 'Proxy list contains IP' => [ [ '1.2.3.4' ], true ],
161 'Proxy list contains IP as value' => [ [ 'test' => '1.2.3.4' ], true ],
162 'Proxy list contains range that covers IP' => [ [ '1.2.3.0/16' ], true ],
163 ];
164 }
165
166 /**
167 * @covers ::isLocallyBlockedProxy
168 */
169 public function testIsLocallyBlockedProxyDeprecated() {
170 $proxy = '1.2.3.4';
171
172 $this->hideDeprecated(
173 'IP addresses in the keys of $wgProxyList (found the following IP ' .
174 'addresses in keys: ' . $proxy . ', please move them to values)'
175 );
176
177 $class = new ReflectionClass( BlockManager::class );
178 $method = $class->getMethod( 'isLocallyBlockedProxy' );
179 $method->setAccessible( true );
180
181 $blockManager = $this->getBlockManager( [
182 'wgProxyList' => [ $proxy => 'test' ]
183 ] );
184
185 $ip = '1.2.3.4';
186 $this->assertSame( true, $method->invoke( $blockManager, $ip ) );
187 }
188
189 /**
190 * @dataProvider provideIsDnsBlacklisted
191 * @covers ::isDnsBlacklisted
192 * @covers ::inDnsBlacklist
193 */
194 public function testIsDnsBlacklisted( $options, $expected ) {
195 $blockManagerConfig = [
196 'wgEnableDnsBlacklist' => true,
197 'wgDnsBlacklistUrls' => $options['blacklist'],
198 'wgProxyWhitelist' => $options['whitelist'],
199 ];
200
201 $blockManager = $this->getMockBuilder( BlockManager::class )
202 ->setConstructorArgs( $this->getBlockManagerConstructorArgs( $blockManagerConfig ) )
203 ->setMethods( [ 'checkHost' ] )
204 ->getMock();
205
206 $blockManager->expects( $this->any() )
207 ->method( 'checkHost' )
208 ->will( $this->returnValueMap( [ [
209 $options['dnsblQuery'],
210 $options['dnsblResponse'],
211 ] ] ) );
212
213 $this->assertSame(
214 $expected,
215 $blockManager->isDnsBlacklisted( $options['ip'], $options['checkWhitelist'] )
216 );
217 }
218
219 public static function provideIsDnsBlacklisted() {
220 $dnsblFound = [ '127.0.0.2' ];
221 $dnsblNotFound = false;
222 return [
223 'IP is blacklisted' => [
224 [
225 'blacklist' => [ 'dnsbl.test' ],
226 'ip' => '127.0.0.1',
227 'dnsblQuery' => '1.0.0.127.dnsbl.test',
228 'dnsblResponse' => $dnsblFound,
229 'whitelist' => [],
230 'checkWhitelist' => false,
231 ],
232 true,
233 ],
234 'IP is blacklisted; blacklist has key' => [
235 [
236 'blacklist' => [ [ 'dnsbl.test', 'key' ] ],
237 'ip' => '127.0.0.1',
238 'dnsblQuery' => 'key.1.0.0.127.dnsbl.test',
239 'dnsblResponse' => $dnsblFound,
240 'whitelist' => [],
241 'checkWhitelist' => false,
242 ],
243 true,
244 ],
245 'IP is blacklisted; blacklist is array' => [
246 [
247 'blacklist' => [ [ 'dnsbl.test' ] ],
248 'ip' => '127.0.0.1',
249 'dnsblQuery' => '1.0.0.127.dnsbl.test',
250 'dnsblResponse' => $dnsblFound,
251 'whitelist' => [],
252 'checkWhitelist' => false,
253 ],
254 true,
255 ],
256 'IP is not blacklisted' => [
257 [
258 'blacklist' => [ 'dnsbl.test' ],
259 'ip' => '1.2.3.4',
260 'dnsblQuery' => '4.3.2.1.dnsbl.test',
261 'dnsblResponse' => $dnsblNotFound,
262 'whitelist' => [],
263 'checkWhitelist' => false,
264 ],
265 false,
266 ],
267 'Blacklist is empty' => [
268 [
269 'blacklist' => [],
270 'ip' => '127.0.0.1',
271 'dnsblQuery' => '1.0.0.127.dnsbl.test',
272 'dnsblResponse' => $dnsblFound,
273 'whitelist' => [],
274 'checkWhitelist' => false,
275 ],
276 false,
277 ],
278 'IP is blacklisted and whitelisted; whitelist is not checked' => [
279 [
280 'blacklist' => [ 'dnsbl.test' ],
281 'ip' => '127.0.0.1',
282 'dnsblQuery' => '1.0.0.127.dnsbl.test',
283 'dnsblResponse' => $dnsblFound,
284 'whitelist' => [ '127.0.0.1' ],
285 'checkWhitelist' => false,
286 ],
287 true,
288 ],
289 'IP is blacklisted and whitelisted; whitelist is checked' => [
290 [
291 'blacklist' => [ 'dnsbl.test' ],
292 'ip' => '127.0.0.1',
293 'dnsblQuery' => '1.0.0.127.dnsbl.test',
294 'dnsblResponse' => $dnsblFound,
295 'whitelist' => [ '127.0.0.1' ],
296 'checkWhitelist' => true,
297 ],
298 false,
299 ],
300 ];
301 }
302
303 /**
304 * @covers ::getUniqueBlocks
305 */
306 public function testGetUniqueBlocks() {
307 $blockId = 100;
308
309 $class = new ReflectionClass( BlockManager::class );
310 $method = $class->getMethod( 'getUniqueBlocks' );
311 $method->setAccessible( true );
312
313 $blockManager = $this->getBlockManager( [] );
314
315 $block = $this->getMockBuilder( DatabaseBlock::class )
316 ->setMethods( [ 'getId' ] )
317 ->getMock();
318 $block->expects( $this->any() )
319 ->method( 'getId' )
320 ->willReturn( $blockId );
321
322 $autoblock = $this->getMockBuilder( DatabaseBlock::class )
323 ->setMethods( [ 'getParentBlockId', 'getType' ] )
324 ->getMock();
325 $autoblock->expects( $this->any() )
326 ->method( 'getParentBlockId' )
327 ->willReturn( $blockId );
328 $autoblock->expects( $this->any() )
329 ->method( 'getType' )
330 ->willReturn( DatabaseBlock::TYPE_AUTO );
331
332 $blocks = [ $block, $block, $autoblock, new SystemBlock() ];
333
334 $this->assertSame( 2, count( $method->invoke( $blockManager, $blocks ) ) );
335 }
336
337 /**
338 * @covers ::trackBlockWithCookie
339 * @dataProvider provideTrackBlockWithCookie
340 * @param bool $expectCookieSet
341 * @param bool $hasCookie
342 * @param bool $isBlocked
343 */
344 public function testTrackBlockWithCookie( $expectCookieSet, $hasCookie, $isBlocked ) {
345 $blockID = 123;
346 $this->setMwGlobals( 'wgCookiePrefix', '' );
347
348 $request = new FauxRequest();
349 if ( $hasCookie ) {
350 $request->setCookie( 'BlockID', 'the value does not matter' );
351 }
352
353 if ( $isBlocked ) {
354 $block = $this->getMockBuilder( DatabaseBlock::class )
355 ->setMethods( [ 'getType', 'getId' ] )
356 ->getMock();
357 $block->method( 'getType' )
358 ->willReturn( DatabaseBlock::TYPE_IP );
359 $block->method( 'getId' )
360 ->willReturn( $blockID );
361 } else {
362 $block = null;
363 }
364
365 $user = $this->getMockBuilder( User::class )
366 ->setMethods( [ 'getBlock', 'getRequest' ] )
367 ->getMock();
368 $user->method( 'getBlock' )
369 ->willReturn( $block );
370 $user->method( 'getRequest' )
371 ->willReturn( $request );
372 /** @var User $user */
373
374 // Although the block cookie is set via DeferredUpdates, in command line mode updates are
375 // processed immediately
376 $blockManager = $this->getBlockManager( [] );
377 $blockManager->trackBlockWithCookie( $user );
378
379 /** @var FauxResponse $response */
380 $response = $request->response();
381 $this->assertCount( $expectCookieSet ? 1 : 0, $response->getCookies() );
382 $this->assertEquals( $expectCookieSet ? $blockID : null, $response->getCookie( 'BlockID' ) );
383 }
384
385 public function provideTrackBlockWithCookie() {
386 return [
387 // $expectCookieSet, $hasCookie, $isBlocked
388 [ false, false, false ],
389 [ false, true, false ],
390 [ true, false, true ],
391 [ false, true, true ],
392 ];
393 }
394 }