Forum Moderators: phranque

Message Too Old, No Replies

https to https question

Approaches to rewrite https://%{HTTP_HOST}:80 to http://%{HTTP_HOST}:80

         

fatzopilot

1:41 am on Aug 11, 2010 (gmt 0)

10+ Year Member



I have a tomcat backed dynamic webapp (mod_proxy) with a login page under /auth which should be secured by SSL (done by apache), whilst the rest should be delivered in plain http.
So the idea was to use mod_rewrite to force access to
http://%{HTTP_HOST}%/auth
like so
RewriteRule ^/auth(.*)$ https://%{HTTP_HOST}/auth$1 [L,R,NE,QSA]

The problem starts when the login is done, the browser is redirected to e.g.
https://%{HTTP_HOST}/somecontentnotauth:80
, i.e. the URL has a https prefix but still the browser uses port 80. This fails (ssl_error_rx_record_too_long in FF).
I haven't found I way to check for a https prefix to write it back to http (According to this [zytrax.com ] site, there does not seem to be an Apache Enviromental Variable that could be used for this purpose) .
This post [webmasterworld.com ] suggests, that it might not be feasible at all.
The app is used on several domains, so absolute links are not an option. Any ideas how this might work out nevertheless?

Thanks
fatzopilot

phranque

7:08 am on Aug 11, 2010 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



welcome to WebmasterWorld [webmasterworld.com], fatzopilot!

the port specification should immediately follow the hostname so i'm not sure where that came from or if it is really even doing anything for or against your efforts.
perhaps it is a typo.

in any case perhaps an additional redirect will solve your problem:

RewriteCond %{SERVER_PORT} =443
RewriteCond $1 !^auth
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]

if you have shared objects between http/https pages you may want to exclude those from being redirected.

fatzopilot

10:26 am on Aug 11, 2010 (gmt 0)

10+ Year Member



phranque, thanks for the warm welcome.
The complete redirect portions look like so:

<VirtualHost *:80>
RewriteEngine on
RewriteCond %{SERVER_PORT} ^80$
RewriteCond %{REQUEST_URI} ^/auth
RewriteRule ^/auth(.*)$ https://%{SERVER_NAME}/auth$1 [R=301,L,R,NE,QSA]
...

and
<VirtualHost *:443>
RewriteEngine on
RewriteCond %{SERVER_PORT} ^443$
RewriteCond %{REQUEST_URI} !^/auth
RewriteRule ^(.*)$ http://%{SERVER_NAME}/$1 [R=301,P,L,NE,QSA] #
...

I can completely deactivate rewrite in the 443 VH with no difference.
The URL I end up with after the login reads

https://%{HTTP_HOST}/somecontentnotauth:80

so it is handled by the *:80 VH.
Since checking for

%{SERVER_PORT} ^443$

does not make sense (the request is made on 80 and I think I can omit that port check anyway as the *:80 VH just gets all request on port 80), I need means to redirect a https prefixed URL on port 80 to a just http prefixed one in the VH *:80.
I haven't found a way to do so without causing infinite redirects so far :(
I also have completely no idea whether the offending URL should be as is (why is it on port 80 and not 443 so that it can be redirected by a redirect to plain http in the 443 VH?).

Cheers
fatzopilot

jdMorgan

1:17 pm on Aug 11, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Because of the way that Apache handles ports in the requests, http/https selection is done only on the basis of the requested protocol, and not on the value of the port number (if any) appended to the HTTP_HOST header. I suspect that you may have included the port number in your ServerName or ServerAlias directives, which would be the cause of the redirect to the incorrect port numbers... If so, remove them. I have used %{HTTP_HOST} in the RewriteRules below to avoid this effect. The RewriteConds must always use HTTP_HOST though, even if the ServerNames are corrected, because we want to redirect if the client gets it wrong.

The following code redirects if the protocol is incorrect or if the port number is actually appended to the HTTP_HOST request header. It also removes several superfluous and one incorrect RewriteRule flags. Exact string compares are used where possible to improve performance. Note corrected slash handling and removal of redundant "=a/auth" check from first rule.

<VirtualHost *:80>
RewriteEngine on
#
# If not an https protocol request
RewriteCond %{SERVER_PORT} !=433 [OR]
# or if explicit port number appended to HTTP_HOST request header
RewriteCond %{HTTP_HOST} :[0-9]+$
# redirect /auth requests to force https protocol
RewriteRule ^/(auth.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
...
#
<VirtualHost *:443>
RewriteEngine on
#
# If an https protocol request
RewriteCond %{SERVER_PORT} =443 [OR]
# or if explicit port number appended to HTTP_HOST request header
RewriteCond %{HTTP_HOST} :[0-9]+$
# and if not /auth request
RewriteCond %{REQUEST_URI} !^/auth
# and if not http/https shared-object request
RewriteCond $1 !\.(gif|jpe?g|png|ico|css|js)$
# redirect to force http protocol
RewriteRule ^/(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]
...

Note the exclusion of object-types commonly shared between http and https pages such as images, css, and external JavaScripts in the second rule. This type of exclusion is often required in order to prevent "Mixed Secure/Insecure Content" warnings in the browser when such objects are included by both http and https pages (i.e. they are 'shared' by both types of pages). It is generally only needed in the rule with the negative URL-path match (for example, consider the effect of all images stored at path "/images" on the action of each rule here).

Flags:

[NE] (No Escape) is not needed unless you wish to pass percent-encoded URL-path characters without URL-escaping.

[P] (Proxy through-put) invokes a reverse proxy through-put -- Certainly not desirable on the http side. If your tomcat apps are Aliased (see Apache mod_alias), then the [PT] (Pass-Through) flag may be required, but the [P] is different.

[QSA] (Query String Append) is not needed unless new query string parameters are to be appended by the rule. If not additional parameters are present in the substitution URL, existing queries will be passed through unchanged even in the absence of this flag.

Jim

jdMorgan

1:51 pm on Aug 11, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Added: You can do away with the RewriteConds checking %{SERVER_PORT} if you wish, since the requests will only resolve to the appropriate <VirtualHost> container and execute the code based on that port number. As such, these RewriteConds are redundant. The RewriteConds checking %{HTTP_HOST} however, are not: They are looking for port numbers appended to the HTTP Host request header, and function as commented.

Jim

fatzopilot

2:33 pm on Aug 11, 2010 (gmt 0)

10+ Year Member



Jim,

Thank you very much for you valuable insights. I did as you proposed (there are no names or aliases with port numbers) but the effect stayed the same. Seems to be a tough nut to crack :(
I thought it might be a good idea to provide the complete VH-host files because the AJP proxying might be involved in causing the issue.
These are basically modified default files with spare comments ommitted:


<VirtualHost *:80>
ServerAdmin webmaster@server.com
ServerName my.server.com #it indeed is on a subdomain on a different machine, could that be a problem?
RewriteEngine on

# If not an https protocol request
RewriteCond %{SERVER_PORT} !=433 [OR]
# or if explicit port number appended to HTTP_HOST request header
RewriteCond %{HTTP_HOST} :[0-9]+$
# redirect /auth requests to force https protocol
RewriteRule ^/(auth.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 9

ProxyPass / ajp://my.server.com:8009/
#Don't use proxy for gwt static content
ProxyPass /gwt !
# Aliases, dont't use proxy for these directories
Alias /gwt "/var/lib/tomcat6/webapps/ROOT/gwt"
<Directory /var/lib/tomcat6/webapps/ROOT/gwt>
Options FollowSymLinks
Allow from all
Order allow,deny
</Directory>
<Location />
ProxyPassReverse http://my.server.com/
Order allow,deny
Allow from all

#agressively cache static content (there are no static pages)
ExpiresActive On
ExpiresByType text/html "modification plus 1 year"
ExpiresByType image/gif "modification plus 1 year"
ExpiresByType image/png "modification plus 1 year"
ExpiresByType image/jpg "modification plus 1 year"
ExpiresByType application/x-javascript "modification plus 1 year"
ExpiresByType text/javascript "modification plus 1 year"
ExpiresByType text/css "modification plus 1 year"
ExpiresByType text/html "modification plus 1 year"
ExpiresByType text/xml "modification plus 1 year"
Header set Cache-Control "public, no-transform"

#enable compression
SetOutputFilter DEFLATE
# Insert filter
</Location>

# Don't compress images
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary

# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary

DeflateBufferSize 259072
DeflateCompressionLevel 9

ErrorLog /var/log/apache2/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog /var/log/apache2/access.log combined
</VirtualHost>

SSL:

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster@server.com
ServerName my.server.com
ErrorLog /var/log/apache2/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog /var/log/apache2/ssl_access.log combined

RewriteEngine on

# If an https protocol request
RewriteCond %{SERVER_PORT} =443 [OR]
# or if explicit port number appended to HTTP_HOST request header
RewriteCond %{HTTP_HOST} :[0-9]+$
# and if not /auth request
RewriteCond %{REQUEST_URI} !^/auth
# and if not http/https shared-object request
RewriteCond $1 !\.(gif|jpe?g|png|ico|css|js)$
# redirect to force http protocol
RewriteRule ^/(.*)$ http://%{HTTP_HOST}/$1 [R=301,L,P,NE,QSA]

RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 9

ProxyRequests Off
ProxyPreserveHost On

ProxyPass / ajp://my.server.com:8009/
<Location />
ProxyPassReverse https://my.server.com/
Order allow,deny
Allow from all
</Location>

SSLEngine on

SSLCertificateFile /etc/ssl/cert/server.com.pem
SSLCertificateKeyFile /etc/ssl/private/server.com.key

SSLCertificateChainFile /etc/ssl/certs/startSSL.intermediate.sub.class1.server.ca.pem
SSLCACertificateFile /etc/apache2/ssl.crt/startSSL.root.ca.pem

<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>

BrowserMatch "MSIE [2-6]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

</VirtualHost>
</IfModule>


In addition, here is the rewrite log which is generated when the login is invoked:

(2) init rewrite engine with requested uri /
(3) applying pattern '^/(auth.*)$' to uri '/'
(1) pass through /
(2) init rewrite engine with requested uri /overview
(3) applying pattern '^/(auth.*)$' to uri '/overview'
(1) pass through /overview
(2) init rewrite engine with requested uri /auth/login
(3) applying pattern '^/(auth.*)$' to uri '/auth/login'
(4) RewriteCond: input='80' pattern='!=433' => matched
(2) rewrite '/auth/login' -> 'https://my.server.com/auth/login'
(2) explicitly forcing redirect with https://my.server.com/auth/login
(1) escaping https://my.server.com/auth/login for redirect
(1) redirect to https://my.server.com/auth/login?targetUri=%252Foverview [REDIRECT/301]
(2) init rewrite engine with requested uri /auth/login
(3) applying pattern '^/(.*)$' to uri '/auth/login'
(4) RewriteCond: input='443' pattern='=443' => matched
(4) RewriteCond: input='/auth/login' pattern='!^/auth' => not-matched
(1) pass through /auth/login

and here is what happens when the login is done

(2) init rewrite engine with requested uri /auth/signIn
(3) applying pattern '^/(.*)$' to uri '/auth/signIn'
(4) RewriteCond: input='443' pattern='=443' => matched
(4) RewriteCond: input='/auth/signIn' pattern='!^/auth' => not-matched
(1) pass through /auth/signIn
(2) init rewrite engine with requested uri /
(3) applying pattern '^/(auth.*)$' to uri '/'
(1) pass through /


Then there is this URL

https://my.server.com:80/auth/%2Foverview

in the browser address bar which causes the error.
Are there maybe other files or logs which could be important here?

Thanks
fatzopilot

jdMorgan

4:38 pm on Aug 12, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Please re-read the explanation of "Flags" in my previous posts. You have not taken action in this regard.

Jim

fatzopilot

8:02 pm on Aug 12, 2010 (gmt 0)

10+ Year Member



Jim,

sorry for this negligence, I removed the flags such that it now reads
RewriteRule ^/(.*)$ http://%{HTTP_HOST}/$1 [R=301,L]

but there is still no difference...

jdMorgan

10:40 pm on Aug 12, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Please see the [P] and [PT] flag descriptions.

If you wish the output of mod_rewrite to be processed by mod_alias, use [PT].

If mod_alias 'triggers' on a requested URL, it will change the URL *before* mod_rewrite can process it, so mod_rewrite will have no effect. Make sure that mod_alias cannot "grab" URLs from mod_rewrite in this manner by making the Alias trigger on the *output* URL-path from mod_rewrite, not the input URL-path.

To clarify. Note that directives are processed on a per-module basis, and not in the order that you put them in a config file. Only directives of the same module will execute in the order you specify. Apache config files should never be confused with "sequentially-processed scripts."

Jim

fatzopilot

5:53 pm on Aug 13, 2010 (gmt 0)

10+ Year Member



Hi Jim,

Thanks for your response.
If I blindly add PT to the rewriteRule flags,i.e.:

# redirect /auth requests to force https protocol
RewriteRule ^/(auth.*)$ https://%{HTTP_HOST}/$1 [R=301,PT,L]

in VH *:80 and

# redirect to force http protocol
RewriteRule ^/(.*)$ http://%{HTTP_HOST}/$1 [R=301,PT,L]

in VH *:443
all I get is a

"Bad Request

Your browser sent a request that this server could not understand."

in FF.

The reason why I use the alias is just to tell apache to serve the gwt stuff (js) directly from the disk and to avoid unnecessary proxying and processing of it by tomcat. So it should not change any URL or so, it should just tell apache to source the content from elsewhere.
If aliasing is completely deactivated, (and the corresponding lines in the config file commented, i.e.:
#Don't use proxy for gwt static content
#ProxyPass /gwt !
# Aliases, dont't use proxy for these directories
#Alias /gwt "/var/lib/tomcat6/webapps/ROOT/gwt"
#<Directory /var/lib/tomcat6/webapps/ROOT/gwt>
#Options FollowSymLinks
#Allow from all
#Order allow,deny
#</Directory>
#<Location />

and
a2dismod alias

the problem persists.
Am I still confusing something?

Thanks again, I am really appreciating your help :)
fatzopilot

jdMorgan

7:10 pm on Aug 13, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You can't "blindly" do anything in server config files like this... :o

[PT] is used only if you wish to pass the output of a rewriterule to another module, such as mod_proxy. It tells mod_rewrite NOT to convert the requested URL-path to a filepath representation, but rather to leave it as a URL-path, so that other modules (which like mod_rewrite assume that their input will be a URL-path) can function properly.

[P] is used to immediately force a proxy through-put, and can be used to allow a rewriterule to replace one or more mod_proxy Alias, AliasMatch, ScriptAlias, and ScriptAliasMatch directive(s).

I will try to re-review the code dump later today, but in the meantime I'd suggest some research at apache.org to find out what each of your directives means and does... to avoid "blindness." :)

Jim

fatzopilot

12:10 am on Aug 16, 2010 (gmt 0)

10+ Year Member



Jim,

I've discovered possible idiosyncrasies with redirects in the web framework I am using when SSL is used. Maybe they are the root of the problem, so I think it makes sense to clear these things first before getting back to the apache config. I'll get back to this thread when there are new answers or questions. Many Thanks for taking the time to shed some light on this issue so far.

Cheers
fatzopilot

jdMorgan

1:53 am on Aug 19, 2010 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> idiosyncrasies with redirects in the web framework I am using

Ugh! I hate it when that happens...

Best of luck with that part of the project.

Jim