Completed
Push — master ( df8989...bc4c56 )
by Jonathan
07:56
created

testSetSourceArrayOverridesServerSuperglobal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 10
Ratio 100 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 1
eloc 7
c 3
b 1
f 0
nc 1
nop 0
dl 10
loc 10
rs 9.4285
1
<?php
2
/*
3
The MIT License (MIT)
4
5
Copyright (c) 2015 Vectorface, Inc.
6
7
Permission is hereby granted, free of charge, to any person obtaining a copy
8
of this software and associated documentation files (the "Software"), to deal
9
in the Software without restriction, including without limitation the rights
10
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
copies of the Software, and to permit persons to whom the Software is
12
furnished to do so, subject to the following conditions:
13
14
The above copyright notice and this permission notice shall be included in
15
all copies or substantial portions of the Software.
16
17
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
THE SOFTWARE.
24
*/
25
namespace Vectorface\WhipTests;
26
27
use PHPUnit_Framework_TestCase;
28
use Vectorface\Whip\Whip;
29
use Vectorface\Whip\IpRange\IpWhitelist;
30
use Psr\Http\Message\ServerRequestInterface;
31
32
/**
33
 * Test class for testing Whip.
34
 * @backupGlobals enabled
35
 * @copyright Vectorface, Inc 2015
36
 * @author Daniel Bruce <[email protected]>
37
 */
38
class WhipTest extends PHPUnit_Framework_TestCase
39
{
40
    /**
41
     * Tests that an invalid source format is rejected.
42
     * @expectedException \InvalidArgumentException
43
     */
44
    public function testInvalidSource()
45
    {
46
        new Whip(Whip::REMOTE_ADDR, array(), new \stdClass());
47
    }
48
    /**
49
     * Tests that we get back the right IP when there using superglobals.
50
     */
51
    public function testSuperglobal()
0 ignored issues
show
Coding Style introduced by
testSuperglobal uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
52
    {
53
        $_SERVER = array('REMOTE_ADDR' => '24.24.24.24');
54
        $lookup = new Whip(Whip::REMOTE_ADDR);
55
        $this->assertEquals('24.24.24.24', $lookup->getValidIpAddress());
56
    }
57
58
    /**
59
     * Tests that we get back 127.0.0.1 when there is no superglobal information
60
     * at all.
61
     */
62
    public function testEmptySuperglobal()
0 ignored issues
show
Coding Style introduced by
testEmptySuperglobal uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
63
    {
64
        $_SERVER = array();
65
        $lookup = new Whip();
66
        $this->assertFalse($lookup->getIpAddress());
67
    }
68
69
    /**
70
     * Helper to get a mocked PSR-7 instance.
71
     *
72
     * @param string $remoteAddr The remote address to mock.
73
     * @param string[][] $headers The headers, in the format expected by Psr-7.
74
     */
75
    private function getHttpMessageMock($remoteAddr, array $headers = array())
76
    {
77
        $stub = $this->getMockBuilder("Psr\Http\Message\ServerRequestInterface")
78
            ->getMock();
79
80
        $stub->method('getServerParams')
81
            ->willReturn(array('REMOTE_ADDR' => $remoteAddr));
82
        $stub->method('getHeaders')
83
            ->willReturn($headers);
84
85
        return $stub;
86
    }
87
    /**
88
     * Tests that we can use a PSR-7 ServerRequestInterface compatible class.
89
     */
90
    public function testPsr7Request()
91
    {
92
        $lookup = new Whip(
93
            Whip::PROXY_HEADERS,
94
            array(
95
                Whip::PROXY_HEADERS => array(
96
                    IpWhitelist::IPV4 => array(
97
                        '127.0.0.1'
98
                    )
99
                )
100
            ),
101
            $this->getHttpMessageMock("127.0.0.1", array('X-Forwarded-For' => array('192.168.1.1,32.32.32.32')))
102
        );
103
104
        $this->assertEquals('32.32.32.32', $lookup->getIpAddress());
105
    }
106
107
    /**
108
     * Tests that we get false when no valid IP address could be found.
109
     */
110
    public function testNoAddresFoundDueToBitmask()
111
    {
112
        $lookup = new Whip(Whip::PROXY_HEADERS);
113
        $lookup->setSource(array('REMOTE_ADDR' => '127.0.0.1'));
114
        $this->assertFalse($lookup->getIpAddress());
115
    }
116
117
    /**
118
     * Tests the standard REMOTE_ADDR method.
119
     */
120
    public function testRemoteAddrMethod()
121
    {
122
        $lookup = new Whip(Whip::REMOTE_ADDR);
123
        $lookup->setSource(array('REMOTE_ADDR' => '24.24.24.24'));
124
        $this->assertEquals('24.24.24.24', $lookup->getValidIpAddress());
125
    }
126
127
    /**
128
     * Tests that an invalid IPv4 address returns false.
129
     */
130
    public function testInvalidIPv4Address()
131
    {
132
        $lookup = new Whip(Whip::REMOTE_ADDR);
133
        $lookup->setSource(array('REMOTE_ADDR' => '127.0.0.256'));
134
        $this->assertFalse($lookup->getValidIpAddress());
135
    }
136
137
    /**
138
     * Tests a valid IPv6 address.
139
     */
140
    public function testValidIPv6Address()
141
    {
142
        $lookup = new Whip(Whip::REMOTE_ADDR);
143
        $lookup->setSource(array('REMOTE_ADDR' => '::1'));
144
        $this->assertEquals('::1', $lookup->getValidIpAddress());
145
    }
146
147
    /**
148
     * Tests that we accept whitelisted proxy methods when the IP matches, even
149
     * if the IP listed is a comma separated list.
150
     *
151
     * @dataProvider proxyMethodWhitelistProvider
152
     */
153 View Code Duplication
    public function testValidWhitelistedProxyMethod($remoteAddr)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
    {
155
        $lookup = new Whip(
156
            Whip::PROXY_HEADERS,
157
            array(
158
                Whip::PROXY_HEADERS => array(
159
                    IpWhitelist::IPV4 => array('127.0.0.1'),
160
                    IpWhitelist::IPV6 => array('::1')
161
                )
162
            ),
163
            array(
164
                'REMOTE_ADDR' => $remoteAddr,
165
                'HTTP_X_FORWARDED_FOR' => '192.168.1.1,32.32.32.32'
166
            )
167
        );
168
        $this->assertEquals('32.32.32.32', $lookup->getIpAddress());
169
    }
170
171
    /**
172
     * Repeats the above test twice for ipv4 and ipv6
173
     */
174
    public function proxyMethodWhitelistProvider()
175
    {
176
        return array(
177
            array('127.0.0.1'),
178
            array('::1'),
179
        );
180
    }
181
182
    /**
183
     * Tests that we accept proxy method based on a whitelisted IP using the
184
     * dashed range notation.
185
     */
186 View Code Duplication
    public function testValidWhitelistedProxyMethodWithDashNotation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
    {
188
        $lookup = new Whip(
189
            Whip::PROXY_HEADERS,
190
            array(
191
                Whip::PROXY_HEADERS => array(
192
                    IpWhitelist::IPV4 => array(
193
                        '127.0.0.0-127.0.255.255',
194
                    ),
195
                    IpWhitelist::IPV6 => array(
196
                        '::1'
197
                    )
198
                )
199
            ),
200
            array(
201
                'REMOTE_ADDR' => '127.0.0.1',
202
                'HTTP_X_FORWARDED_FOR' => '32.32.32.32'
203
            )
204
        );
205
        $this->assertEquals('32.32.32.32', $lookup->getIpAddress());
206
    }
207
208
    /**
209
     * Tests that we accept proxy method based on a whitelisted IP using the
210
     * wildcard asterix notation.
211
     */
212 View Code Duplication
    public function testValidWhitelistedProxyMethodWithWildcardNotation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
213
    {
214
        $lookup = new Whip(
215
            Whip::PROXY_HEADERS,
216
            array(
217
                Whip::PROXY_HEADERS => array(
218
                    IpWhitelist::IPV4 => array(
219
                        '127.0.*'
220
                    ),
221
                    IpWhitelist::IPV6 => array(
222
                        '::1'
223
                    )
224
                )
225
            ),
226
            array(
227
                'REMOTE_ADDR' => '127.0.0.1',
228
                'HTTP_X_FORWARDED_FOR' => '32.32.32.32'
229
            )
230
        );
231
        $this->assertEquals('32.32.32.32', $lookup->getIpAddress());
232
    }
233
234
    /**
235
     * Tests that we accept proxy method based on a whitelisted IP using the
236
     * CIDR address notation.
237
     */
238 View Code Duplication
    public function testValidWhitelistedProxyMethodWithCIDRdNotation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
    {
240
        $lookup = new Whip(
241
            Whip::PROXY_HEADERS,
242
            array(
243
                Whip::PROXY_HEADERS => array(
244
                    IpWhitelist::IPV4 => array(
245
                        '127.0.0.0/24'
246
                    ),
247
                    IpWhitelist::IPV6 => array(
248
                        '::1'
249
                    )
250
                )
251
            ),
252
            array(
253
                'REMOTE_ADDR' => '127.0.0.1',
254
                'HTTP_X_FORWARDED_FOR' => '32.32.32.32'
255
            )
256
        );
257
        $this->assertEquals('32.32.32.32', $lookup->getIpAddress());
258
    }
259
260
    /**
261
     * Tests that we get false if there is a valid IP in a proxy header but
262
     * we reject it due to REMOTE_ADDR not being in the whitelist.
263
     */
264 View Code Duplication
    public function testValidIpRejectedDueToWhitelist()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
265
    {
266
        $lookup = new Whip(
267
            Whip::PROXY_HEADERS,
268
            array(
269
                Whip::PROXY_HEADERS => array(
270
                    IpWhitelist::IPV4 => array(
271
                        '127.0.0.1/24'
272
                    ),
273
                    IpWhitelist::IPV6 => array(
274
                        '::1'
275
                    )
276
                )
277
            ),
278
            array(
279
                'REMOTE_ADDR' => '24.24.24.24',
280
                'HTTP_X_FORWARDED_FOR' => '32.32.32.32'
281
            )
282
        );
283
        $this->assertFalse($lookup->getIpAddress());
284
    }
285
286
    /**
287
     * Tests that we reject a proxy listed IPv6 address that does not fall within
288
     * the allowed subnet.
289
     */
290
    public function testIPv6AddressRejectedDueToWhitelist()
291
    {
292
        $lookup = new Whip(
293
            Whip::PROXY_HEADERS,
294
            array(
295
                Whip::PROXY_HEADERS => array(
296
                    IpWhitelist::IPV6 => array(
297
                        '2400:cb00::/32'
298
                    )
299
                )
300
            ),
301
            array(
302
                'REMOTE_ADDR' => '::1',
303
                'HTTP_X_FORWARDED_FOR' => '::1'
304
            )
305
        );
306
        $this->assertFalse($lookup->getIpAddress());
307
    }
308
309
    /**
310
     * Tests that we reject a proxy listed IPv6 address that does not fall within
311
     * the allowed subnet.
312
     */
313
    public function testIPv6AddressFoundInWhitelist()
314
    {
315
        $lookup = new Whip(
316
            Whip::PROXY_HEADERS,
317
            array(
318
                Whip::PROXY_HEADERS => array(
319
                    IpWhitelist::IPV6 => array(
320
                        '::1/32'
321
                    )
322
                )
323
            ),
324
            array(
325
                'REMOTE_ADDR' => '::1',
326
                'HTTP_X_FORWARDED_FOR' => '::1'
327
            )
328
        );
329
        $this->assertEquals('::1', $lookup->getIpAddress());
330
    }
331
332
    /**
333
     * Test that an IPv4 address is rejected because the whitelist is empty for
334
     * IPv4.
335
     */
336
    public function testIPv4AddressRejectedDueToEmptyWhitelist()
337
    {
338
        $lookup = new Whip(
339
            Whip::PROXY_HEADERS,
340
            array(
341
                Whip::PROXY_HEADERS => array(
342
                    IpWhitelist::IPV6 => array(
343
                        '::1/32'
344
                    )
345
                )
346
            ),
347
            array(
348
                'REMOTE_ADDR' => '127.0.0.1',
349
                'HTTP_X_FORWARDED_FOR' => '24.24.24.24'
350
            )
351
        );
352
        $this->assertFalse($lookup->getIpAddress());
353
    }
354
355
    /**
356
     * Test that an IPv6 address is rejected because the whitelist is empty for
357
     * IPv6.
358
     */
359
    public function testIPv6AddressRejectedDueToEmptyWhitelist()
360
    {
361
        $lookup = new Whip(
362
            Whip::PROXY_HEADERS,
363
            array(
364
                Whip::PROXY_HEADERS => array(
365
                    IpWhitelist::IPV4 => array(
366
                        '127.0.0.0/24'
367
                    )
368
                )
369
            ),
370
            array(
371
                'REMOTE_ADDR' => '::1',
372
                'HTTP_X_FORWARDED_FOR' => '::1'
373
            )
374
        );
375
        $this->assertFalse($lookup->getIpAddress());
376
    }
377
378
    /**
379
     * Test a custom header with a whitelisted IP.
380
     */
381 View Code Duplication
    public function testCustomHeader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
382
    {
383
        $lookup = new Whip(
384
            Whip::CUSTOM_HEADERS | Whip::REMOTE_ADDR,
385
            array(
386
                Whip::CUSTOM_HEADERS => array(
387
                    IpWhitelist::IPV4 => array(
388
                        '127.0.0.1',
389
                        '::1'
390
                    )
391
                )
392
            ),
393
            array(
394
                'REMOTE_ADDR' => '127.0.0.1',
395
                'HTTP_CUSTOM_SECRET_HEADER' => '32.32.32.32'
396
            )
397
        );
398
        $this->assertEquals(
399
            '32.32.32.32',
400
            $lookup->addCustomHeader('HTTP_CUSTOM_SECRET_HEADER')->getIpAddress()
401
        );
402
    }
403
404
    /**
405
     * Test HTTP_X_REAL_IP header.
406
     */
407
    public function testHttpXRealIpHeader()
408
    {
409
        $lookup = new Whip(
410
            Whip::PROXY_HEADERS | Whip::REMOTE_ADDR,
411
            array(),
412
            array(
413
                'REMOTE_ADDR' => '127.0.0.1',
414
                'HTTP_X_REAL_IP' => '24.24.24.24'
415
            )
416
        );
417
        $this->assertEquals('24.24.24.24', $lookup->getIpAddress());
418
    }
419
420
    /**
421
     * Tests that if we specify the source array, it overrides any values found
422
     * in the $_SERVER array.
423
     */
424 View Code Duplication
    public function testSourceArrayOverridesServerSuperglobal()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
425
    {
426
        $source = array(
427
            'REMOTE_ADDR' => '24.24.24.24'
428
        );
429
        $lookup = new Whip(Whip::REMOTE_ADDR, array(), array('REMOTE_ADDR' => '127.0.0.1'));
430
        $this->assertNotEquals($source['REMOTE_ADDR'], $lookup->getIpAddress());
431
        $this->assertEquals($source['REMOTE_ADDR'], $lookup->getIpAddress($source));
432
    }
433
434
    /**
435
     * Tests that if we specify the source array through Whip::setSource, the
436
     * class will override any values found in $_SERVER.
437
     */
438 View Code Duplication
    public function testSetSourceArrayOverridesServerSuperglobal()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
439
    {
440
        $source = array(
441
            'REMOTE_ADDR' => '24.24.24.24'
442
        );
443
        $lookup = new Whip(Whip::REMOTE_ADDR, array(), array('REMOTE_ADDR' => '127.0.0.1'));
444
        $this->assertNotEquals($source['REMOTE_ADDR'], $lookup->getIpAddress());
445
        $lookup->setSource($source);
446
        $this->assertEquals($source['REMOTE_ADDR'], $lookup->getIpAddress());
447
    }
448
}
449