Repository: fideloper/TrustedProxy Branch: master Commit: a751f2bc86dd Files: 12 Total size: 32.7 KB Directory structure: gitextract_lrvm80ac/ ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ └── laravel-9-updates.md │ └── workflows/ │ └── tests.yml ├── .gitignore ├── LICENSE.md ├── composer.json ├── config/ │ └── trustedproxy.php ├── phpunit.xml.dist ├── readme.md ├── src/ │ ├── TrustProxies.php │ └── TrustedProxyServiceProvider.php └── tests/ └── TrustedProxyTest.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ * text=auto /tests export-ignore /.gitattributes export-ignore /.gitignore export-ignore /.travis.yml export-ignore /phpunit.xml.dist export-ignore /readme.md export-ignore ================================================ FILE: .github/ISSUE_TEMPLATE/laravel-9-updates.md ================================================ --- name: Laravel 9 Updates about: Inform about Laravel 9 changes title: '' labels: '' assignees: '' --- ================================================ FILE: .github/workflows/tests.yml ================================================ # This is a basic workflow to help you get started with Actions name: Tests # Controls when the action will run. on: push: pull_request: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" run_tests: # The type of runner that the job will run on runs-on: ubuntu-latest strategy: fail-fast: true matrix: php: [7.2, 7.3, 7.4, 8.0, 8.1] name: PHP ${{ matrix.php }} # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 - name: Checkout code uses: actions/checkout@v2 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite tools: composer:v2 coverage: none - name: Install dependencies uses: nick-invision/retry@v1 with: timeout_minutes: 5 max_attempts: 5 command: composer update --prefer-dist --no-interaction --no-progress - name: Execute tests run: vendor/bin/phpunit --verbose ================================================ FILE: .gitignore ================================================ /.idea /vendor composer.lock phpunit.xml .phpunit.result.cache ================================================ FILE: LICENSE.md ================================================ MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: composer.json ================================================ { "name": "fideloper/proxy", "description": "Set trusted proxies for Laravel", "keywords": ["proxy", "trusted proxy", "load balancing"], "license": "MIT", "authors": [ { "name": "Chris Fidao", "email": "fideloper@gmail.com" } ], "require": { "php": ">=5.4.0", "illuminate/contracts": "^5.0|^6.0|^7.0|^8.0|^9.0" }, "require-dev": { "illuminate/http": "^5.0|^6.0|^7.0|^8.0|^9.0", "mockery/mockery": "^1.0", "phpunit/phpunit": "^8.5.8|^9.3.3" }, "autoload": { "psr-4": { "Fideloper\\Proxy\\": "src/" } }, "extra": { "laravel": { "providers": [ "Fideloper\\Proxy\\TrustedProxyServiceProvider" ] } }, "minimum-stability": "dev", "prefer-stable": true } ================================================ FILE: config/trustedproxy.php ================================================ null, // [,], '*', ',' /* * To trust one or more specific proxies that connect * directly to your server, use an array or a string separated by comma of IP addresses: */ // 'proxies' => ['192.168.1.1'], // 'proxies' => '192.168.1.1, 192.168.1.2', /* * Or, to trust all proxies that connect * directly to your server, use a "*" */ // 'proxies' => '*', /* * Which headers to use to detect proxy related data (For, Host, Proto, Port) * * Options include: * * - All headers (see below) - Trust all x-forwarded-* headers * - Illuminate\Http\Request::HEADER_FORWARDED - Use the FORWARDED header to establish trust * - Illuminate\Http\Request::HEADER_X_FORWARDED_AWS_ELB - If you are using AWS Elastic Load Balancer * * @link https://symfony.com/doc/current/deployment/proxies.html */ 'headers' => Illuminate\Http\Request::HEADER_X_FORWARDED_FOR | Illuminate\Http\Request::HEADER_X_FORWARDED_HOST | Illuminate\Http\Request::HEADER_X_FORWARDED_PORT | Illuminate\Http\Request::HEADER_X_FORWARDED_PROTO | Illuminate\Http\Request::HEADER_X_FORWARDED_AWS_ELB, ]; ================================================ FILE: phpunit.xml.dist ================================================ ./tests/ ================================================ FILE: readme.md ================================================ # Laravel Trusted Proxies [![Build Status](https://github.com/fideloper/TrustedProxy/workflows/Tests/badge.svg)](https://github.com/fideloper/TrustedProxy/actions) [![Total Downloads](https://poser.pugx.org/fideloper/proxy/downloads.png)](https://packagist.org/packages/fideloper/proxy) **Setting a trusted proxy allows for correct URL generation, redirecting, session handling and logging in Laravel when behind a reverse proxy such as a load balancer or cache.** --- ## Installation **Laravel 5.5+ comes with this package**. If you are using Laravel 5.5 or greater, you **do not** need to add this to your project separately. * [Laravel 5.5](https://laravel.com/docs/5.5/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:~3.3`) * [Laravel 5.6](https://laravel.com/docs/5.6/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`) * [Laravel 5.7](https://laravel.com/docs/5.7/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`) * [Laravel 5.8](https://laravel.com/docs/5.8/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`) * [Laravel 6.x](https://laravel.com/docs/6.x/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`) * [Laravel 7.x](https://laravel.com/docs/7.x/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.2`) * [Laravel 8.x](https://laravel.com/docs/8.x/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.3`) * [Laravel 9.x](https://laravel.com/docs/9.x/requests#configuring-trusted-proxies) Docs (**Don't use this package**. [Explanation here](https://github.com/fideloper/TrustedProxy/issues/152), [Upgrade docs here](https://laravel.com/docs/9.x/upgrade)) ### Laravel 5.0 - 5.4 To install Trusted Proxy, use: ``` composer require fideloper/proxy:^3.3 ``` ### Laravel 4 ``` composer require fideloper/proxy:^2.0 ``` ## Setup Refer to the docs above for using Trusted Proxy in Laravel 5.5+. For Laravel 4.0 - 5.4, refer to [the wiki](https://github.com/fideloper/TrustedProxy/wiki). ## What Does This Do? Setting a trusted proxy allows for correct URL generation, redirecting, session handling and logging in Laravel when behind a reverse proxy. This is useful if your web servers sit behind a load balancer (Nginx, HAProxy, Envoy, ELB/ALB, etc), HTTP cache (CloudFlare, Squid, Varnish, etc), or other intermediary (reverse) proxy. ## How Does This Work? Applications behind a reverse proxy typically read some HTTP headers such as `X-Forwarded`, `X-Forwarded-For`, `X-Forwarded-Proto` (and more) to know about the real end-client making an HTTP request. > If those headers were not set, then the application code would think every incoming HTTP request would be from the proxy. Laravel (technically the Symfony HTTP base classes) have a concept of a "trusted proxy", where those `X-Forwarded` headers will only be used if the source IP address of the request is known. In other words, it only trusts those headers if the proxy is trusted. This package creates an easier interface to that option. You can set the IP addresses of the proxies (that the application would see, so it may be a private network IP address), and the Symfony HTTP classes will know to use the `X-Forwarded` headers if an HTTP requets containing those headers was from the trusted proxy. ## Why Does This Matter? A very common load balancing approach is to send `https://` requests to a load balancer, but send `http://` requests to the application servers behind the load balancer. For example, you may send a request in your browser to `https://example.org`. The load balancer, in turn, might send requests to an application server at `http://192.168.1.23`. What if that server returns a redirect, or generates an asset url? The users's browser would get back a redirect or HTML that includes `http://192.168.1.23` in it, which is clearly wrong. What happens is that the application thinks its hostname is `192.168.1.23` and the schema is `http://`. It doesn't know that the end client used `https://example.org` for its web request. So the application needs to know to read the `X-Forwarded` headers to get the correct request details (schema `https://`, host `example.org`). Laravel/Symfony automatically reads those headers, but only if the trusted proxy configuration is set to "trust" the load balancer/reverse proxy. > Note: Many of us use hosted load balancers/proxies such as AWS ELB/ALB, etc. We don't know the IP address of those reverse proxies, and so you need to trusted **all** proxies in that case. > > The trade-off there is running the security risk of allowing people to potentially spoof the `X-Forwarded` headers. ## IP Addresses by Service [This Wiki page](https://github.com/fideloper/TrustedProxy/wiki/IP-Addresses-of-Popular-Services) has a list of popular services and their IP addresses of their servers, if available. Any updates or suggestions are welcome! ================================================ FILE: src/TrustProxies.php ================================================ config = $config; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @throws \Symfony\Component\HttpKernel\Exception\HttpException * * @return mixed */ public function handle(Request $request, Closure $next) { $request::setTrustedProxies([], $this->getTrustedHeaderNames()); // Reset trusted proxies between requests $this->setTrustedProxyIpAddresses($request); return $next($request); } /** * Sets the trusted proxies on the request to the value of trustedproxy.proxies * * @param \Illuminate\Http\Request $request */ protected function setTrustedProxyIpAddresses(Request $request) { $trustedIps = $this->proxies ?: $this->config->get('trustedproxy.proxies'); // Trust any IP address that calls us // `**` for backwards compatibility, but is deprecated if ($trustedIps === '*' || $trustedIps === '**') { return $this->setTrustedProxyIpAddressesToTheCallingIp($request); } // Support IPs addresses separated by comma $trustedIps = is_string($trustedIps) ? array_map('trim', explode(',', $trustedIps)) : $trustedIps; // Only trust specific IP addresses if (is_array($trustedIps)) { return $this->setTrustedProxyIpAddressesToSpecificIps($request, $trustedIps); } } /** * Specify the IP addresses to trust explicitly. * * @param \Illuminate\Http\Request $request * @param array $trustedIps */ private function setTrustedProxyIpAddressesToSpecificIps(Request $request, $trustedIps) { $request->setTrustedProxies((array) $trustedIps, $this->getTrustedHeaderNames()); } /** * Set the trusted proxy to be the IP address calling this servers * * @param \Illuminate\Http\Request $request */ private function setTrustedProxyIpAddressesToTheCallingIp(Request $request) { $request->setTrustedProxies([$request->server->get('REMOTE_ADDR')], $this->getTrustedHeaderNames()); } /** * Retrieve trusted header name(s), falling back to defaults if config not set. * * @return int A bit field of Request::HEADER_*, to set which headers to trust from your proxies. */ protected function getTrustedHeaderNames() { $headers = $this->headers ?: $this->config->get('trustedproxy.headers'); switch ($headers) { case 'HEADER_X_FORWARDED_AWS_ELB': case Request::HEADER_X_FORWARDED_AWS_ELB: return Request::HEADER_X_FORWARDED_AWS_ELB; break; case 'HEADER_FORWARDED': case Request::HEADER_FORWARDED: return Request::HEADER_FORWARDED; break; case 'HEADER_X_FORWARDED_FOR': case Request::HEADER_X_FORWARDED_FOR: return Request::HEADER_X_FORWARDED_FOR; break; case 'HEADER_X_FORWARDED_HOST': case Request::HEADER_X_FORWARDED_HOST: return Request::HEADER_X_FORWARDED_HOST; break; case 'HEADER_X_FORWARDED_PORT': case Request::HEADER_X_FORWARDED_PORT: return Request::HEADER_X_FORWARDED_PORT; break; case 'HEADER_X_FORWARDED_PROTO': case Request::HEADER_X_FORWARDED_PROTO: return Request::HEADER_X_FORWARDED_PROTO; break; default: return Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB; } return $headers; } } ================================================ FILE: src/TrustedProxyServiceProvider.php ================================================ app instanceof LaravelApplication && $this->app->runningInConsole()) { $this->publishes([$source => config_path('trustedproxy.php')]); } elseif ($this->app instanceof LumenApplication) { $this->app->configure('trustedproxy'); } if ($this->app instanceof LaravelApplication && ! $this->app->configurationIsCached()) { $this->mergeConfigFrom($source, 'trustedproxy'); } } /** * Register the service provider. * * @return void */ public function register() { // } } ================================================ FILE: tests/TrustedProxyTest.php ================================================ createProxiedRequest(); $this->assertEquals('192.168.10.10', $req->getClientIp(), 'Assert untrusted proxy x-forwarded-for header not used'); $this->assertEquals('http', $req->getScheme(), 'Assert untrusted proxy x-forwarded-proto header not used'); $this->assertEquals('localhost', $req->getHost(), 'Assert untrusted proxy x-forwarded-host header not used'); $this->assertEquals(8888, $req->getPort(), 'Assert untrusted proxy x-forwarded-port header not used'); } /** * Test that Symfony DOES indeed trust X-Forwarded-* * headers when given trusted proxies * * Again, this re-tests Symfony's Request class. */ public function test_does_trust_trusted_proxy() { $req = $this->createProxiedRequest(); $req->setTrustedProxies(['192.168.10.10'], $this->headerAll); $this->assertEquals('173.174.200.38', $req->getClientIp(), 'Assert trusted proxy x-forwarded-for header used'); $this->assertEquals('https', $req->getScheme(), 'Assert trusted proxy x-forwarded-proto header used'); $this->assertEquals('serversforhackers.com', $req->getHost(), 'Assert trusted proxy x-forwarded-host header used'); $this->assertEquals(443, $req->getPort(), 'Assert trusted proxy x-forwarded-port header used'); } /** * Test the next most typical usage of TrustedProxies: * Trusted X-Forwarded-For header, wilcard for TrustedProxies */ public function test_trusted_proxy_sets_trusted_proxies_with_wildcard() { $trustedProxy = $this->createTrustedProxy($this->headerAll, '*'); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy x-forwarded-for header used with wildcard proxy setting'); }); } /** * Test the next most typical usage of TrustedProxies: * Trusted X-Forwarded-For header, wilcard for TrustedProxies */ public function test_trusted_proxy_sets_trusted_proxies_with_double_wildcard_for_backwards_compat() { $trustedProxy = $this->createTrustedProxy($this->headerAll, '**'); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy x-forwarded-for header used with wildcard proxy setting'); }); } /** * Test the most typical usage of TrustProxies: * Trusted X-Forwarded-For header */ public function test_trusted_proxy_sets_trusted_proxies() { $trustedProxy = $this->createTrustedProxy($this->headerAll, ['192.168.10.10']); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy x-forwarded-for header used'); }); } /** * Test X-Forwarded-For header with multiple IP addresses */ public function test_get_client_ips() { $trustedProxy = $this->createTrustedProxy($this->headerAll, ['192.168.10.10']); $forwardedFor = [ '192.0.2.2', '192.0.2.2, 192.0.2.199', '192.0.2.2, 192.0.2.199, 99.99.99.99', '192.0.2.2,192.0.2.199', ]; foreach($forwardedFor as $forwardedForHeader) { $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_FOR' => $forwardedForHeader]); $trustedProxy->handle($request, function ($request) use ($forwardedForHeader) { $ips = $request->getClientIps(); $this->assertEquals('192.0.2.2', end($ips), 'Assert sets the '.$forwardedForHeader); }); } } /** * Test X-Forwarded-For header with multiple IP addresses, with some of those being trusted */ public function test_get_client_ip_with_muliple_ip_addresses_some_of_which_are_trusted() { $trustedProxy = $this->createTrustedProxy($this->headerAll, ['192.168.10.10', '192.0.2.199']); $forwardedFor = [ '192.0.2.2', '192.0.2.2, 192.0.2.199', '99.99.99.99, 192.0.2.2, 192.0.2.199', '192.0.2.2,192.0.2.199', ]; foreach($forwardedFor as $forwardedForHeader) { $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_FOR' => $forwardedForHeader]); $trustedProxy->handle($request, function ($request) use ($forwardedForHeader) { $this->assertEquals('192.0.2.2', $request->getClientIp(), 'Assert sets the '.$forwardedForHeader); }); } } /** * Test X-Forwarded-For header with multiple IP addresses, with * wildcard trusting of all proxies */ public function test_get_client_ip_with_muliple_ip_addresses_all_proxies_are_trusted() { $trustedProxy = $this->createTrustedProxy($this->headerAll, '*'); $forwardedFor = [ '192.0.2.2', '192.0.2.199, 192.0.2.2', '192.0.2.199,192.0.2.2', '99.99.99.99,192.0.2.199,192.0.2.2', ]; foreach($forwardedFor as $forwardedForHeader) { $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_FOR' => $forwardedForHeader]); $trustedProxy->handle($request, function ($request) use ($forwardedForHeader) { $this->assertEquals('192.0.2.2', $request->getClientIp(), 'Assert sets the '.$forwardedForHeader); }); } } /** * Test distrusting a header. */ public function test_can_distrust_headers() { $trustedProxy = $this->createTrustedProxy(Request::HEADER_FORWARDED, ['192.168.10.10']); $request = $this->createProxiedRequest([ 'HTTP_FORWARDED' => 'for=173.174.200.40:443; proto=https; host=serversforhackers.com', 'HTTP_X_FORWARDED_FOR' => '173.174.200.38', 'HTTP_X_FORWARDED_HOST' => 'svrs4hkrs.com', 'HTTP_X_FORWARDED_PORT' => '80', 'HTTP_X_FORWARDED_PROTO' => 'http', ]); $trustedProxy->handle($request, function ($request) { $this->assertEquals('173.174.200.40', $request->getClientIp(), 'Assert trusted proxy used forwarded header for IP'); $this->assertEquals('https', $request->getScheme(), 'Assert trusted proxy used forwarded header for scheme'); $this->assertEquals('serversforhackers.com', $request->getHost(), 'Assert trusted proxy used forwarded header for host'); $this->assertEquals(443, $request->getPort(), 'Assert trusted proxy used forwarded header for port'); }); } /** * Test that only the X-Forwarded-For header is trusted. */ public function test_x_forwarded_for_header_only_trusted() { $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_FOR, '*'); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy used forwarded header for IP'); $this->assertEquals('http', $request->getScheme(), 'Assert trusted proxy did not use forwarded header for scheme'); $this->assertEquals('localhost', $request->getHost(), 'Assert trusted proxy did not use forwarded header for host'); $this->assertEquals(8888, $request->getPort(), 'Assert trusted proxy did not use forwarded header for port'); }); } /** * Test that only the X-Forwarded-Host header is trusted. */ public function test_x_forwarded_host_header_only_trusted() { $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_HOST, '*'); $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_HOST' => 'serversforhackers.com:8888']); $trustedProxy->handle($request, function ($request) { $this->assertEquals('192.168.10.10', $request->getClientIp(), 'Assert trusted proxy did not use forwarded header for IP'); $this->assertEquals('http', $request->getScheme(), 'Assert trusted proxy did not use forwarded header for scheme'); $this->assertEquals('serversforhackers.com', $request->getHost(), 'Assert trusted proxy used forwarded header for host'); $this->assertEquals(8888, $request->getPort(), 'Assert trusted proxy did not use forwarded header for port'); }); } /** * Test that only the X-Forwarded-Port header is trusted. */ public function test_x_forwarded_port_header_only_trusted() { $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_PORT, '*'); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('192.168.10.10', $request->getClientIp(), 'Assert trusted proxy did not use forwarded header for IP'); $this->assertEquals('http', $request->getScheme(), 'Assert trusted proxy did not use forwarded header for scheme'); $this->assertEquals('localhost', $request->getHost(), 'Assert trusted proxy did not use forwarded header for host'); $this->assertEquals(443, $request->getPort(), 'Assert trusted proxy used forwarded header for port'); }); } /** * Test that only the X-Forwarded-Proto header is trusted. */ public function test_x_forwarded_proto_header_only_trusted() { $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_PROTO, '*'); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('192.168.10.10', $request->getClientIp(), 'Assert trusted proxy did not use forwarded header for IP'); $this->assertEquals('https', $request->getScheme(), 'Assert trusted proxy used forwarded header for scheme'); $this->assertEquals('localhost', $request->getHost(), 'Assert trusted proxy did not use forwarded header for host'); $this->assertEquals(8888, $request->getPort(), 'Assert trusted proxy did not use forwarded header for port'); }); } /** * Test a combination of individual X-Forwarded-* headers are trusted. */ public function test_x_forwarded_multiple_individual_headers_trusted() { $trustedProxy = $this->createTrustedProxy( Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO, '*' ); $request = $this->createProxiedRequest(); $trustedProxy->handle($request, function ($request) { $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy used forwarded header for IP'); $this->assertEquals('https', $request->getScheme(), 'Assert trusted proxy used forwarded header for scheme'); $this->assertEquals('serversforhackers.com', $request->getHost(), 'Assert trusted proxy used forwarded header for host'); $this->assertEquals(443, $request->getPort(), 'Assert trusted proxy used forwarded header for port'); }); } /** * Test to ensure it's reading text-based configurations and converting it correctly. */ public function test_is_reading_text_based_configurations() { $request = $this->createProxiedRequest(); // trust *all* "X-Forwarded-*" headers $trustedProxy = $this->createTrustedProxy('HEADER_X_FORWARDED_ALL', '192.168.1.1, 192.168.1.2'); $trustedProxy->handle($request, function (Request $request) { $this->assertEquals($request->getTrustedHeaderSet(), $this->headerAll, 'Assert trusted proxy used all "X-Forwarded-*" header'); $this->assertEquals($request->getTrustedProxies(), ['192.168.1.1', '192.168.1.2'], 'Assert trusted proxy using proxies as string separated by comma.'); }); // or, if your proxy instead uses the "Forwarded" header $trustedProxy = $this->createTrustedProxy('HEADER_FORWARDED', '192.168.1.1, 192.168.1.2'); $trustedProxy->handle($request, function (Request $request) { $this->assertEquals($request->getTrustedHeaderSet(), Request::HEADER_FORWARDED, 'Assert trusted proxy used forwarded header'); $this->assertEquals($request->getTrustedProxies(), ['192.168.1.1', '192.168.1.2'], 'Assert trusted proxy using proxies as string separated by comma.'); }); // or, if you're using AWS ELB $trustedProxy = $this->createTrustedProxy('HEADER_X_FORWARDED_AWS_ELB', '192.168.1.1, 192.168.1.2'); $trustedProxy->handle($request, function (Request $request) { $this->assertEquals($request->getTrustedHeaderSet(), Request::HEADER_X_FORWARDED_AWS_ELB, 'Assert trusted proxy used AWS ELB header'); $this->assertEquals($request->getTrustedProxies(), ['192.168.1.1', '192.168.1.2'], 'Assert trusted proxy using proxies as string separated by comma.'); }); } ################################################################ # Utility Functions ################################################################ /** * Fake an HTTP request by generating a Symfony Request object. * * @param array $serverOverRides * * @return \Symfony\Component\HttpFoundation\Request */ protected function createProxiedRequest($serverOverRides = []) { // Add some X-Forwarded headers and over-ride // defaults, simulating a request made over a proxy $serverOverRides = array_replace([ 'HTTP_X_FORWARDED_FOR' => '173.174.200.38', // X-Forwarded-For -- getClientIp() 'HTTP_X_FORWARDED_HOST' => 'serversforhackers.com', // X-Forwarded-Host -- getHosts() 'HTTP_X_FORWARDED_PORT' => '443', // X-Forwarded-Port -- getPort() 'HTTP_X_FORWARDED_PROTO' => 'https', // X-Forwarded-Proto -- getScheme() / isSecure() 'SERVER_PORT' => 8888, 'HTTP_HOST' => 'localhost', 'REMOTE_ADDR' => '192.168.10.10', ], $serverOverRides); // Create a fake request made over "http", one that we'd get over a proxy // which is likely something like this: $request = Request::create('http://localhost:8888/tag/proxy', 'GET', [], [], [], $serverOverRides, null); // Need to make sure these haven't already been set $request->setTrustedProxies([], $this->headerAll); return $request; } /** * Retrieve a TrustProxies object, with dependencies mocked. * * @param null|string|int $trustedHeaders * @param null|array|string $trustedProxies * * @return \Fideloper\Proxy\TrustProxies */ protected function createTrustedProxy($trustedHeaders, $trustedProxies) { // Mock TrustProxies dependencies and calls for config values $config = Mockery::mock('Illuminate\Contracts\Config\Repository') ->shouldReceive('get') ->with('trustedproxy.headers') ->andReturn($trustedHeaders) ->shouldReceive('get') ->with('trustedproxy.proxies') ->andReturn($trustedProxies) ->getMock(); return new TrustProxies($config); } }