Completed
Pull Request — master (#157)
by Alexander
01:52
created

newRequestWithSchemaAndHeaders()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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