BadHorsie
BadHorsie

Reputation: 14554

Why is Apache <If> statement causing all my FilesMatch directives to be ignored?

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.

Upvotes: 1

Views: 1691

Answers (2)

anubhava
anubhava

Reputation: 785256

The <If> container changes the order of processing. <If> containers are merged very late, after the <FilesMatch> container, so the Require valid-user essentially overrides the Require 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 the Require valid-user directive.

However, there is no need to use <if> directive here for enforcing auth for stag environment. You can use Apache 2.4 Require and RequireAny directives to achieve this:

AuthType Basic
AuthUserFile /etc/.htpasswd
AuthName "Authorised Access Only"
<RequireAny>
   Require expr "env('ENV_NAME') != 'stag'"
   Require valid-user
</RequireAny>

This will enforce auth only when an env variable ENV_NAME is not equal to stag due to presence of RequireAny block that requires any of the Require 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:

<If "%{REQUEST_URI} !~ m#^/\.ht# && env('ENV_NAME') == 'stag'">
    AuthUserFile /etc/.htpasswd
    AuthName "Authorised Access Only"
    AuthType Basic
    Require valid-user
</If>

Upvotes: 0

julp
julp

Reputation: 4010

I tried to replace <If> with Require expr "env('ENV_NAME') != 'stag'" but the function env seems to not recognize variables defined by SetEnv. 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 simple AuthMerging And.

So, my suggestion and answer is to add AuthMerging And in your .htaccess

Because 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.

Upvotes: 1

Related Questions