Trigger apache authentication depending on URL parameter - apache

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>

Related

Apache permissions based on querystring

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>

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>

htaccess exclude one url from Basic Auth

I need to exclude one Url (or even better one prefix) from normal htaccess Basic Auth protection. Something like /callbacks/myBank or /callbacks/.*
Do you have any hints how to do it?
What I'm not looking for is how to exclude a file.
This has to be url (as this is solution based on PHP framework, and all urls are redirected with mod_rewrite to index.php). So there is no file under this URL. Nothing.
Some of those urls are just callbacks from other services (No IP is not known so I cannot exclude based on IP) and they cannot prompt for User / Password.
Current definition is as simple as:
AuthName "Please login."
AuthGroupFile /dev/null
AuthType Basic
AuthUserFile /xxx/.htpasswd
require valid-user
Using SetEnvIf, you can create a variable when the request starts with some path, then use the Satisfy Any directive to avoid having to login.
# set an environtment variable "noauth" if the request starts with "/callbacks/"
SetEnvIf Request_URI ^/callbacks/ noauth=1
# the auth block
AuthName "Please login."
AuthGroupFile /dev/null
AuthType Basic
AuthUserFile /xxx/.htpasswd
# Here is where we allow/deny
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=noauth
The allow/deny chunk of directives says that deny access for EVERYONE, except when there is a valid-user (successful BASIC auth login) or if the noauth variable is set.
If you are using Apache 2.4, SetEnvIf and mod_rewrite workarounds are no longer necessary since the Require directive is able to interpret expressions directly:
AuthType Basic
AuthName "Please login."
AuthUserFile "/xxx/.htpasswd"
Require expr %{REQUEST_URI} =~ m#^/callbacks/.*#
Require valid-user
Apache 2.4 treats Require directives that are not grouped by <RequireAll> as if they were in a <RequireAny>, which behaves as an "or" statement. Here's a more complicated example that demonstrates matching both the request URI and the query string together, and falling back on requiring a valid user:
AuthType Basic
AuthName "Please login."
AuthUserFile "/xxx/.htpasswd"
<RequireAny>
<RequireAll>
# I'm using the alternate matching form here so I don't have
# to escape the /'s in the URL.
Require expr %{REQUEST_URI} =~ m#^/callbacks/.*#
# You can also match on the query string, which is more
# convenient than SetEnvIf.
#Require expr %{QUERY_STRING} = 'secret_var=42'
</RequireAll>
Require valid-user
</RequireAny>
This example would allow access to /callbacks/foo?secret_var=42 but require a username and password for /callbacks/foo.
Remember that unless you use <RequireAll>, Apache will attempt to match each Require in order so think about which conditions you want to allow first.
The reference for the Require directive is here: https://httpd.apache.org/docs/2.4/mod/mod_authz_core.html#require
And the expression reference is here: https://httpd.apache.org/docs/2.4/expr.html
This solution works pretty well, you just need to define whitelist you want to pass through.
SetEnvIfNoCase Request_URI "^/status\.php" noauth
AuthType Basic
AuthName "Identify yourself"
AuthUserFile /path/to/.htpasswd
Require valid-user
Order Deny,Allow
Deny from all
Allow from env=noauth
Satisfy any
I tried the other solutions but this is what worked for me. Hopefully it will be of help to others.
# Auth stuff
AuthName "Authorized personnel only."
AuthType Basic
AuthUserFile /path/to/your/htpasswd/file
SetEnvIf Request_URI "^/index.php/api/*" allow
Order allow,deny
Require valid-user
Allow from env=allow
Deny from env=!allow
Satisfy any
This will allow the api url and any url string after /index.php/api/ to open without having to login and anything else will be prompted to login.
Example:
mywebsite.com/index.php/api will open without being prompted to login
mywebsite.com/index.php/api/soap/?wsdl=1 will open without being prompted to login
mywebsite.com will be prompted to login first
<location />
SetEnvIf Request_URI "/callback/.*" 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>
why don't you just use basic auth the way it was intended?
user:password#domain.com/callbacks/etc
Another approach works like this, if the area you are protecting has a monolithic PHP script controlling everything, like Wordpress. Set up Authentication with in a different directory. Put an index.php there that sets a cookie on path '/'. Then in Wordpress (for example), check the cookie, but bypass the check if $_SERVER['REQUEST_URI'] is the excluded URL.
On my shared hosting platform, RewriteRule could not set an environment variable that worked with "Satisfy any".
With any approach, watch out that the page you are protecting does not include images, stylesheets, etc., that trigger an authentication request when the page itself does not.
Add below code to your root htaccess file and don't forget to change your admin url, .htpasswd file page.
<Files "admin.php">
AuthName "Cron auth"
AuthUserFile E:\wamp\www\mg\.htpasswd
AuthType basic
Require valid-user
</Files>
Create .htpasswd file in your root folder and add below username and password (set default username:admin and password: admin123)
admin:$apr1$8.nTvE4f$UirPOK.PQqqfghwANLY47.
Please let me know if you still facing any issue.
None of this worked for me with Apache 2.4, because my PHP/Laravel htaccess did a rewrite and changed Request_URI to be always /index.php.
I used Require expr %{THE_REQUEST} to get the first line of the HTTP request (THE_REQUEST) which remains unchanged.
e.g., "GET /callbacks HTTP/1.1"
This worked for me:
<Location />
AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/.htpasswd
Require expr %{THE_REQUEST} =~ m#^GET /callbacks#
Require valid-user
</Location>
Note you need to change GET to POST if you need to or allow both:
Require expr %{THE_REQUEST} =~ m#^GET /callbacks#
Require expr %{THE_REQUEST} =~ m#^POST /callbacks#
Require valid-user
More about Require expr

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.

apache: basic authentication before rewrite

I have an Apache in frontend that should redirect a request via a RewriteRule.
I have to put a basic authentication before the request is redirected, so I put this in the config file:
<VirtualHost *:443>
ServerAdmin xxxxxx
DocumentRoot /var/www/html/
ServerName xxxxxxx
RewriteEngine on
ErrorLog logs/error.log
CustomLog logs/access_log common
<Directory /var/www/html/>
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
</VirtualHost>
But it doesn't work.
Any suggestions?
UPDATE: I would expect that all requests after authentication would be redirected with the rule RewriteRule ^/(.*) xxxxxx:xxx/$1 [P,L] but this doesn't happen. Apache search the page under /var/www/html
In general, Apache does the rewrite phase before the authorization phase, which is why your code performs the rewrite without ever asking for user to authenticate.
You can get around this with the LA-U:REMOTE_USER variable. Preface your RewriteRule with a condition which looks ahead ("LA") to the authorization phase:
RewriteCond %{LA-U:REMOTE_USER} !^$
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [L]
See notes about this in http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritecond
As other posters point out, it's also better to take the RewriteRule directives out of the block so they are more reliable.
I solved putting the rewrite condition and rewrite rule outside the Locatio directive:
<Location />
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
</Location>
RewriteCond %{LA-U:REMOTE_USER} !^$
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [P,L]
many thanks to h0tw1r3 for the suggestion
*Keep in mind that Location directives operate on URLs, and not directories. That means that if someone creates an alias to the document root, they'll completely bypass these authentication rules. (See http://httpd.apache.org/docs/2.0/mod/core.html#location for more.)
Update: Implicit directory rule ensures validation is always required before the rewrite is done. Found that different combinations of apache modules changed the behavior, thus the accepted answer may not always work.
<Location />
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
</Location>
<Directory /documentroot>
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule (.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
<Directory /var/www/html/>
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
RewriteRule ^/(.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
There are 2 issues here that will prevent your RewriteRule from doing anything:
You need to enable the rewrite engine inside the <Directory> container (a directory context). You've (incorrectly) enabled the rewrite engine in the outer <VirtualHost> container (a virtualhost context) - in which you don't have any mod_rewrite directives. The <VirtualHost> and <Directory> containers work in different contexts. If you don't enable the rewrite engine inside the <Directory> container then the directives will simply be ignored.
RewriteEngine On
When used in a directory context (<Directory> and .htaccess) the URL-path matched by the RewriteRule pattern does not start with a slash, since the directory-prefix (that ends in a slash) has been removed. So, you need to remove the slash prefix from the regex, otherwise, it will simply never match in a directory context:
RewriteRule (.*) http://xxxxxx:xxx/$1 [P,L]
(The ^ prefix on the pattern then becomes superfluous.)
Summary
Actioning the above points, this becomes:
<Directory /var/www/html/>
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /etc/httpd/conf/tag.pwd
Require valid-user
RewriteEngine On
RewriteRule (.*) http://xxxxxx:xxx/$1 [P,L]
</Directory>
Alternatively, you move the RewriteRule directive outside of the <Directory> container and use this directly inside the <VirtualHost> container in which you've already enabled the rewrite engine.
However, in this context, the mod_rewrite directives will execute before the authorisation directives inside the <Directory> container, so you will need the additional condition that checks the REMOTE_USER via a look-ahead (ie. LA-U:REMOTE_USER), as mentioned in the other answers.