Apache 2.2 Allow from env=_variable_ - apache

I have an Apache 2.2 set up with LDAP Authorization, which is working fantastically as expected, and have also made it so that I can bypass Authentication when accessing it locally.
Allow from localIP hostnameA hostnameB, etc...
If I curl from the server, I don't get any Auth Required. So all good and working as expected.
What I need now is to make one particular URL to also bypass authorisation.
I have tried all the usual solution of using SetEnvIf;
SetEnvIf Request_URI "^/calendar/export" bypassauth=true`
Allow from env=bypassauth IP_ADDRESS HOSTNAME_A HOSTNAME_B
But this is just not working!!
Local access is still unrestricted, but remotely it is not (no change there)
If I dump out my server environment variables on that URL's script, I can see my bypassauth variable is being passed.
I just cannot for the life of me figure out why the Allow from env=bypassauth part is not working, while it still obeys the additional directive parameters.
I also tried another suggestion, using the Location directive;
<Location /calendar/export>
Satisfy Any
Allow from all
AuthType None
SetEnv WTF 123
</Location>
Again, I can see my new environmental variable (WTF) appear on this URL (when I dumped the server envs in the script), so I know that the SetEnv and SetEnvIf directives are working.
Is there anything I'm missing (any Apache2.2 quirks?), as all the solutions I've seen so far just are not working. It's as if my Allow from changes are having no effect after restarting Apache. I'm starting to feel my sanity slip.
Is there also a particular order when writing the directives for Satisfy Any, Order allow, deny and the Auth* directives, which might be effecting this?

Finally managed to figure it out!! :)
Seems my url was being processed by mod_rewrite (my environmental variable being prefixed by REWRITE_ should have rung alarm bells), which according to this post https://stackoverflow.com/a/23094842/4800587, the mod_rewrite is performed AFTER our SetEnvIf and Allow directives.
Anyway, long story short; I used the rewritten/final URL and the Location section to bypass authentication using the Allow any directive. So I changed...
<Location "/calendar/export">
Allow from all
</Location>
to..
<Location "/calendar/index.php/export">
Allow from all
</Location>
which is the final URL (after rewrite), and now works.

Related

Apache LocationMatch named regular expression strange behavior

I'm trying to create dynamic apache config for lots of directories with OpenID auth, but I never got it to work, I think that there's something wrong with named regexp, but I don't know.
Here's my virtualhost config:
AliasMatch ^/backup/(.*)$ /user_server_backups/$1
<LocationMatch "^/backup/(?<sitename>[^/]+)">
Require claim "roles:%{env:MATCH_SITENAME}"
AuthType openid-connect
</LocationMatch>
Whenever I try to access I got 401
I tried also using numbered regexp but as described in docs numbered regexps are ignored.
You'll need to use at least version 2.4.2.1 of mod_auth_openidc, see: https://github.com/zmartzone/mod_auth_openidc/pull/469

Apache 2.4.x ip blacklist

I'm looking for an easy way to blacklist IP addresses in Apache 2.4.x. My web site logs ip addresses that tried illegal operations into a text file. I would like to use this text file within Apache to deny all access to all vhosts to this ip list. What would be the best way (easiest and least resource consuming way) ?
Found this but this is only for 2.2.. Not sure how this applies to 2.4..
Cheers.
edit: this is a windows x64 box running apache x64
#vastlysuperiorman called it right, csf/lfd is the best at this. Unfortunately, they only run on linux.
This free utility promises to provide the same functionality: dynamically monitor access attempts and auto-block IP addresses. You can unblock with a command, in case of false positives. Certainly worth a short.
An alternative could be to create a VM (if your platform supports virtualization) deploy a very small spec linux box, and use that as a proxy. This should be easy to implement. BTW, why not just use linux? .. :-)
(this should have been a comment on #vastlysuperiorman's post, but I don't have enough SO reps to comment on the post of others)
Edited to suggest a possible apache 2.4 based solution:
To translate ACL directives between the 2.2 and 2.4 in apache
2.2 Syntax
order Deny,Allow
include conf/IPList.conf
Allow from all
2.4 Syntax
DocumentRoot /some/local/dir
<Directory /some/local/dir/>
<RequireAll>
Require all granted
Include conf/IPList.conf
</RequireAll>
</Directory>
#this will also work
<Location />
<RequireAll>
Require all granted
Include conf/IPList.conf
</RequireAll>
</Directory>
# conf/IPLIst.com is actually in /etc/apache2/conf/IPList.conf
# (ie, paths are relative to where apache is installed.
# I guess you can also use the full path to the list.
And inside conf/IPList.conf, you will have individual lines with entries like the following
Require not ip 10.10.1.23
Require not ip 192.168.22.199
Require not ip 10.20.70.100
Using mod-rewrite and a list of IPs for banning
For a redirect-to-another-page to work, you need to keep the RewriteRule outside the base URL you are guarding.
For instance, the redirect would not work under a Directory directive on DocumentRoot or a Location directive on '/', because the ban affects the status page we want to display.
So, best to keep this outside a Directory or Location directive, or link to a status page on another unprotected web server.
#Required set of rewrite rules
RewriteEngine on
RewriteMap hosts-deny txt:/etc/apache/banned-hosts
RewriteCond ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND [OR]
RewriteCond ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND
RewriteRule ^ /why-am-i-banned.html
## inside our banned hosts file, we have:
## /etc/apache2/banned-hosts (maintain the format .. its not just a plain text file)
##
193.102.180.41 -
192.168.111.45 -
www.example.com -
www.sumwia.net -
# inside our status page, could be html as below or a plain text file with '.txt' extension
#/var/www/html/why-am-i-banned.html
#
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Why is my IP banned?</title>
</head>
<body>
<h2>Why is my IP address banned?</h2>
<p>
To manage spammers and for other security needs, our server automatically blocks
suspicious IP address. If however you reckon your IP address has been blocked
wrongfully, please contact us.
</p>
</body>
</html>
And of course, you can parse your log files and populate conf/IPList.conf or /etc/apache2/banned-hosts as appropriate ..
As a short term solution
An alternative that will allow you to use the 2.2 syntax, is to install mod_access_compat module and continue using your deprecated 2.2 style 'Deny,Allow' directives. But this is only advisable as a short-term solution since that module is just there to aid transition, and would probably go away in future versions of apache 2.4
I too have not seen a good alternative for blocking access dynamically from within Apache itself. There are "hacky" ways: you could set an environment variable to contain a list of IPs and then use the module with ${REMOTE_ADDR} and the env function, but that's a stretch. Details on the Expression Parser
However, I have used several light weight modules that are helpful in protecting your Apache server.
ConfigServer Firewall (CSF/LFD) is a great solution for linux systems. It provides a simple method for managing iptables, and can be set up to do brute force detection and blocking. Info here
EDIT:
Add the following line to /etc/csf/csf.deny to include your custom IP block list:
Include /var/www/example.deny
Alternately, update your script to append IP addresses to csf.deny either directly:
echo $badIP >> /etc/csf/csf.deny
or using the CSF command line option (preferred):
csf -d 10.20.30.40
CSF readme here
mod_security is one of my favorite Apache/nginx modules. It detects dangerous GET and POST requests and blocks access accordingly. When set up properly, it will trigger CSF to block the IP addresses that frequently violate rules. Details here

Apache 2.4 + PHP-FPM and Authorization headers

Summary:
Apache 2.4's mod_proxy does not seem to be passing the Authorization headers to PHP-FPM. Is there any way to fix this?
Long version:
I am running a server with Apache 2.4 and PHP-FPM. I am using APC for both opcode caching and user caching. As recommended by the Internet, I am using Apache 2.4's mod_proxy_fcgi to proxy the requests to FPM, like this:
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/foo/bar/$1
The setup works fine, except one thing: APC's bundled apc.php, used to monitor the status of APC does not allow me to log in (required for looking at user cache entries). When I click "User cache entries" to see the user cache, it asks me to log in, clicking on the login button displays the usual HTTP login form, but entering the correct login and password yields no success. This function is working perfectly when running with mod_php instead of mod_proxy + php-fpm.
After some googling I found that other people had the same issue and figured out that it was because Apache was not passing the Authorization HTTP headers to the external FastCgi process. Unfortunately I only found a fix for mod_fastcgi, which looked like this:
FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -pass-header Authorization
Is there an equivalent setting or some workaround which would also work with mod_proxy_fcgi?
Various Apache modules will strip the Authorization header, usually for "security reasons". They all have different obscure settings you can tweak to overrule this behaviour, but you'll need to determine exactly which module is to blame.
You can work around this issue by passing the header directly to PHP via the env:
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
See also Zend Server Windows - Authorization header is not passed to PHP script
In some scenarios, even this won't work directly and you must also change your PHP code to access $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] rather than $_SERVER['HTTP_AUTHORIZATION']. See When setting environment variables in Apache RewriteRule directives, what causes the variable name to be prefixed with "REDIRECT_"?
This took me a long time to crack, since it's not documented under mod_proxy or mod_proxy_fcgi.
Add the following directive to your apache conf or .htaccess:
CGIPassAuth on
See here for details.
Recently I haven'd problem with this arch.
In my environement, the proxy to php-fpm was configured as follow:
<IfModule proxy_module>
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/usr/local/apache2/htdocs/$1
ProxyTimeout 1800
</IfModule>
I fixed the issue set up the SetEnvIf directive as follow:
<IfModule proxy_module>
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/usr/local/apache2/htdocs/$1
ProxyTimeout 1800
</IfModule>
I didn't find any similar settings with mod_proxy_fcgi BUT it just works for me by default. It asks for user authorization (.htaccess as usual) and the php gets it, and works like with mod_php or fastcgi and pass-header. I don't know if I was helpful...
EDIT:
it only works on teszt.com/ when using the DirectoryIndex... If i pass the php file name (even if the index.php!) it just doesn't work, don't pass the auth to the php. This is a blocker for me, but I don't want to downgrade to apache 2.2 (and mod_fastgi) so I migrate to nginx (on this machine too).

conditional proxypass ajp rules using ip whitelist

I've successfully created a ProxyPass ajp rule which works fine, but now i want to restrict the access of certain urls using an ip-whitelist. In other words, when someone comes from an ip that is not on the whitelist the request should not be proxypassed (and, ideally, some sort of access denied should be issued)
i don't have control over the machine i'm proxy-passing to, so i can't put the ip-whitelist on that machine's configuration. That's why i'm trying to configure this on the same machine that has the proxypass rule.
Defining a <Location /path> with 'Allow from'-rules doesn't work, because the request is still proxypassed. I guess this simply means the proxypass rules preceed the location-rules.
I've tried to work around it by setting an environment variable depending on the remote-address (because then i could proxy non-whitelist-ips to nonexistent url - not pretty, but it would achieve the goal), but it seems the proxypass rule doesn't work with environment variables. Something as simple as this:
SetEnv custom_proxypath=/
ProxyPass %{ENV:custom_proxypath} ajp://10.50.40.21:8009/
ProxyPassReverse %{ENV:custom_proxypath} ajp://10.50.40.21:8009/
doesn't work. while
ProxyPass / ajp://10.50.40.21:8009/
ProxyPassReverse / ajp://10.50.40.21:8009/
works perfectly.
I'm out of options. Does anyone else have a suggestion how to approach this?
I learned this today.... SetEnv is applied later in the request cycle than the ProxyPass, so it isn't set in time. However, SetEnvIf is applied early enough, as are environment variables set with RewriteCond/RewriteRule. You should be able to refactor this to a SetEnvIf that is always true and that will do the trick.

Apache .htaccess - applying basic authentication conditionally based on environment or hostname

My dev setup: Mac OSX 10.7.4 / Apache 2.2.21 / PHP 5.3.10
I wish to add conditional logic to my .htaccess files depending on dev vs live environment. for example i want to have authentication on the live server but not on the dev server. i have in my httpd.conf
SetEnv DEV 1
I have confirmed that this var is set by checking the output from phpinfo(). then in my .htaccess file
<IfDefine !DEV>
AuthType Basic
AuthName "password protected"
AuthUserFile /path/to/.htpasswd
Require valid-user
</IfDefine>
...but I am still prompted for password on my local dev. it appears that the DEV variable is not available to .htaccess. I do have AllowOverride All set in my httpd.conf for my doc root. Any ideas?
I am fresh off of about 4 hours into this problem, and I believe I have the final answer and can summarize for everyone how to solve this particularly painfull problem.
I am using Windows 7 Home Premium with Apache 2.2x and Php 5.3 as my dev machine.
I too want to have a DEV environment variable, which I can use in my .htaccess files to turn off Rewriting and other directives which are not valid on my develpment environment but are critical to my production environment.
My .htaccess file looks like this;
<IfDefine !__DEV__>
AddType application/x-httpd-php53 .php
</IfDefine>
HostGator informed me that in order to have php 5.3 I needed to modify my htaccess file like this to enable it or I'd only have php 5.2. But I already have it on my dev machine so, this directive was causing my customer website to crash when I viewed it locally. Everything I'm about to explain has allowed me to keep ONE .htaccess file in my Git Repository, which works in both locations.
First, let me clear/sum up all the things I learned while scouring the internet for the way to use IfDefine and SetEnv to solve this issue;
The IfDefine directive in Apache, Only , ONLY and when I say only i mean ONLY, responds to parameters passed at the command line. Let me emphasize that a little. ONLY COMMAND LINE!
SetEnv and SetEnvIf, are two entirely different things. One (SetEnv) is for use in the conf files, setting environment variables (specific to apache) which are set at SERVER START TIME. SetEnfIf is used at REQUEST TIME and is only used to determine what to set based on REQUEST variables.
The IfDefine directive does not read variables set by SetEnv or SetEnvIf. Period. There's no argument, there's no question, there's no "but i thought..." NO. It doesn't, so get over it.
The short answer is NO, you can't just use "SetEnv DEV 1" in httpd.conf and then use IfDefine to detect it in your .htaccess file, which would seem intuitive and reasonable based on the syntax and nature of programming logic any of us are used to. Recall that we are not in fact programming anything, that these are config files and of course they don't conform to this expectation simply because it seems like they should.
The Answer
So this means that I have to figure out how to add a startup parameter to Apache, well for the Linux Guys, that answer is readily available, you just have to add the right stuff to the envvars file, but what about us poor windows junkies?
Well for windows users it gets more fun for the following reasons:
Windows does not allow you to permanently add startup parameters in the services configuration for Apache2.2 (it doesn't work, don't try it, I've done it a million times, trust me). This is true, if you go in there and try to put in your own parameters, it will only work one time and then the parameter field is empty the next time you open the dialog. I don't know why this is the case, but it seems that those parameters are intended for testing, not a permanent modification.
When Apache is installed it creates "Start", "Stop" and "Restart" shortcuts in the start menu, as well as installs the Apache Services Monitor. BUT the shortcuts in the start menu use different startup parameters than those used by apache services monitor. So if you start/stop apache using a combination of these methods you will get different results depending on what method you used. However, you can put the -D "__DEV__" in the start menu shortcut and it will work!
Steps to Solve It
To permanently and universally setup a __DEV__ environment variable which you can reference using IfDefine in .htaccess files, on a Windows Development environment which will work whether you start Apache using a service or the shortcuts in the start menu or using NET START/STOP on the command line, do the following:
Open the properties for the start menu shortcut and extract the command you find for starting Apache there. Mine was; "C:\Program Files (x86)\Apache Software Foundation\Apache2.2\bin\httpd.exe" -w -n "Apache2.2" -k start
Modify it to include the new -D __DEV__ variable, which MUST go at the start immediately following httpd.exe; "C:\Program Files (x86)\Apache Software Foundation\Apache2.2\bin\httpd.exe" -D "__DEV__" -w -n "Apache2.2" -k start
Your start menu shortcut will now start apache with your dev variable in place.
Go to a command line (as administrator)
Type: net stop apache2.2 (or whatever your service name is for apache)
Now type in (or copy-paste) the same command as is used in the start menu shortcut above into the command line but make the following change to it; "C:\Program Files (x86)\Apache Software Foundation\Apache2.2\bin\httpd.exe" -D "__DEV__" -w -n "Apache2.2" -k config
Note the change of the word start to config. What this magical command does is saves the settings you are seeing on the screen to the settings stored with the service in Windows. Hit Enter. From this point forward your variable will be passed whenever you start the service, the Apache Services Monitor starts the service, or windows starts the service.
Sorry for the novel everyone, I hope it helps some other weary soul out there to have all this info summarized and explained, I know it would have helped me! :D
Another option to my first answer is use the Allow directive.
Look at: http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#allow
Order deny,allow
Deny from all
AuthType Basic
AuthName "password protected"
AuthUserFile /path/to/.htpasswd
Require valid-user
Allow from env=DEV
Satisfy Any
This will only check if DEV exists not the value, thats how apache works. Replace (or add) "Allow" with "Allow from 127.0.0.1" to have your localhost always be in dev mode.
This states that any of the conditions are acceptable, where the conditions are: password or from 127.0.0.1. If you develop on your localhost you can use 127.0.0.1, or just replace that with any ip you develop with. This don't need to be wrapped in anything, just placed in your htaccess file. I use virtual hosts, so I would place it there.
Source (I changed it to look your your original code):
http://www.askapache.com/htaccess/apache-authentication-in-htaccess.html#allow-conditional
2 years on and I'm having similar issues. Specifically, we are auto-deploying to an AWS OpsWorks stack and have no control over the placement of a .htpasswd file (used to obscure work during development).
Our final working solution was along the lines of this (Apache 2.2.25):
# check the host against a regex, defining env=DEV if it matches
# this guy matches localhost, dev.project and 10.1.X.X
SetEnvIfNoCase Host "^(localhost|dev\.project|10\.1(\.\d+){2})$" DEV
AuthType Basic
AuthName "Restricted"
# auth file location, in our case defined by an AWS OpsWorks auto-deployment
# this only gets loaded if the regex above doesn't match, which is handy
AuthUserFile /srv/www/project/current/.htpasswd
Require valid-user
Satisfy any
Order deny,allow
Deny from all
Allow from env=DEV
This solution is flexible enough to allow multiple development environments access while auth checking any number of others. No need for ignoring or editing the htaccess before a git commit. An environment variable might seem overkill but it allows for a regular expression and could be used elsewhere as well.
See: http://httpd.apache.org/docs/2.2/howto/access.html
Solution for Debian/Ubuntu:
In /etc/apache2/envars one has to change:
## If you would like to pass arguments to the web server, add them below
## to the APACHE_ARGUMENTS environment.
#export APACHE_ARGUMENTS=''
to
## If you would like to pass arguments to the web server, add them below
## to the APACHE_ARGUMENTS environment.
export APACHE_ARGUMENTS='-D __DEV__'
Now one can use
<IfDefine !__DEV__>
...
</IfDefine>
I do love answering questions, but a quick google search gave me your answer. Check out the apache documentation:
http://httpd.apache.org/docs/2.0/mod/core.html#ifdefine
The IfDefine directive can only test a "parameter-name", and a "parameter-name" is a variable set by httpd on startup.
Also check out this site, and scroll down to the table:
http://turboflash.wordpress.com/2010/05/27/apache-environment-variables-visibility-with-setenv-setenvif-and-rewriterule-directives/
What you are asking is still possible if you just start your dev webserver like this:
$ httpd -DDEV
This will define the variable DEV. Note that you don't need to set it to anything, being defined is basically setting it to 1/true. If it doesn't exist it's like being set to false/0/null/etc...
I've solved this problem using a different approach based on AccessFileName directive.
In my MAMP environment, I've added the following to <VirtualHost> configuration:
AccessFileName .htaccess_dev
Then, I've scanned the application directory for .htaccess files and created corresponding symlinks to the .htaccess_dev version so to have identical versions for all of them and have the application to work on my development environment.
Then, I've located the only .htaccess file containing the path to the .htpasswd file and removed the symlink and created instead a modified copy of it.
I've this in .htaccess file:
## production
AuthType Basic
AuthName "Admin"
AuthUserFile /srv/users/prod/apps/appname/public/sys-admin/.htpasswd
require valid-user
And this in .htaccess_dev
## development
AuthType Basic
AuthName "Admin"
AuthUserFile /Users/fregini/Work/MAMP/appname/sys-admin/.htpasswd
require valid-user