Bram Bram - 2 months ago 22
Apache Configuration Question

.htaccess basic auth combined with ip restriction

I would like to block a path from my site using the .htaccess configuration. The idea is that only a specific set of IP's can access that specific path from the URL after they authenticated using basic auth.

Note: It's a path, not a page or directory. We are trying to shield off a web-service so there will be only post calls to the URL's.

I would like the url

example.com/rest
to be blocked and everything behind that url based on IP. So
example.com/rest/foo
and
example.com/rest/foo/bar
should be blocked.

All other paths from the application should remain functional and without basic auth.

The IP blocking part has been resolved in a previous question I asked.

The basic configuration (the blocking part, there is more in the .htaccess but is not relevant to this question.) you can find below.

SetEnvIf Request_URI "/rest(/.*)?$" rest_uri
# Check on what subdomain we are.
SetEnvIf Host ^local\. None_Prod_Env

# Static
SetEnvIf AH_CLIENT_IP ^123\.123\.123\.123$ Allow_Host
# Range
SetEnvIf AH_CLIENT_IP ^123\.123\.123\. Allow_Host

Order deny,allow
Deny from all
Allow from env=!rest_uri
Allow from env=Allow_Host
Allow from env=None_Prod_Env


So the configuration above blocks all access to /rest/* but not to non rest paths, it allows a user coming from IP X (Allow_Host variable) and we allow none production environments in this case local.

I tried to extend this functionality with basic auth like so:

SetEnvIf Request_URI "/rest(/.*)?$" rest_uri
SetEnvIfNoCase Request_URI "/rest(/.*)?$" require_auth=true

# ... Allow Host stuff and none prod stuff ...

Order deny,allow
Deny from all
Allow from env=!rest_uri
Allow from env=Allow_Host
Allow from env=None_Prod_Env

AuthName "Password Protected"
AuthType Basic
AuthBasicProvider file
AuthUserFile /var/www/html/.htpasswd
Require valid-user


However this resulted in a basic auth on all pages and not only for the /rest/* url. I played a lot with it but couldn't figure it out. Changing
SetEnvIfNoCase
to
SetEnvIf
also didn't help.

Note: Our server is running apache 2.2.22.

Answer

You can solve this complex problem using a combination of few Apache directives i.e. mod_dir, mod_setenv and mod_auth_basic:

SetEnvIf Request_URI ^/rest(/.*)?$ rest_uri
# Check on what subdomain we are.
SetEnvIf Host ^local None_Prod_Env

# Static
SetEnvIf AH_CLIENT_IP ^123\.123\.123\.123$ Allow_Host
# Range
SetEnvIf AH_CLIENT_IP ^192\.168\. Allow_Host

RewriteEngine On

# block if request is /rest/* and IP is not whitelisted and not localhost
RewriteCond %{ENV:rest_uri} =1
RewriteCond %{ENV:None_Prod_Env} !=1
RewriteCond %{ENV:Allow_Host} !=1
RewriteRule ^ - [F]

# ask auth for /rest/* && NOT localhost && whitelist IP
AuthType Basic
AuthName "Password Protected"
AuthUserFile /var/www/html/.htpasswd
Require valid-user

Order deny,allow
Deny from all
Allow from env=!rest_uri
Allow from env=!Allow_Host
Allow from env=None_Prod_Env
Satisfy any