Background
The main Apache config file comes with rules to block viewing of .htaccess files. I have some other <FilesMatch>
directives of my own. I know these all work, as is.
<FilesMatch "^.ht">
Require all denied
</FilesMatch>
In the .htaccess
at the root of my website I require authentication:
AuthUserFile /etc/.htpasswd
AuthName "Authorised Access Only"
AuthType Basic
Require valid-user
This works absolutely fine. If I try to view the .htaccess
, for example, I get forbidden. If I try to access any other page of the site, I am prompted to authenticate.
The Problem
However, I want to use a condition based on my Apache environment variable so that the authentication is only active on my staging environment:
<If "env('ENV_NAME') == 'stag'">
AuthUserFile /etc/.htpasswd
AuthName "Authorised Access Only"
AuthType Basic
Require valid-user
</If>
I also know this works in itself. However, as soon as I add the <If>
statement around the Auth block, all of my <FilesMatch>
statements stop working and it’s like the authentication allows all of them to bypassed.
Once I have the <If>
statement and try to view my .htaccess
in the browser, I am asked to authenticate, and then I can view the file.
What I want to achieve
I want to be able to maintain my conditional authentication based on the environment variable, but still require all the <FilesMatch>
security directives to be honoured.
2
Answers
The
<If>
container changes the order of processing.<If>
containers are merged very late, after the<FilesMatch>
container, so theRequire valid-user
essentially overrides theRequire all denied
set in Apache config. However, without the<If>
container, the.htaccess
directives are processed early and the<FilesMatch>
container is merged later, overriding theRequire valid-user
directive.However, there is no need to use
<if>
directive here for enforcing auth forstag
environment. You can use Apache 2.4Require
andRequireAny
directives to achieve this:This will enforce auth only when an env variable
ENV_NAME
is not equal tostag
due to presence ofRequireAny
block that requires any of theRequire
conditions to be true.Alternatively, you may add another condition in your
<If>
expression to make this block execute only for requests that are not starting with/.ht
like this:I tried to replace
<If>
withRequire expr "env('ENV_NAME') != 'stag'"
but the functionenv
seems to not recognize variables defined bySetEnv
. Only<If>
seems to do so but there are some expression evaluation specificities.I also tried some combinations of
<Require(All|Any|None)>
at different level to finaly make it with a simpleAuthMerging And
.So, my suggestion and answer is to add
AuthMerging And
in your .htaccessBecause I’m really not a huge fan of anubhava’s answer if you have to duplicate any higher-level logic that you even might not know in the first place in the .htaccess.
EDIT: in fact, it might be a better idea to put
AuthMerging And
directly in the<FilesMatch "^.ht">
block instead of the .htaccess itself.