Seems to be the place for apache so here goes :)
Age old problem: how so I redirect HTTP->HTTPS, then and only if HTTPS, do an auth?
Oh - and I'd like most of it in a single snippet that can be Include-ed in multiple <directory> or <location> blocks, so no virtual host level random path based rewrites...
Well, here's what I have that does seem to work:
In the top of a VirtualHost block
# Set ssl_off environment variable
RewriteEngine on
RewriteCond %{HTTPS} =on
RewriteRule ^ - [E=ssl]
In the location or directory block
RewriteEngine on
# Case 1 redirect port 80 SSL
RewriteCond %{HTTPS} !=on
RewriteCond %{SERVER_PORT} =80
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301]
AuthType Basic
AuthBasicProvider external
AuthExternal auth_pam
AuthName "My Underpants"
AuthzUnixgroup on
Order Deny,Allow
Deny from all
Allow from env=!ssl
Satisfy any
Require group nice-users
Pluses
All of that bar the Require's can be abstracted out to a snippet file to Include in one line on each location
It fixes forcing SSL and authentication together for each location, so less chance of mistakes
Minuses
Bloody hell, it is hardly intuitive! Might be fragile for all I know...
Is there a better way (not that I've found...)?
Comments would be very welcome on whether that has any serious flaws :)
Aside Life would be so much easier if Apache had a sensible config syntax with a generic
<If expression> </If>
block that could be used anywhere. It has certain special case blocks such as IfModule, and then you have special case conditionals like RewriteCond (which is very hard to grok if you're not used to it).
Cheers,
Tim
If you're wanting to force the entire site to https, you can use the VirtualHost directives, and then it's quite simple:
<VirtualHost *:80>
ServerName example.com
RedirectMatch (.*) https://example.com$1
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
...
...
...
</VirtualHost>
Tim Watts' solution seems to work best for me but needed a bit of tweaking. Also my situation is slightly different in that I wish to allow certain IP addresses without HTTP auth but this just adds an extra line.
mod_rewrite won't inherit config from the VirtualHost by default.
See: http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriteoptions
I was going to make use of "RewriteOptions inherit" but it seems that this applies the parent rules AFTER the child ones. In any case, I thought of a different solution.
Within my SSL <VirtualHost> I have the line:
SetEnvIf Request_URI "/" using_ssl=yes
This sets the using_ssl environment variable if the request URI contains a forward slash (i.e. all the time.) It's a bit of hack as I'd prefer to use the unconditional SetEnv but apparently:
The internal environment variables set by this directive are set after most early request processing directives are run, such as access control and URI-to-filename mapping. If the environment variable you're setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.
(source: http://httpd.apache.org/docs/2.2/mod/mod_env.html#setenv)
My config within my container looks like this:
# Require a basic HTTP auth user
AuthName "realm-name-goes-here"
AuthType Basic
AuthUserFile /var/www/etc/htpasswd
Require valid-user
# OR allow from non-SSL (which will be redirected due to mod_rewrite below!)
Order Allow,Deny
Allow from env=!using_ssl
# OR allow from a trusted IP range
# NB: This allows certain IPs without a username & password
Allow from 192.168.0.0/16
Satisfy Any
# Force a redirect to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=permanent]
You probably want to try with just 'R' instead of 'R=permanent' first for testing purposes.
Hope this is useful for others :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With