Passed
Pull Request — master (#157)
by
unknown
01:50
created

php$0 ➔ testNotTrustedMiddleware()   A

Complexity

Conditions 1

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 33
rs 9.392

2 Methods

Rating   Name   Duplication   Size   Complexity  
A TrustedHostsNetworkResolverTest.php$0 ➔ __construct() 0 3 1
A TrustedHostsNetworkResolverTest.php$0 ➔ process() 0 7 1
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\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Yiisoft\Yii\Web\Middleware\TrustedHostsNetworkResolver;
13
use Yiisoft\Yii\Web\Tests\Middleware\Mock\MockRequestHandler;
14
15
class TrustedHostsNetworkResolverTest extends TestCase
16
{
17
    protected function newRequestWithSchemaAndHeaders(
18
        string $scheme = 'http',
19
        array $headers = [],
20
        array $serverParams = []
21
    ): ServerRequestInterface {
22
        $request = new ServerRequest('GET', '/', $headers, null, '1.1', $serverParams);
23
        $uri = $request->getUri()->withScheme($scheme);
24
        return $request->withUri($uri);
25
    }
26
27
    public function trustedDataProvider(): array
28
    {
29
        return [
30
            'xForwardLevel1' => [
31
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
32
                ['REMOTE_ADDR' => '127.0.0.1'],
33
                [['hosts' => ['8.8.8.8', '127.0.0.1']]],
34
                '2.2.2.2',
35
            ],
36
            'xForwardLevel2' => [
37
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
38
                ['REMOTE_ADDR' => '127.0.0.1'],
39
                [['hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2']]],
40
                '5.5.5.5',
41
            ],
42
            'forwardLevel1' => [
43
                ['forward' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
44
                ['REMOTE_ADDR' => '127.0.0.1'],
45
                [
46
                    [
47
                        'hosts' => ['8.8.8.8', '127.0.0.1'],
48
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forward']],
49
                    ]
50
                ],
51
                '2.2.2.2',
52
            ],
53
            'forwardLevel2' => [
54
                ['forward' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
55
                ['REMOTE_ADDR' => '127.0.0.1'],
56
                [
57
                    [
58
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
59
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forward']],
60
                    ],
61
62
                ],
63
                '5.5.5.5',
64
            ],
65
            'forwardLevel2HostAndProtocol' => [
66
                ['forward' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2']],
67
                ['REMOTE_ADDR' => '127.0.0.1'],
68
                [
69
                    [
70
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
71
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forward']],
72
                    ],
73
                ],
74
                '5.5.5.5',
75
                'test',
76
                'https',
77
            ],
78
            'forwardLevel2HostAndProtocolAndUrl' => [
79
                [
80
                    'forward' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2'],
81
                    'x-rewrite-url' => ['/test?test=test'],
82
                ],
83
                ['REMOTE_ADDR' => '127.0.0.1'],
84
                [
85
                    [
86
                        'hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2'],
87
                        'ipHeaders' => [[TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239, 'forward']],
88
                    ],
89
                ],
90
                '5.5.5.5',
91
                'test',
92
                'https',
93
                '/test',
94
                'test=test',
95
            ],
96
        ];
97
    }
98
99
    /**
100
     * @dataProvider trustedDataProvider
101
     */
102
    public function testTrusted(
103
        array $headers,
104
        array $serverParams,
105
        array $trustedHosts,
106
        string $expectedClientIp,
107
        ?string $expectedHttpHost = null,
108
        string $expectedHttpScheme = 'http',
109
        string $expectedPath = '/',
110
        string $expectedQuery = ''
111
    ): void {
112
        $request = $this->newRequestWithSchemaAndHeaders('http', $headers, $serverParams);
113
        $requestHandler = new MockRequestHandler();
114
115
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
116
        foreach ($trustedHosts as $data) {
117
            $middleware = $middleware->withAddedTrustedHosts(
118
                $data['hosts'],
119
                $data['ipHeaders'] ?? null,
120
                $data['protocolHeaders'] ?? null,
121
                null,
122
                null,
123
                $data['trustedHeaders'] ?? null);
124
        }
125
        $response = $middleware->process($request, $requestHandler);
126
        $this->assertSame(200, $response->getStatusCode());
127
        $this->assertSame($expectedClientIp, $requestHandler->processedRequest->getAttribute('requestClientIp'));
128
        if ($expectedHttpHost !== null) {
129
            $this->assertSame($expectedHttpHost, $requestHandler->processedRequest->getUri()->getHost());
130
        }
131
        $this->assertSame($expectedHttpScheme, $requestHandler->processedRequest->getUri()->getScheme());
132
        $this->assertSame($expectedPath, $requestHandler->processedRequest->getUri()->getPath());
133
        $this->assertSame($expectedQuery, $requestHandler->processedRequest->getUri()->getQuery());
134
    }
135
136
    public function notTrustedDataProvider(): array
137
    {
138
        return [
139
            'none' => [
140
                [],
141
                ['REMOTE_ADDR' => '127.0.0.1'],
142
                [],
143
            ],
144
            'x-forwarded-for' => [
145
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
146
                ['REMOTE_ADDR' => '127.0.0.1'],
147
                [['hosts' => ['8.8.8.8']]],
148
            ],
149
            'forward' => [
150
                ['x-forwarded-for' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
151
                ['REMOTE_ADDR' => '127.0.0.1'],
152
                [['hosts' => ['8.8.8.8']]],
153
            ],
154
        ];
155
    }
156
157
    /**
158
     * @dataProvider notTrustedDataProvider
159
     */
160
    public function testNotTrusted(array $headers, array $serverParams, array $trustedHosts): void
161
    {
162
        $request = $this->newRequestWithSchemaAndHeaders('http', $headers, $serverParams);
163
        $requestHandler = new MockRequestHandler();
164
165
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
166
        foreach ($trustedHosts as $data) {
167
            $middleware = $middleware->withAddedTrustedHosts(
168
                $data['hosts'],
169
                $data['ipHeaders'] ?? null,
170
                $data['protocolHeaders'] ?? null,
171
                null,
172
                null,
173
                $data['trustedHeaders'] ?? null);
174
        }
175
        $response = $middleware->process($request, $requestHandler);
176
        $this->assertSame(412, $response->getStatusCode());
177
    }
178
179
    public function testNotTrustedMiddleware(): void
180
    {
181
        $request = $this->newRequestWithSchemaAndHeaders('http', [], [
182
            'REMOTE_ADDR' => '127.0.0.1',
183
        ]);
184
        $requestHandler = new MockRequestHandler();
185
186
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
187
        $content = 'Another branch.';
188
        $middleware = $middleware->withNotTrustedBranch(new class($content) implements MiddlewareInterface
189
        {
190
            private $content;
191
192
            public function __construct(string $content)
193
            {
194
                $this->content = $content;
195
            }
196
197
            public function process(
198
                ServerRequestInterface $request,
199
                RequestHandlerInterface $handler
200
            ): ResponseInterface {
201
                $response = (new Psr17Factory())->createResponse(403);
202
                $response->getBody()->write($this->content);
203
                return $response;
204
            }
205
        });
206
        $response = $middleware->process($request, $requestHandler);
207
        $this->assertInstanceOf(ResponseInterface::class, $response);
208
        $this->assertSame(403, $response->getStatusCode());
209
        $body = $response->getBody();
210
        $body->rewind();
211
        $this->assertSame($content, $body->getContents());
212
    }
213
214
    public function addedTrustedHostsInvalidParameterDataProvider(): array
215
    {
216
        return [
217
            'hostsEmpty' => ['hosts' => []],
218
            'hostsEmptyString' => ['hosts' => ['']],
219
            'hostsNumeric' => ['hosts' => [888]],
220
            'hostsSpaces' => ['hosts' => ['    ']],
221
            'hostsNotDomain' => ['host' => ['-apple']],
222
            'urlHeadersEmpty' => ['urlHeaders' => ['']],
223
            'urlHeadersNumeric' => ['urlHeaders' => [888]],
224
            'urlHeadersSpaces' => ['urlHeaders' => ['   ']],
225
            'trustedHeadersEmpty' => ['trustedHeaders' => ['']],
226
            'trustedHeadersNumeric' => ['trustedHeaders' => [888]],
227
            'trustedHeadersSpaces' => ['trustedHeaders' => ['   ']],
228
            'protocolHeadersNumeric' => ['protocolHeaders' => ['http' => 888]],
229
            'ipHeadersEmptyString' => ['ipHeaders' => [' ']],
230
            'ipHeadersNumeric' => ['ipHeaders' => [888]],
231
            'ipHeadersInvalidType' => ['ipHeaders' => [['---', 'aaa']]],
232
            'ipHeadersInvalidTypeValue' => [
233
                'ipHeaders' => [
234
                    [
235
                        TrustedHostsNetworkResolver::IP_HEADER_TYPE_RFC7239,
236
                        888
237
                    ]
238
                ]
239
            ],
240
        ];
241
    }
242
243
    /**
244
     * @dataProvider addedTrustedHostsInvalidParameterDataProvider
245
     */
246
    public function testAddedTrustedHostsInvalidParameter(array $data): void
247
    {
248
        $this->expectException(\InvalidArgumentException::class);
249
        (new TrustedHostsNetworkResolver(new Psr17Factory()))
250
            ->withAddedTrustedHosts($data['hosts'] ?? [],
251
                $data['ipHeaders'] ?? null,
252
                $data['protocolHeaders'] ?? null,
253
                $data['hostHeaders'] ?? null,
254
                $data['urlHeaders'] ?? null,
255
                $data['trustedHeaders'] ?? null
256
            );
257
    }
258
}
259