Problem/Motivation

This feature request is to make the kernel capable of rewriting the scheme of the base_url, when the base_url has been set in the settings.php file.

This is necessary if a website is behind a crypto off-loader, the base_url is set and the website can be accessed over both HTTP and HTTPS.

Proposed resolution

My proposed solution is to create a new setting, reverse_proxy_proto_change, defaulting to FALSE, which would instruct the kernel to alter the base_url scheme as needed.

Remaining tasks

I will be writing and submitting the patch shortly.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

t0xicCode’s picture

The patch allows initializeRequestGlobals to rewrite the base_url scheme if necessary to use links with the correct URI.

t0xicCode’s picture

Status: Active » Needs review
mgifford’s picture

Issue tags: +Security

Seems to work nicely when I applied this on SimplyTest.me. Haven't done any further work though.

t0xicCode’s picture

Nice with ST.me!

In addition, to exhaustively test the patch, the best way is to setup a local install of d8, install the patch, and configure apache to add the X-Forwarded-Proto with the https value (add RequestHeader set X-Forwarded-Proto "https" to the vhost configuration). The $base_url should be set to an url with the http scheme, and reverse_proxy_proto_change should be set to TRUE.

From there, absolute urls should be constructed with https.

mparker17’s picture

Assigned: t0xicCode » Unassigned
Status: Needs review » Needs work
Issue tags: +Needs tests

As instructed:

  1. I set RequestHeader set X-Forwarded-Proto "https" in my Apache config,
  2. I reloaded Apache,
  3. I set $settings['reverse_proxy_proto_change'] = TRUE; and $base_url = 'http://test_d8.dev'; in settings.php, and,
  4. I loaded the page over https.

Without the patch applied, all absolute links in the source (to stylesheets, etc) started with http (i.e.: used the unmodified $base_url). With the patch applied, all absolute links in the source (to stylesheets, etc) started with http (i.e.: used the modified $base_url). I'd say this is working as-intended.

The code looks good, but is missing tests.

I initially thought it might be really hard to test this because $base_url is a global, but there's already a bunch of tests in \Drupal\Tests\Core\Routing\UrlGeneratorTest::testPathBasedURLGeneration() that test generating URLs with custom $base_urls.

\Drupal\Tests\Core\Site\SettingsTest may also be useful, as it contains examples of how to set $settings within a test.

t0xicCode’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
6.07 KB
6.08 KB

I've passed some time debugging this in more details, and I noticed that initializeRequestGlobals was called too early in the process for the request to be aware of whether it was behind a reverse proxy (or crypto offloader).

To fix that, I've moved the relevant code for this issue in the \Drupal\Core\EventSubscriber\ReverseProxySubscriber class.

I've also added a test suite which should cover this use-case.

mgifford’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

No longer applies.

ravi.khetri’s picture

Status: Needs work » Needs review
FileSize
4.66 KB

ReRolled.

Status: Needs review » Needs work

The last submitted patch, 8: 2296555_8.patch, failed testing.

t0xicCode’s picture

+++ b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
@@ -60,6 +63,60 @@ public function testReverseProxyEnabled($provided_settings) {
+    $subscriber = new ReverseProxySubscriber($settings);

ReverseProxySubscriber is no more, as we've moved to stackphp #2303673: Implement stackphp; cleanup handlePageCache() and preHandle().

piyuesh23’s picture

Status: Needs work » Needs review
Issue tags: +#DCM2015

Test file has already been updated. Re-queuing it for testing.

mgifford’s picture

Status: Needs review » Needs work

The latest patch is still using ReverseProxySubscriber() for tests.

Sharique’s picture

Status: Needs work » Needs review
FileSize
4.88 KB
3.47 KB

Here is updated patch.

Status: Needs review » Needs work

The last submitted patch, 13: 2296555_13.patch, failed testing.

t0xicCode’s picture

Status: Needs work » Needs review
FileSize
7.43 KB
4.99 KB

Also added support for the other X-Forwarded-* headers, as they are needed for correct operation.

mparker17’s picture

I just did a code review. Seems to conform to Drupal coding standards.

A few things I noticed:

  1. +++ b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
    @@ -36,11 +36,14 @@ public function setUp() {
    +    $this->assertEquals(FALSE, $settings->get('reverse_proxy'));
    
    @@ -54,9 +57,54 @@ public function testNoProxy() {
    +    $settings = new Settings(array('reverse_proxy' => 1) + $provided_settings);
    ...
    +      'reverse_proxy' => 1,
    ...
    +      'reverse_proxy' => 1,
    

    Inconsistent variable type usage (TRUE/FALSE vs 1/0).

  2. +++ b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
    @@ -54,9 +57,54 @@ public function testNoProxy() {
    +      'reverse_proxy_addresses' => array('127.0.0.2'),
    ...
    +    $request->server->set('REMOTE_ADDR', '127.0.0.2');
    ...
    +      'reverse_proxy_addresses' => array('127.0.0.2'),
    ...
    +    $request->server->set('REMOTE_ADDR', '127.0.0.2');
    

    "127.0.0.2" seems like a "magic number (constant)". Should it be defined in a constant or variable in the test object?

    Probably not a big deal in a test.

... other than those things, it looks fine.

mparker17’s picture

Status: Needs review » Needs work
Issue tags: -Needs reroll +Needs beta evaluation

One more thing to note: if you want code committed to Drupal 8.0.x now that we're in beta, you'll need to fill out a Beta Evaluation to determine if it meets the criteria allowed changes during the Drupal 8 beta phase. If it doesn't apply, you'll have to mark it for Drupal 8.1.x. :S

mparker17’s picture

Also reading through the core gates to see if this issue passes... a couple of notes:

Documentation gate:

  1. An update to the issue summary would be nice (especially the Remaining tasks section; plus it would be good to add the User interface changes and API changes sections)
  2. Is there a specification/best-practice for reverse proxies and/or the X_FORWARDED_* headers? If so, please link to it in both the issue summary and in the code so both the core maintainers looking to commit the changes and folks who stumble across the code in the future can read more about what it does / how it works and confirm you wrote code that uses those standards/best-practices.
  3. You should also write a change record.

Performance gate: I don't think you need to do anything (doesn't apply).
Accessibility gate: I don't think you need to do anything (doesn't apply).
Usability gate: I don't think you need to do anything (doesn't apply).
Testing gate: I don't think you need to do anything (already done).

t0xicCode’s picture

Status: Needs work » Closed (duplicate)

Reviewing this, I believe that the issue can be closed, and all work migrated to #313145: Support X-Forwarded-* HTTP headers alternates.