Completed
Pull Request — master (#157)
by Alexander
02:06 queued 16s
created

trustedDataProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 47
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 38
nc 1
nop 0
dl 0
loc 47
rs 9.312
c 2
b 0
f 0
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
    {
23
        $request = new ServerRequest('GET', '/', $headers, null, '1.1', $serverParams);
24
        $uri = $request->getUri()->withScheme($scheme);
25
        return $request->withUri($uri);
26
    }
27
28
    public function trustedDataProvider(): array
29
    {
30
        return [
31
            'xForwardLevel1' => [
32
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
33
                ['REMOTE_ADDR' => '127.0.0.1'],
34
                [['hosts' => ['8.8.8.8', '127.0.0.1']]],
35
                '2.2.2.2',
36
            ],
37
            'xForwardLevel2' => [
38
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
39
                ['REMOTE_ADDR' => '127.0.0.1'],
40
                [['hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2']]],
41
                '5.5.5.5',
42
            ],
43
            'forwardLevel1' => [
44
                ['forward' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
45
                ['REMOTE_ADDR' => '127.0.0.1'],
46
                [['hosts' => ['8.8.8.8', '127.0.0.1']]],
47
                '2.2.2.2',
48
            ],
49
            'forwardLevel2' => [
50
                ['forward' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
51
                ['REMOTE_ADDR' => '127.0.0.1'],
52
                [['hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2']]],
53
                '5.5.5.5',
54
            ],
55
            'forwardLevel2HostAndProtocol' => [
56
                ['forward' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2']],
57
                ['REMOTE_ADDR' => '127.0.0.1'],
58
                [['hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2']]],
59
                '5.5.5.5',
60
                'test',
61
                'https',
62
            ],
63
            'forwardLevel2HostAndProtocolAndUrl' => [
64
                [
65
                    'forward' => ['for=9.9.9.9', 'proto=https;for=5.5.5.5;host=test', 'for=2.2.2.2'],
66
                    'x-rewrite-url' => ['/test?test=test'],
67
                ],
68
                ['REMOTE_ADDR' => '127.0.0.1'],
69
                [['hosts' => ['8.8.8.8', '127.0.0.1', '2.2.2.2']]],
70
                '5.5.5.5',
71
                'test',
72
                'https',
73
                '/test',
74
                'test=test',
75
            ],
76
        ];
77
    }
78
79
    /**
80
     * @dataProvider trustedDataProvider
81
     */
82
    public function testTrusted(
83
        array $headers,
84
        array $serverParams,
85
        array $trustedHosts,
86
        string $expectedClientIp,
87
        ?string $expectedHttpHost = null,
88
        string $expectedHttpScheme = 'http',
89
        string $expectedPath = '/',
90
        string $expectedQuery = ''
91
    ): void
92
    {
93
        $request = $this->newRequestWithSchemaAndHeaders('http', $headers, $serverParams);
94
        $requestHandler = new MockRequestHandler();
95
96
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
97
        foreach ($trustedHosts as $data) {
98
            $middleware = $middleware->withAddedTrustedHosts(
99
                $data['hosts'],
100
                $data['ipHeaders'] ?? null,
101
                $data['protocolHeaders'] ?? null,
102
                null,
103
                null,
104
                $data['trustedHeaders'] ?? null);
105
        }
106
        $response = $middleware->process($request, $requestHandler);
107
        $this->assertSame(200, $response->getStatusCode());
108
        $this->assertSame($expectedClientIp, $requestHandler->processedRequest->getAttribute('requestClientIp'));
109
        if ($expectedHttpHost !== null) {
110
            $this->assertSame($expectedHttpHost, $requestHandler->processedRequest->getUri()->getHost());
111
        }
112
        $this->assertSame($expectedHttpScheme, $requestHandler->processedRequest->getUri()->getScheme());
113
        $this->assertSame($expectedPath, $requestHandler->processedRequest->getUri()->getPath());
114
        $this->assertSame($expectedQuery, $requestHandler->processedRequest->getUri()->getQuery());
115
    }
116
117
    public function notTrustedDataProvider(): array
118
    {
119
        return [
120
            'none' => [
121
                [],
122
                ['REMOTE_ADDR' => '127.0.0.1'],
123
                [],
124
            ],
125
            'x-forwarded-for' => [
126
                ['x-forwarded-for' => ['9.9.9.9', '5.5.5.5', '2.2.2.2']],
127
                ['REMOTE_ADDR' => '127.0.0.1'],
128
                [['hosts' => ['8.8.8.8']]],
129
            ],
130
            'forward' => [
131
                ['x-forwarded-for' => ['for=9.9.9.9', 'for=5.5.5.5', 'for=2.2.2.2']],
132
                ['REMOTE_ADDR' => '127.0.0.1'],
133
                [['hosts' => ['8.8.8.8']]],
134
            ],
135
        ];
136
    }
137
138
    /**
139
     * @dataProvider notTrustedDataProvider
140
     */
141
    public function testNotTrusted(array $headers, array $serverParams, array $trustedHosts): void
142
    {
143
        $request = $this->newRequestWithSchemaAndHeaders('http', $headers, $serverParams);
144
        $requestHandler = new MockRequestHandler();
145
146
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
147
        foreach ($trustedHosts as $data) {
148
            $middleware = $middleware->withAddedTrustedHosts(
149
                $data['hosts'],
150
                $data['ipHeaders'] ?? null,
151
                $data['protocolHeaders'] ?? null,
152
                null,
153
                null,
154
                $data['trustedHeaders'] ?? null);
155
        }
156
        $response = $middleware->process($request, $requestHandler);
157
        $this->assertSame(412, $response->getStatusCode());
158
    }
159
160
    public function testNotTrustedMiddleware(): void
161
    {
162
        $request = $this->newRequestWithSchemaAndHeaders('http', [], [
163
            'REMOTE_ADDR' => '127.0.0.1',
164
        ]);
165
        $requestHandler = new MockRequestHandler();
166
167
        $middleware = new TrustedHostsNetworkResolver(new Psr17Factory());
168
        $content = 'Another branch.';
169
        $middleware = $middleware->withNotTrustedBranch(new class($content) implements MiddlewareInterface {
170
            private $content;
171
172
            public function __construct(string $content)
173
            {
174
                $this->content = $content;
175
            }
176
177
            public function process(
178
                ServerRequestInterface $request,
179
                RequestHandlerInterface $handler
180
            ): ResponseInterface {
181
                $response = (new Psr17Factory())->createResponse(403);
182
                $response->getBody()->write($this->content);
183
                return $response;
184
            }
185
        });
186
        $response = $middleware->process($request, $requestHandler);
187
        $this->assertInstanceOf(ResponseInterface::class, $response);
188
        $this->assertSame(403, $response->getStatusCode());
189
        $body = $response->getBody();
190
        $body->rewind();
191
        $this->assertSame($content, $body->getContents());
192
    }
193
}
194