Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache 2.2 redirect to SSL *then* do auth (with solution < but is it crap?)

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

like image 824
Tim Watts Avatar asked Jun 23 '11 17:06

Tim Watts


2 Answers

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>
like image 84
Corey Henderson Avatar answered Nov 10 '22 22:11

Corey Henderson


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 :)

like image 44
BenKennish Avatar answered Nov 10 '22 20:11

BenKennish