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