‪TYPO3CMS  ‪main
VerifyHostHeaderTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
22 use Psr\Http\Server\RequestHandlerInterface;
26 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
27 
28 final class ‪VerifyHostHeaderTest extends UnitTestCase
29 {
30  #[Test]
32  {
33  $subject = new ‪VerifyHostHeader('');
34  $serverParams = ‪$_SERVER;
35  self::assertFalse($subject->isAllowedHostHeaderValue('evil.foo.bar', $serverParams));
36  }
37 
39  {
40  return [
41  'hostname without port matching' => ['lolli.did.this', '.*\.did\.this'],
42  'other hostname without port matching' => ['helmut.did.this', '.*\.did\.this'],
43  'two different hostnames without port matching 1st host' => ['helmut.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
44  'two different hostnames without port matching 2nd host' => ['lolli.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
45  'hostname with port matching' => ['lolli.did.this:42', '.*\.did\.this:42'],
46  'hostnames are case insensitive 1' => ['lolli.DID.this:42', '.*\.did.this:42'],
47  'hostnames are case insensitive 2' => ['lolli.did.this:42', '.*\.DID.this:42'],
48  ];
49  }
50 
52  {
53  return [
54  'hostname without port' => ['lolli.did.this', 'helmut\.did\.this'],
55  'hostname with port, but port not allowed' => ['lolli.did.this:42', 'helmut\.did\.this'],
56  'two different hostnames in pattern but host header starts with different value #1' => ['sub.helmut.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
57  'two different hostnames in pattern but host header starts with different value #2' => ['sub.lolli.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
58  'two different hostnames in pattern but host header ends with different value #1' => ['helmut.is.secure.tld', '(helmut\.is\.secure|lolli\.is\.secure)'],
59  'two different hostnames in pattern but host header ends with different value #2' => ['lolli.is.secure.tld', '(helmut\.is\.secure|lolli\.is\.secure)'],
60  ];
61  }
62 
67  #[DataProvider('hostnamesMatchingTrustedHostsConfigurationDataProvider')]
68  #[Test]
69  public function ‪isAllowedHostHeaderValueReturnsTrueIfHostValueMatches(string $httpHost, string $hostNamePattern): void
70  {
71  $serverParams = ‪$_SERVER;
72 
73  $subject = new ‪VerifyHostHeader($hostNamePattern);
74  self::assertTrue($subject->isAllowedHostHeaderValue($httpHost, $serverParams));
75  }
76 
81  #[DataProvider('hostnamesNotMatchingTrustedHostsConfigurationDataProvider')]
82  #[Test]
83  public function ‪isAllowedHostHeaderValueReturnsFalseIfHostValueMatches(string $httpHost, string $hostNamePattern): void
84  {
85  $serverParams = ‪$_SERVER;
86 
87  $subject = new ‪VerifyHostHeader($hostNamePattern);
88  self::assertFalse($subject->isAllowedHostHeaderValue($httpHost, $serverParams));
89  }
90 
91  public static function ‪serverNamePatternDataProvider(): array
92  {
93  return [
94  'host value matches server name and server port is default http' => [
95  'httpHost' => 'secure.web.server',
96  'serverName' => 'secure.web.server',
97  'isAllowed' => true,
98  'serverPort' => '80',
99  'ssl' => 'Off',
100  ],
101  'host value matches server name if compared case insensitive 1' => [
102  'httpHost' => 'secure.web.server',
103  'serverName' => 'secure.WEB.server',
104  'isAllowed' => true,
105  ],
106  'host value matches server name if compared case insensitive 2' => [
107  'httpHost' => 'secure.WEB.server',
108  'serverName' => 'secure.web.server',
109  'isAllowed' => true,
110  ],
111  'host value matches server name and server port is default https' => [
112  'httpHost' => 'secure.web.server',
113  'serverName' => 'secure.web.server',
114  'isAllowed' => true,
115  'serverPort' => '443',
116  'ssl' => 'On',
117  ],
118  'host value matches server name and server port' => [
119  'httpHost' => 'secure.web.server:88',
120  'serverName' => 'secure.web.server',
121  'isAllowed' => true,
122  'serverPort' => '88',
123  ],
124  'host value matches server name case insensitive 1 and server port' => [
125  'httpHost' => 'secure.WEB.server:88',
126  'serverName' => 'secure.web.server',
127  'isAllowed' => true,
128  'serverPort' => '88',
129  ],
130  'host value matches server name case insensitive 2 and server port' => [
131  'httpHost' => 'secure.web.server:88',
132  'serverName' => 'secure.WEB.server',
133  'isAllowed' => true,
134  'serverPort' => '88',
135  ],
136  'host value is ipv6 but matches server name and server port' => [
137  'httpHost' => '[::1]:81',
138  'serverName' => '[::1]',
139  'isAllowed' => true,
140  'serverPort' => '81',
141  ],
142  'host value does not match server name' => [
143  'httpHost' => 'insecure.web.server',
144  'serverName' => 'secure.web.server',
145  'isAllowed' => false,
146  ],
147  'host value does not match server port' => [
148  'httpHost' => 'secure.web.server:88',
149  'serverName' => 'secure.web.server',
150  'isAllowed' => false,
151  'serverPort' => '89',
152  ],
153  'host value has default port that does not match server port' => [
154  'httpHost' => 'secure.web.server',
155  'serverName' => 'secure.web.server',
156  'isAllowed' => false,
157  'serverPort' => '81',
158  'ssl' => 'Off',
159  ],
160  'host value has default port that does not match server ssl port' => [
161  'httpHost' => 'secure.web.server',
162  'serverName' => 'secure.web.server',
163  'isAllowed' => false,
164  'serverPort' => '444',
165  'ssl' => 'On',
166  ],
167  ];
168  }
169 
170  #[DataProvider('serverNamePatternDataProvider')]
171  #[Test]
173  string $httpHost,
174  string $serverName,
175  bool $isAllowed,
176  string $serverPort = '80',
177  string $ssl = 'Off'
178  ): void {
179  $serverParams = ‪$_SERVER;
180  $serverParams['SERVER_NAME'] = $serverName;
181  $serverParams['SERVER_PORT'] = $serverPort;
182  $serverParams['HTTPS'] = $ssl;
183 
185 
186  self::assertSame($isAllowed, $subject->isAllowedHostHeaderValue($httpHost, $serverParams));
187  }
188 
189  #[DataProvider('serverNamePatternDataProvider')]
190  #[Test]
192  string $httpHost,
193  string $serverName,
194  bool $isAllowed,
195  string $serverPort = '80',
196  string $ssl = 'Off'
197  ): void {
198  $serverParams = ‪$_SERVER;
199  $serverParams['REMOTE_ADDR'] = '10.0.0.1';
200  $serverParams['SERVER_NAME'] = $serverName;
201  $serverParams['SERVER_PORT'] = $serverPort;
202  $serverParams['HTTPS'] = $ssl;
203 
205 
206  self::assertSame($isAllowed, $subject->isAllowedHostHeaderValue($httpHost, $serverParams));
207  }
208 
209  #[DataProvider('hostnamesNotMatchingTrustedHostsConfigurationDataProvider')]
210  #[Test]
211  public function ‪processThrowsExceptionForNotAllowedHostnameValues(string $httpHost, string $hostNamePattern): void
212  {
213  $serverParams = ‪$_SERVER;
214  $serverParams['HTTP_HOST'] = $httpHost;
215  $subject = new ‪VerifyHostHeader($hostNamePattern);
216  $request = new ‪ServerRequest(serverParams: $serverParams);
217  $requestHandlerMock = $this->createMock(RequestHandlerInterface::class);
218 
219  $this->expectException(\UnexpectedValueException::class);
220  $this->expectExceptionCode(1396795884);
221 
222  $subject->process($request, $requestHandlerMock);
223  }
224 
225  #[DataProvider('hostnamesNotMatchingTrustedHostsConfigurationDataProvider')]
226  #[Test]
228  {
229  $serverParams = ‪$_SERVER;
230  $serverParams['HTTP_HOST'] = $httpHost;
232  $request = new ‪ServerRequest(serverParams: $serverParams);
233  $requestHandlerMock = $this->createMock(RequestHandlerInterface::class);
234 
235  $requestHandlerMock->expects(self::atLeastOnce())->method('handle')->with($request)->willReturn(new ‪Response());
236 
237  $subject->process($request, $requestHandlerMock);
238  }
239 }
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\isAllowedHostHeaderValueReturnsFalseIfHostValueMatches
‪isAllowedHostHeaderValueReturnsFalseIfHostValueMatches(string $httpHost, string $hostNamePattern)
Definition: VerifyHostHeaderTest.php:83
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\hostnamesNotMatchingTrustedHostsConfigurationDataProvider
‪static hostnamesNotMatchingTrustedHostsConfigurationDataProvider()
Definition: VerifyHostHeaderTest.php:51
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\processThrowsExceptionForNotAllowedHostnameValues
‪processThrowsExceptionForNotAllowedHostnameValues(string $httpHost, string $hostNamePattern)
Definition: VerifyHostHeaderTest.php:211
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest
Definition: VerifyHostHeaderTest.php:29
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\isAllowedHostHeaderValueWorksCorrectlyWithWithServerNamePattern
‪isAllowedHostHeaderValueWorksCorrectlyWithWithServerNamePattern(string $httpHost, string $serverName, bool $isAllowed, string $serverPort='80', string $ssl='Off')
Definition: VerifyHostHeaderTest.php:172
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\isAllowedHostHeaderValueReturnsFalseIfTrustedHostsIsNotConfigured
‪isAllowedHostHeaderValueReturnsFalseIfTrustedHostsIsNotConfigured()
Definition: VerifyHostHeaderTest.php:31
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\hostnamesMatchingTrustedHostsConfigurationDataProvider
‪static hostnamesMatchingTrustedHostsConfigurationDataProvider()
Definition: VerifyHostHeaderTest.php:38
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\isAllowedHostHeaderValueReturnsTrueIfHostValueMatches
‪isAllowedHostHeaderValueReturnsTrueIfHostValueMatches(string $httpHost, string $hostNamePattern)
Definition: VerifyHostHeaderTest.php:69
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\processAllowsAllHostnameValuesIfHostPatternIsSetToAllowAll
‪processAllowsAllHostnameValuesIfHostPatternIsSetToAllowAll(string $httpHost)
Definition: VerifyHostHeaderTest.php:227
‪TYPO3\CMS\Core\Http\Response
Definition: Response.php:32
‪TYPO3\CMS\Core\Tests\Unit\Middleware
Definition: VerifyHostHeaderTest.php:18
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:39
‪$_SERVER
‪$_SERVER['TYPO3_DEPRECATED_ENTRYPOINT']
Definition: legacy-backend.php:20
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\isAllowedHostHeaderValueWorksCorrectlyWithWithServerNamePatternAndSslProxy
‪isAllowedHostHeaderValueWorksCorrectlyWithWithServerNamePatternAndSslProxy(string $httpHost, string $serverName, bool $isAllowed, string $serverPort='80', string $ssl='Off')
Definition: VerifyHostHeaderTest.php:191
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
‪const ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL
Definition: VerifyHostHeader.php:32
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader\ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME
‪const ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME
Definition: VerifyHostHeader.php:33
‪TYPO3\CMS\Core\Middleware\VerifyHostHeader
Definition: VerifyHostHeader.php:31
‪TYPO3\CMS\Core\Tests\Unit\Middleware\VerifyHostHeaderTest\serverNamePatternDataProvider
‪static serverNamePatternDataProvider()
Definition: VerifyHostHeaderTest.php:91