Jump to content

SSL usage not recognized when using SSL Proxy


Recommended Posts

I'm experimenting with prestashop (1.5.6.0, according to _PS_VERSION_) and have a fairly typical setup of apache behind an SSL proxy. This works, in as much as I can visit an https page, however, Prestashop fails to detect that an SSL proxy is in use and thinks everything is on HTTP, and links everything to http URLs (why it isn't simply using relative URLs is beyond me, but that's beside the point), which of course means SSL never really sticks around. E.g., I can't enable it inside the admin interface, and even if I could it wouldn't recognize users were using SSL either, and would constantly be sending them back to non-SSL pages.

 

So the question is how do I get it to detect SSL with a proxy in front?

 

I'm hesitant to just modify Tools::usingSecureMode() (and possibly other functions which may need it) since it's been my experience that modifying central files tends to break upgrades when the upgrade overwrites the file and then dies halfway through because it no longer detects the thing it was looking for, so I was hoping there's some way I'm missing.

 

Some relevant data from $_SERVER:

Array (

[HTTP_X_FORWARDED_FOR] => 10.122.69.49

[HTTP_X_FORWARDED_PROTO] => https

[PATH] => /usr/local/bin:/usr/bin:/bin

[sERVER_SOFTWARE] => Apache/2.2.22 (Debian)

[sERVER_ADDR] => 127.0.0.1

[sERVER_PORT] => 80

[sERVER_PROTOCOL] => HTTP/1.0

[REQUEST_METHOD] => GET

)

 

Thanks!

Link to comment
Share on other sites

This guy give a clear set of instructions of setting up Apache as a proxy with SSL. It is not for Prestashop but it may give you a guide. It mentions all of the modules that need to be installed and gives great examples.

 

http://dev.mensfeld.pl/2013/06/jenkins-behind-apache-with-https-proxy-pass-with-ssl/

 

 

<VirtualHost *:443>
  ServerName jenkins.my.domain
  ServerAlias www.jenkins.my.domain
 
  SSLEngine On
  SSLCertificateFile    /etc/apache2/ssl/crt/jenkins.my.domain.crt
  SSLCertificateKeyFile /etc/apache2/ssl/key/jenkins.my.domain.key
 
  ProxyRequests     Off
  ProxyPass         /  http://localhost:8080/
  ProxyPassReverse  /  http://localhost:8080/
  ProxyPassReverse  /  http://my.jenkins.host/
    Order allow,deny
    Allow from all
  </Proxy>
  ProxyPreserveHost on
</VirtualHost>

 

 

To create a SSL Proxy pass we need to install some Apache mods (still as a root):

a2enmod proxy
a2enmod proxy_http
a2enmod rewrite
a2enmod ssl

Link to comment
Share on other sites

Thanks Bill, but I already /have/ an SSL proxy set up. My problem is that Prestashop doesn't seem to attempt to detect this case (e.g., by checking X-Forwarded-Proto), and I'm not sure how to explicitly override its incorrect detection in a way that will survive upgrades, etc.

Link to comment
Share on other sites

So you have your SSL domain name and you have put that domain in

Preferences  > SEO & URLs

SSL Domain

You then go to

Preferences  > General

Enable SSL You click on "Please click here to use HTTPS protocol before enabling SSL."

What happens at that point?

 

Can you put a plain html page in your PS folder and load that page VIA your SSL domain?

Link to comment
Share on other sites

You then go to Preferences > General

Enable SSL You click on "Please click here to use HTTPS protocol before enabling SSL."

What happens at that point?

At that point, I get taken to the same page, but via SSL, and it continues to say "Please click here to use HTTPS protocol before enabling SSL.".

 

Can you put a plain html page in your PS folder and load that page VIA your SSL domain?

Yes. The proxy works fine, I'm just not seeing anything in Prestashop's code which attempts to detect an SSL proxy in use, and I'm not sure where a safe, upgrade-surviving place to put a snippet like the following to fake it out would be:

 

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
  $_SERVER['HTTPS'] = 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ? 'on' : 'off';
}
Link to comment
Share on other sites

Sorry for the preliminary questions. I would say you have it correctly setup and that for whatever reason PS can't pickup on that. This is the same with some setups for the rewrite modules.

 

I suggest you bypass the current code that is incorrectly looking for your SSL, and edit your PS database directly.

 

In the ps_configuration table change id_configuration #31 Name ps_SSL_Enabled from "0" to "1"

 

Let me know if that works for you.

Link to comment
Share on other sites

No worries on the prelim questions. I appreciate the help. :)

 

Forcing SSL on without having a way for it to detect SSL is in use just results in infinite redirects on pages which are forced to SSL (e.g., /en/order-history), presumably because without detecting the SSL proxy it mistakenly thinks the end user is not using SSL, and so redirects to HTTPS, where it doesn't detect SSL and ... well, you get the idea.

 

If I add in my little snippet to munge $_SERVER['HTTPS'] it appears to function correctly, but that's not really a permanent solution without some place I can put it that'll survive upgrades.

Link to comment
Share on other sites

Found a patch for Classes/Tools.php

 

After you apply it, to make it work, you can simply add this to config.inc.php

/* Proxy settings */
 define('PS_PROXY_SERVER', 'http://proxy.example.com');
 define('PS_PROXY_PORT', '3128');
 define('PS_PROXY_USER', 'presta');
 define('PS_PROXY_PASS', 'shop');

 

Download the patch here,

http://forge.prestashop.com/browse/PSCFV-9498

 

Hope this helps.

Edited by Bill Dalton (see edit history)
Link to comment
Share on other sites

Well that does involve proxying, yes, but unfortunately that's for an entirely different thing (Prestashop talking to other servers, not browsers talking to Prestashop). My problem is a "reverse proxy" scenario. Apologies for any confusion caused by my loose terminology earlier. Basically, the user's browser connects to a server (nginx, lighttpd, whatever) which handles the SSL, then forwards the request on to apache as a regular (non-SSL) HTTP request with some additional headers such as X-Forwarded-Proto and X-Forwarded-For, so one can distinguish betwixt client requests.

 

Thus, $_SERVER['HTTPS'] is never "on" because apache never deals with the SSL, and Prestashop never checks the de-facto standard header added by the reverse proxy to tell it what protocol is being used for the client connection, so it never detects SSL is in use for the client connection.

 

Since Prestashop doesn't appear to have native support for this mode of operation, I can fake it with a bit of smoke and mirrors, but I'm not familiar enough with the software yet to know what file (if any) is both going to be used on every request and would be safe to splice in a fix without worrying about being overwritten on upgrades. (E.g., is config/settings.inc.php safe, or is that a candidate for being rewritten on upgrades?)

Link to comment
Share on other sites

I looked at the code in the patch. I feel certain that it will solve all problems related to proxy servers and Prestashop, at least in how I understand what is needed.

 

You seem to have a unique problem that I just don't understand. I hope someone else can post or if you ever find a fix I hope you will share.

 

I'll post the patch here for anyone else that may need it.

 

diff --git a/classes/Tools.php b/classes/Tools.php
index 7617dde..ab43fb7 100644
--- a/classes/Tools.php
+++ b/classes/Tools.php
[spam-filter] -1281,9 +1281,7 [spam-filter] class ToolsCore
  {
   if ($stream_context == null && preg_match('/^https?:\/\//', $url))
    $stream_context = @stream_context_create(array('http' => array('timeout' => $curl_timeout)));
-  if (in_array(ini_get('allow_url_fopen'), array('On', 'on', '1')) || !preg_match('/^https?:\/\//', $url))
-   return @file_get_contents($url, $use_include_path, $stream_context);
-  elseif (function_exists('curl_init'))
+  if (function_exists('curl_init'))
   {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
[spam-filter] -1301,10 +1299,18 [spam-filter] class ToolsCore
      curl_setopt($curl, CURLOPT_POSTFIELDS, $datas);
     }
    }
+   if ((defined('_PS_PROXY_SERVER_')) && (defined('_PS_PROXY_PORT_'))) {
+    curl_setopt( $curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
+    curl_setopt( $curl, CURLOPT_PROXY, _PS_PROXY_SERVER_ );
+    curl_setopt( $curl, CURLOPT_PROXYPORT, _PS_PROXY_PORT_ );
+    curl_setopt( $curl, CURLOPT_USERPWD, _PS_PROXY_USER_.':'._PS_PROXY_PASS_ );
+   }
    $content = curl_exec($curl);
    curl_close($curl);
    return $content;
   }
+  elseif (in_array(ini_get('allow_url_fopen'), array('On', 'on', '1')) || !preg_match('/^https?:\/\//', $url))
+   return @file_get_contents($url, $use_include_path, $stream_context);
   else
    return false;
  }

Edited by Bill Dalton (see edit history)
Link to comment
Share on other sites

I looked at the code in the patch. I feel certain that it will solve all problems related to proxy servers and Prestashop, at least in how I understand what is needed.

Alas, I am apparently incapable of explaining the problem in a way which puts us at an even understanding. But certainly modifying Tools::file_get_contents() is not going to help Tools::usingSecureMode() return the correct value. I appreciate the effort, though.

 

You seem to have a unique problem that I just don't understand. I hope someone else can post or if you ever find a fix I hope you will share.

Maybe not entirely unique (this post was almost certainly the same issue, for instance), but yeah, it's not something you're going to run into on generic el-cheapo webhost 37.

 

And I did post a workaround :P, though I still don't know if where I put it (settings.inc.php) is upgrade-safe.

Link to comment
Share on other sites

... I just would like to be clear about your workaround. Actually, you can /resolve/ this by put the line "$_SERVER['HTTPS']" in "settings.inc.php" for exemple ?

The three lines I posted (and have duplicated below) appear to work for me, in my environment, yes. But as I've mentioned, I don't know if settings.inc.php is modified during the upgrade process, so I'd be hesitant to consider it a permanent fix.

 

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
  $_SERVER['HTTPS'] = 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ? 'on' : 'off';
}
  • Like 1
Link to comment
Share on other sites

×
×
  • Create New...