Apache permissions based on querystring - apache

I have an apache server where authentication is required, but there are some calls that need to be allowed for all.
On off these calls is based on a query string for example:
/foo/api.php?Token=123&Task=DoStuff&Result=json
I taught that with a LocationMatch that this would have workd so i worked out this configuration:
<LocationMatch ^/foo/api.php\?.*(Task=DoStuff).*>
Order Allow,Deny
Allow from All
</LocationMatch>
But this doesn't let me pass the authentication (meaning i get a 401).
If I just filter ^/foo/api.php I get passed the authentication, but this isn't strict enough.
Anyone has any idea how to configure this to check the Task parameter in the querystring?
For authentication we are using kerberos, this is forced on the whole site
This is our conf for kerb
LoadModule auth_kerb_module modules/mod_auth_kerb.so
<Directory /var/www/html>
Options FollowSymLinks
AllowOverride All
AuthType Kerberos
Require valid-user
AuthName "Kerberos Login"
KrbMethodNegotiate on
KrbMethodK5Passwd on
KrbAuthRealms FOO.LOCAL
KrbServiceName HTTP/server.foo.local#foo.LOCAL
Krb5KeyTab /etc/httpd/conf/http.keytab
Satisfy Any
Order deny,allow
Deny from all
Allow from 192.168.72.90
Allow from 192.168.72.91
Allow from 192.168.72.94
Allow from 192.168.72.95
Allow from 127.0.0.1
</Directory>

As you can read here:
The <Location>, <LocationMatch>, <Directory> and <DirectoryMatch>
Apache directives allow us to apply authentication/authorization to
specific patterns of resources with a high degree of specificity, but
do not give us that control down to the query-string level.
Therefore, you have to use mod_rewrite to achieve your goal.
For example:
RewriteEngine on
RewriteCond %{QUERY_STRING} Task=DoStuff
RewriteRule ^/foo/api.php - [E=no_auth_required:1]
<LocationMatch ^/foo/api.php>
Order allow,deny
Allow from env=no_auth_required
AuthType Basic
AuthName "Login Required"
AuthUserFile /var/www/foo/.htpasswd
require valid-user
Satisfy Any
</LocationMatch>
UPDATE
You've stated that:
If I just filter ^/foo/api.php I get passed the authentication, but
this isn't strict enough.
Then, try adding the following rows to your configuration:
RewriteEngine on
RewriteCond %{QUERY_STRING} Task=DoStuff
RewriteRule ^/foo/api.php - [E=no_auth_required:1]
<LocationMatch ^/foo/api.php>
Order allow,deny
Allow from env=no_auth_required
</LocationMatch>

In Apache 2.4 there's an easier way to do this without the rewrite.
You can use LocationMatch to match upto the QUERY_STRING, and then use an If block to match the contents of QUERY_STRING. i.e., something like this:
<LocationMatch "^/foo/api.php">
<If "%{QUERY_STRING} =~ /.*Task=DoStuff.*/" >
Require all granted
</If>
</LocationMatch>

we can't use <If %{QUERY_STRING} /a=b/>, is not supported by < apache 2.4
RewriteEngine On
RewriteCond %{QUERY_STRING} test=ok
RewriteRule ^/ - [E=checkParamTest:1]
<LocationMatch "^/">
Order allow,deny
Allow from env=checkParamTest
Satisfy any
</LocationMatch>
<Location />
AuthType openid-connect
Require valid-user
...
</Location>

Related

Trigger apache authentication depending on URL parameter

I need to trigger the apache authentications depending only on a URL parameter. For instance, The following URL http://mySillyApplication.com/items/browse?collection=9&sort_field=Title&num_items=10&... I need to trigger the authentication only if collection=9 . I've tried many things but I couldn't find how to do it. I think the key is to find a RewriteRule that could activate the LocationMatch .... just a guess:
RewriteEngine On
RewriteCond %{QUERY_STRING} (.*(?:^|&))collection=9((?:&|$).*) [NC]
RewriteRule (.*) - [R=401]
<LocationMatch "....don't know...">
AuthType Basic
AuthName "Login Required"
AuthUserFile /var/www/.../.htpwd
Require valid-user
Order allow,deny
Allow from all
Satisfy any
</LocationMatch>
Thanks.
You could use <If> Directive if Apache is 2.4.26 and later http://httpd.apache.org/docs/2.4/mod/core.html#if
So, try the following code :
<If "%{QUERY_STRING} =~ /(collection=9&)/">
AuthType Basic
AuthName "Login Required"
AuthUserFile /path/to/.htpasswd
Require valid-user
Order allow,deny
Deny from all
Satisfy any
</If>

How to make Basic Auth exclude a rewritten URL

I have a Basic Authentication setup on a development server. It is setup inside my httpd.conf file for the VirtualHost of the website. I've had to set up it to exclude certain directories, which has caused no problems and all works fine.
The issue has been with excluding a URL that has been through my mod_rewrite rules in the .htaccess file. My set up is that I have all URLs going through my index.php file and from there the relevant code is found and ran. I tried adding the URL that I wanted to exclude (/businesses/upload_logo) like I did the others but it still requires authentication. This is what I currently have:
...
<Location />
SetEnvIf Request_URI "/businesses/upload_logo" noauth=1
SetEnvIf Request_URI "/api/.*" noauth=1
AuthType Basic
AuthName "Private"
AuthUserFile ****
Require valid-user
Order deny,allow
Satisfy any
Deny from all
Allow from env=noauth
</Location>
....
I have found questions that are similar to mine here & here but the answers only give me what I'm already trying.
I have thought of possible other solutions as well, but these will be last resort things. I want to see if it's possible the way I'm currently doing it:
Set up the basic auth inside my php code instead
Too much hassle at the moment
Put the authentication in my .htaccess file instead
Didn't want to do this just yet as I only want the authentication to happen on one of 3 servers. I'm aware that I could use some more SetEnvIf HOST ... but I'm looking to see if it can be fixed this way or not first.
The mod_rewrite rule:
...
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php [L,QSA]
Try adding
Allow from env=REDIRECT_noauth
For me something like this works like a charm:
<location />
SetEnvIf Request_URI "/businesses/upload_logo" REDIRECT_noauth=1
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/passwords/passwords
Order Deny,Allow
Satisfy any
Deny from all
Allow from env=REDIRECT_noauth
Require user yournickname
</location>
based on what you have given it should work, unless there is a conflicting directive somewhere else in your configuration.
i have made a similar working setup , just i have used filesystem path instead of URI
i am adding it here, hoping you may find it useful
<VirtualHost *:8989 >
<IfModule mod_auth_basic.c>
<Directory /var/www/html/vella-8989>
# the auth block
AuthType Basic
AuthName "Please login."
AuthUserFile /var/www/html/vella-8989/.htpasswd
require valid-user
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=noauth
</Directory>
</IfModule>
# set an environtment variable "noauth" if the request has "/callbacks/"
SetEnvIf Request_URI "/callbacks/" noauth=1
ServerName vella.com
ServerSignature off
</VirtualHost>

getting "authentication required" when requesting / instead of /index.php

On my server I have the following .htaccess file:
DirectoryIndex index.php
AuthType Basic
AuthName "Password Required"
AuthUserFile /var/www/webinterface/.htpasswd
Options +FollowSymLinks
Require valid-user
<Files index.php>
Satisfy any
Allow from *
</Files>
If I request the URL "IP-ADDRESS/index.php", everything works fine, I get the index.php displayed without an authentication prompt. However as soon as I request "IP-ADDRESS/" the browser asks me for my credentials.
Why is this the case? What am I missing?
Try replacing the block to use mod_setenvif to check the request URI instead of using <Files>. The mod_auth* modules has precedence over mod_dir so the mapping from / to /index.php doesn't happen until after the auth takes place. Mod_setenvif will occur before the auth. Try:
SetEnvIf Request_URI "^/$" allow=yes
SetEnvIf Request_URI "^/index.php$" allow=yes
AuthType Basic
AuthName "Password Required"
AuthUserFile /var/www/webinterface/.htpasswd
Options +FollowSymLinks
Order Deny,Allow
Satisfy any
Deny from All
Require valid-user
Allow from env=allow
If the requested URI is exactly / or /index.php, the variable allow gets set. The stuff after the Auth lines say to deny everything except a valid user or if the variable allow has been set.

.htaccess basic auth by virtual host?

I was wondering if it was possible to setup a conditional http basic auth requirement based on the virtual host URL in an .htaccess file.
For example what I want to do is have mysite.com and test.mysite.com run off the same code base in the same directory but password protect test.mysite.com. It would be setup this way so that I wouldn't need to branch my code since my app code can see which vhost/url it's being served from and pick the database to serve content from.
You can sort of kludge this by using mod_setenvif along with the mod_auth modules. Use the SetEnvIfNoCase directive to set which host is password protected. You'll need a couple of extra directives to satisfy access:
# Check for the hostname here
SetEnvIfNoCase HOST ^test\.mysite\.com\.?(:80)?$ PROTECTED_HOST
Then inside the Directory block (or just out in the open) you have your auth stuff setup, something like this:
AuthUserFile /var/www/test.mysite.com/htpasswd
AuthType Basic
AuthName "Password Protected"
Now for the require/satisfy stuff:
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=!PROTECTED_HOST
This will make it so any host that doesn't match ^test\.mysite\.com\.?(:80)?$ will have access without need for auth (Allow from env=!PROTECTED_HOST) but otherwise, we need a valid user (Require valid-user). The Satisfy any ensures that we just need one of the 2, either the Allow or Require.
I had problems implementing Jon's solution:
Although I am quite familiar with Apache conf and regular expressions, the authentication always fired. From a quick analyzes it looked like the Allow from env=!PROTECTED_HOST line did not kick in.
But I found another solution that actually looks safer to me:
I created two virtual hosts for the two domains pointing to the same document root (which is fully allowed by the way). In one of the vhosts I added the directives for basic auth (directly into the vhost directive block).
Works like a charm. And I have a better feeling that this is really safe - no risk to overlook any details in the regex pattern that would open up the gates for intruders.
<VirtualHost *:80>
ServerName www.mysite.com
DocumentRoot "/path/to/common/doc/root"
<Directory "/path/to/common/doc/root">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName protected.mysite.com
DocumentRoot "/path/to/common/doc/root"
<Directory "/path/to/common/doc/root">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
AuthUserFile /path/to/htpasswd
AuthName "Password please"
AuthType Basic
Require valid-user
</Directory>
</VirtualHost>
Here's a solution similar to what Jon Lin proposed, but using RewriteCond to check the host name:
RewriteEngine On
RewriteCond %{HTTP_HOST} =protected.hostname.com
RewriteRule ^.*$ - [E=DENY:1]
AuthUserFile /path/to/htpasswd
AuthName "Password please"
AuthType Basic
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=!DENY

.htaccess: how to restrict access to a single file by IP?

I've look all over, but keeps running into same info that talks about directory level IP restriction, which usually looks something like this:
Order Deny,Allow
Deny from all
Allow from 123.123.123.123
Is it possible to have same type of access restriction tied to a page/document?
This will allow either someone from IP 127.0.0.1 or logged as a valid user. Stick it either in your config or .htaccess file.
<Files learn.php>
Satisfy any
Order deny,allow
Deny from all
Allow from 127.0.0.1
AuthType Basic
AuthName "private"
AuthUserFile /var/www/phpexperts.pro/.htpasswd
AuthGroupFile /dev/null
Require valid-user
</Files>
IP Alone:
<Files learn.php>
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Files>
That definitely answers your question.
I think the directive needs to be:
Order deny,allow
for the answer above to work (at least for the IP Alone solution).
Mod-rewrite based solution :
RewriteEngine on
RewriteCond %{REMOTE_ADDR} !^Y\.O\.U\.R\.IP$
RewriteRule ^file\.php$ - [F,L]
The rewriteRule above will deny all requests to file.php if client ip does not match the ip address in the RewriteCond's pattern
For a more up to date Apache 2.4 example:
<Files file.html>
Require ip 123.123.123.123
</Files>
Here are the more in depth docs for additional options and examples: https://httpd.apache.org/docs/2.4/howto/access.html and the docs for the <Files> directive: https://httpd.apache.org/docs/2.4/mod/core.html#files
Note that <Files> can be nested inside <Directory> sections to restrict the portion of the filesystem they apply to.