Passed
Pull Request — master (#157)
by Alexander
12:42
created

testAddedTrustedHostsInvalidParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 1
eloc 9
c 3
b 0
f 1
nc 1
nop 1
dl 0
loc 11
rs 9.9666
1
<?php
2
3
namespace Yiisoft\Yii\Web\Tests\Middleware;
4
5
use Nyholm\Psr7\Factory\Psr17Factory;
6
use Nyholm\Psr7\ServerRequest;
7
use PHPUnit\Framework\TestCase;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Yiisoft\Yii\Web\Middleware\TrustedHostsNetworkResolver;
10
use Yiisoft\Yii\Web\Tests\Middleware\Mock\MockRequestHandler;
11
12
class TrustedHostsNetworkResolverTest extends TestCase
13
{
14
    protected function newRequestWithSchemaAndHeaders(
15
        string $scheme = 'http',
16
        array $headers = [],
17
        array $serverParams = []
18
    ): ServerRequestInterface {
19
        $request = new ServerRequest('GET', '/', $headers, null, '1.1', $serverParams);
20
        $uri = $request->getUri()->withScheme($scheme);
21
        return $request->withUri($uri);
22
    }
23
24
    public function trustedDataProvider(): array
25
    {
26
        return [
27
            'xForwardLevel1' => [
28
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
29
                ['REMOTE_ADDR' => '127.0.0.1'],
30
                [
31
                    ['hosts' => ['8.8.8.8', '127.0.0.1'], 'ipHeaders' => ['x-forwarded-for']]
32
                ],
33
                '2.2.2.2',
34
            ],
35
            'xForwardLevel2' => [
36
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
37
                ['REMOTE_ADDR' => '127.0.0.1'],
38
                [
39
                    ['hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'], 'ipHeaders' => ['x-forwarded-for']],
40
                ],
41
                '5.5.5.5',
42
            ],
43
            'rfc7239Level1' => [
44
                ['forwarded' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
45
                ['REMOTE_ADDR' => '127.0.0.1'],
46
                [
47
                    [
48
                        'hosts' => ['8.8.8.8', '127.0.0.1'],
49
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forwarded']],
50
                    ]
51
                ],
52
                '2.2.2.2',
53
            ],
54
            'rfc7239Level2' => [
55
                ['forwarded' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
56
                ['REMOTE_ADDR' => '127.0.0.1'],
57
                [
58
                    [
59
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
60
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forwarded']],
61
                    ],
62
63
                ],
64
                '5.5.5.5',
65
            ],
66
            'rfc7239Level2HostAndProtocol' => [
67
                ['forwarded' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2']],
68
                ['REMOTE_ADDR' => '127.0.0.1'],
69
                [
70
                    [
71
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
72
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forwarded']],
73
                        'hostHeaders' => ['forwarded'],
74
                        'protocolHeaders' => ['forwarded' => ['http' => 'http', 'https' => 'https']],
75
                    ],
76
                ],
77
                '5.5.5.5',
78
                'test',
79
                'https',
80
            ],
81
            'rfc7239Level2HostAndProtocolAndUrl' => [
82
                [
83
                    'forwarded' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2'],
84
                    'x-rewrite-url' => ['/test?test=test'],
85
                ],
86
                ['REMOTE_ADDR' => '127.0.0.1'],
87
                [
88
                    [
89
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
90
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forwarded']],
91
                        'hostHeaders' => ['forwarded'],
92
                        'protocolHeaders' => ['forwarded' => ['http' => 'http', 'https' => 'https']],
93
                        'urlHeaders' => ['x-rewrite-url'],
94
                    ],
95
                ],
96
                '5.5.5.5',
97
                'test',
98
                'https',
99
                '/test',
100
                'test=test',
101
            ],
102
            'rfc7239Level2AnotherHost&AnotherProtocol&Url' => [
103
                [
104
                    'forwarded' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2'],
105
                    'x-rewrite-url' => ['/test?test=test'],
106
                    'x-forwarded-host' => ['test.another'],
107
                    'x-forwarded-proto' => ['on']
108
                ],
109
                ['REMOTE_ADDR' => '127.0.0.1'],
110
                [
111
                    [
112
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
113
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forwarded']],
114
                        'hostHeaders' => ['x-forwarded-host', 'forwarded'],
115
                        'protocolHeaders' => [
116
                            'x-forwarded-proto' => ['http' => 'http', 'httpsss' => 'on'],
117
                            'forwarded' => ['http' => 'http', 'https' => 'https']
118
                        ],
119
                        'urlHeaders' => ['x-rewrite-url'],
120
                    ],
121
                ],
122
                '5.5.5.5',
123
                'test.another',
124
                'httpsss',
125
                '/test',
126
                'test=test',
127
            ],
128
            'rfc7239Level2AnotherHost&AnotherProtocol&Url&Port' => [
129
                [
130
                    'forwarded' => ['for=9.9.9.9', 'proto=https;for="5.5.5.5:123";host=test', 'for=2.2.2.2'],
131
                    'x-rewrite-url' => ['/test?test=test'],
132
                    'x-forwarded-host' => ['test.another'],
133
                    'x-forwarded-proto' => ['on']
134
                ],
135
                ['REMOTE_ADDR' => '127.0.0.1'],
136
                [
137
                    [
138
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
139
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forwarded']],
140
                        'hostHeaders' => ['x-forwarded-host', 'forwarded'],
141
                        'protocolHeaders' => [
142
                            'x-forwarded-proto' => ['http' => 'http', 'httpsss' => 'on'],
143
                            'forwarded' => ['http' => 'http', 'https' => 'https']
144
                        ],
145
                        'urlHeaders' => ['x-rewrite-url'],
146
                        'portHeaders' => ['forwarded'],
147
                    ],
148
                ],
149
                '5.5.5.5',
150
                'test.another',
151
                'httpsss',
152
                '/test',
153
                'test=test',
154
                123,
155
            ],
156
        ];
157
    }
158
159
    /**
160
     * @dataProvider trustedDataProvider
161
     */
162
    public function testTrusted(
163
        array $headers,
164
        array $serverParams,
165
        array $trustedHosts,
166
        string $expectedClientIp,
167
        ?string $expectedHttpHost = null,
168
        string $expectedHttpScheme = 'http',
169
        string $expectedPath = '/',
170
        string $expectedQuery = '',
171
        ?int $expectedPort = null
172
    ): void {
173
        $request = $this->newRequestWithSchemaAndHeaders('http', $headers, $serverParams);
174
        $requestHandler = new MockRequestHandler();
175
176
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
177
        foreach ($trustedHosts as $data) {
178
            $middleware = $middleware->withAddedTrustedHosts(
179
                $data['hosts'],
180
                $data['ipHeaders'] ?? [],
181
                $data['protocolHeaders'] ?? [],
182
                $data['hostHeaders'] ?? [],
183
                $data['urlHeaders'] ?? [],
184
                $data['portHeaders'] ?? [],
185
                $data['trustedHeaders'] ?? null);
186
        }
187
        $response = $middleware->process($request, $requestHandler);
188
        $this->assertSame(200, $response->getStatusCode());
189
        $this->assertSame($expectedClientIp, $requestHandler->processedRequest->getAttribute('requestClientIp'));
190
        if ($expectedHttpHost !== null) {
191
            $this->assertSame($expectedHttpHost, $requestHandler->processedRequest->getUri()->getHost());
192
        }
193
        $this->assertSame($expectedHttpScheme, $requestHandler->processedRequest->getUri()->getScheme());
194
        $this->assertSame($expectedPath, $requestHandler->processedRequest->getUri()->getPath());
195
        $this->assertSame($expectedQuery, $requestHandler->processedRequest->getUri()->getQuery());
196
        $this->assertSame($expectedPort, $requestHandler->processedRequest->getUri()->getPort());
197
    }
198
199
    public function notTrustedDataProvider(): array
200
    {
201
        return [
202
            'none' => [
203
                [],
204
                ['REMOTE_ADDR' => '127.0.0.1'],
205
                [],
206
            ],
207
            'x-forwarded-for' => [
208
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
209
                ['REMOTE_ADDR' => '127.0.0.1'],
210
                [['hosts' => ['8.8.8.8'], 'ipHeaders' => ['x-forwarded-for']]],
211
            ],
212
            'rfc7239' => [
213
                ['x-forwarded-for' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
214
                ['REMOTE_ADDR' => '127.0.0.1'],
215
                [['hosts' => ['8.8.8.8'], 'ipHeaders' => ['x-forwarded-for']]],
216
            ],
217
        ];
218
    }
219
220
    /**
221
     * @dataProvider notTrustedDataProvider
222
     */
223
    public function testNotTrusted(array $headers, array $serverParams, array $trustedHosts): void
224
    {
225
        $request = $this->newRequestWithSchemaAndHeaders('http', $headers, $serverParams);
226
        $requestHandler = new MockRequestHandler();
227
228
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
229
        foreach ($trustedHosts as $data) {
230
            $middleware = $middleware->withAddedTrustedHosts(
231
                $data['hosts'],
232
                $data['ipHeaders'] ?? [],
233
                $data['protocolHeaders'] ?? [],
234
                [],
235
                [],
236
                [],
237
                $data['trustedHeaders'] ?? []);
238
        }
239
        $middleware->process($request, $requestHandler);
240
        $this->assertNull($request->getAttribute('requestClientIp'));
241
    }
242
243
    public function addedTrustedHostsInvalidParameterDataProvider(): array
244
    {
245
        return [
246
            'hostsEmpty' => ['hosts' => []],
247
            'hostsEmptyString' => ['hosts' => ['']],
248
            'hostsNumeric' => ['hosts' => [888]],
249
            'hostsSpaces' => ['hosts' => ['    ']],
250
            'hostsNotDomain' => ['host' => ['-apple']],
251
            'urlHeadersEmpty' => ['urlHeaders' => ['']],
252
            'urlHeadersNumeric' => ['urlHeaders' => [888]],
253
            'urlHeadersSpaces' => ['urlHeaders' => ['   ']],
254
            'trustedHeadersEmpty' => ['trustedHeaders' => ['']],
255
            'trustedHeadersNumeric' => ['trustedHeaders' => [888]],
256
            'trustedHeadersSpaces' => ['trustedHeaders' => ['   ']],
257
            'protocolHeadersNumeric' => ['protocolHeaders' => ['http' => 888]],
258
            'ipHeadersEmptyString' => ['ipHeaders' => [' ']],
259
            'ipHeadersNumeric' => ['ipHeaders' => [888]],
260
            'ipHeadersInvalidType' => ['ipHeaders' => [['---', 'aaa']]],
261
            'ipHeadersInvalidTypeValue' => [
262
                'ipHeaders' => [
263
                    [
264
                        TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239,
265
                        888
266
                    ]
267
                ]
268
            ],
269
        ];
270
    }
271
272
    /**
273
     * @dataProvider addedTrustedHostsInvalidParameterDataProvider
274
     */
275
    public function testAddedTrustedHostsInvalidParameter(array $data): void
276
    {
277
        $this->expectException(\InvalidArgumentException::class);
278
        (new TrustedHostsNetworkResolver(new Psr17Factory()))
279
            ->withAddedTrustedHosts($data['hosts'] ?? [],
280
                $data['ipHeaders'] ?? [],
281
                $data['protocolHeaders'] ?? [],
282
                $data['hostHeaders'] ?? [],
283
                $data['urlHeaders'] ?? [],
284
                $data['portHeaders'] ?? [],
285
                $data['trustedHeaders'] ?? null
286
            );
287
    }
288
}
289