Skip to content

Commit

Permalink
add proxy detection middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
wellingguzman committed Dec 12, 2018
1 parent a652ed7 commit e32b10b
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 281 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"league/oauth1-client": "^1.7",
"intervention/image": "^2.4",
"wellingguzman/oauth2-okta": "dev-master",
"wellingguzman/proxy-detection": "^0.5.1",
"cache/cache": "^1.0",
"akrabat/rka-ip-address-middleware": "^0.5.0",
"firebase/php-jwt": "^5.0",
Expand Down
7 changes: 7 additions & 0 deletions migrations/db/seeds/FieldsSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,13 @@ public function run()
'interface' => 'color-palette',
'locked' => 1
],
[
'collection' => 'directus_settings',
'field' => 'trusted_proxies',
'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING,
'interface' => 'text-input',
'locked' => 1
],


// Users
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php


use Phinx\Migration\AbstractMigration;

class AddTrustedProxiesSettingField extends AbstractMigration
{
public function up()
{
$result = $this->query('SELECT 1 FROM `directus_settings` WHERE `key` = "trusted_proxies";')->fetch();

if (!$result) {
$this->execute("INSERT INTO `directus_settings` (`key`, `value`) VALUES ('trusted_proxies', '');");
}
}
}
6 changes: 5 additions & 1 deletion src/core/Directus/Util/Installation/InstallerUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,11 @@ private static function getDefaultSettings($data)
[
'key' => 'youtube_api_key',
'value' => ''
]
],
[
'key' => 'trusted_proxies',
'value' => ''
],
];
}

Expand Down
125 changes: 54 additions & 71 deletions src/helpers/all.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
namespace Directus;

use Directus\Application\Application;
use Directus\Application\Http\Request;
use Directus\Database\TableGatewayFactory;
use Directus\Exception\Exception;
use Directus\Hook\Emitter;
use Directus\Util\ArrayUtils;
use Directus\Util\StringUtils;
use Phinx\Db\Adapter\AdapterInterface;
use RKA\Middleware\ProxyDetection;
use Slim\Http\Cookies;
use Slim\Http\Environment;
use Slim\Http\Headers;
use Slim\Http\RequestBody;
use Slim\Http\UploadedFile;
use Slim\Http\Uri;

require __DIR__ . '/constants.php';
require __DIR__ . '/app.php';
Expand Down Expand Up @@ -136,90 +144,65 @@ function get_url($path = '')
}
}

if (!function_exists('create_uri_from_global')) {
if (!function_exists('create_request_from_global')) {
/**
* Creates a uri object based on $_SERVER
* Create a Request object from global variables
*
* Snippet copied from Slim URI class
* @param array $options
*
* @return \Slim\Http\Uri
* @return Request
*/
function create_uri_from_global()
function create_request_from_global($options = [])
{
// Scheme
$env = $_SERVER;
$isSecure = \Directus\Util\ArrayUtils::get($env, 'HTTPS');
$scheme = (empty($isSecure) || $isSecure === 'off') ? 'http' : 'https';

// Authority: Username and password
$username = \Directus\Util\ArrayUtils::get($env, 'PHP_AUTH_USER', '');
$password = \Directus\Util\ArrayUtils::get($env, 'PHP_AUTH_PW', '');

// Authority: Host
if (\Directus\Util\ArrayUtils::has($env, 'HTTP_HOST')) {
$host = \Directus\Util\ArrayUtils::get($env, 'HTTP_HOST');
} else {
$host = \Directus\Util\ArrayUtils::get($env, 'SERVER_NAME');
$environment = new Environment($_SERVER);
$method = $environment['REQUEST_METHOD'];
$uri = Uri::createFromEnvironment($environment);
$headers = Headers::createFromEnvironment($environment);
$cookies = Cookies::parseHeader($headers->get('Cookie', []));
$serverParams = $environment->all();
$body = new RequestBody();
$uploadedFiles = [];
$ignorePayload = array_get($options, 'ignore_payload', false) === true;

if (!$ignorePayload) {
$uploadedFiles = UploadedFile::createFromEnvironment($environment);
}

// Authority: Port
$port = (int)\Directus\Util\ArrayUtils::get($env, 'SERVER_PORT', 80);
if (preg_match('/^(\[[a-fA-F0-9:.]+\])(:\d+)?\z/', $host, $matches)) {
$host = $matches[1];

if (isset($matches[2])) {
$port = (int)substr($matches[2], 1);
} else {
$port = $isSecure ? 443 : 80;
}
} else {
$pos = strpos($host, ':');
if ($pos !== false) {
$port = (int)substr($host, $pos + 1);
$host = strstr($host, ':', true);
} else {
$port = $isSecure ? 443 : 80;
}
}

// Path
$requestScriptName = parse_url(\Directus\Util\ArrayUtils::get($env, 'SCRIPT_NAME'), PHP_URL_PATH);
$requestScriptDir = dirname($requestScriptName);

// parse_url() requires a full URL. As we don't extract the domain name or scheme,
// we use a stand-in.
$requestUri = parse_url('http://example.com' . \Directus\Util\ArrayUtils::get($env, 'REQUEST_URI'), PHP_URL_PATH);

$basePath = '';
$virtualPath = $requestUri;
if ($requestUri == $requestScriptName) {
$basePath = $requestScriptDir;
} elseif (stripos($requestUri, $requestScriptName) === 0) {
$basePath = $requestScriptName;
} elseif ($requestScriptDir !== '/' && stripos($requestUri, $requestScriptDir) === 0) {
$basePath = $requestScriptDir;
}
$request = new Request($method, $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles);

if ($basePath) {
$virtualPath = ltrim(substr($requestUri, strlen($basePath)), '/');
if (
!$ignorePayload
&& $method === 'POST'
&& in_array($request->getMediaType(), ['application/x-www-form-urlencoded', 'multipart/form-data'])
) {
// parsed body must be $_POST
$request = $request->withParsedBody($_POST);
}

// Query string
$queryString = \Directus\Util\ArrayUtils::get($env, 'QUERY_STRING', '');
if ($queryString === '') {
$queryString = parse_url('http://example.com' . \Directus\Util\ArrayUtils::get($env, 'REQUEST_URI'), PHP_URL_QUERY);
}
return $request;
}
}

// Fragment
$fragment = '';
if (!function_exists('create_uri_from_global')) {
/**
* Creates a uri object based on $_SERVER
*
* Snippet copied from Slim URI class
*
* @param $checkProxy
*
* @return \Psr\Http\Message\UriInterface
*/
function create_uri_from_global($checkProxy = true)
{
$request = create_request_from_global(['ignore_payload' => true]);

// Build Uri
$uri = new \Slim\Http\Uri($scheme, $host, $port, $virtualPath, $queryString, $fragment, $username, $password);
if ($basePath) {
$uri = $uri->withBasePath($basePath);
if ($checkProxy) {
$proxyDetection = new ProxyDetection(get_trusted_proxies());
$request = $proxyDetection->processRequestIfTrusted($request);
}

return $uri;
return $request->getUri();
}
}

Expand All @@ -231,7 +214,7 @@ function create_uri_from_global()
*/
function get_virtual_path()
{
return create_uri_from_global()->getPath();
return create_uri_from_global(false)->getPath();
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/helpers/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Directus;

use Directus\Application\Application;
use Directus\Util\StringUtils;

if (!function_exists('get_directus_settings')) {
/**
Expand Down Expand Up @@ -116,3 +117,15 @@ function get_directus_settings_by_keys(array $keys)
return $settings;
}
}

if (!function_exists('get_trusted_proxies')) {
/**
* @return array
*/
function get_trusted_proxies()
{
$trustedProxies = get_directus_setting('trusted_proxies');

return $trustedProxies ? StringUtils::safeCvs($trustedProxies) : [];
}
}
Loading

0 comments on commit e32b10b

Please sign in to comment.