skip to Main Content

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


  1. 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>
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search