4

I want to tell Apache 2.4.9 to require valid-user if host is dev.example.com or test.example.com. This doesn't work:

AuthType Basic
AuthName "Speak, friend, and enter."
AuthBasicProvider file
AuthUserFile /sites/example/conf/.htpasswd
AuthGroupFile /dev/null
SetEnvIfNoCase Host ^dev\.example\.com$ env_is_protected
SetEnvIfNoCase Host ^test\.example\.com$ env_is_protected
Require valid-user
Require not env env_is_protected

It causes a server error; evidently not env is not valid contrary to the documentation.

In the following examples, the first five lines are always the same as in the first example.

This doesn't work:

SetEnvIfNoCase Host ^dev\.example\.com$ env_is_protected
SetEnvIfNoCase Host ^test\.example\.com$ env_is_protected
<RequireAny>
    Require valid-user
    <RequireNone>
        Require env env_is_protected
    </RequireNone>
</RequireAny>

It causes a server error. The documentation explains:

Because negated authorization directives are unable to return a successful result, they can not significantly influence the result of <RequireAny> directive. (At most they could cause the directive to fail in the case where they failed and all other directives returned a neutral value.) Therefore negated authorization directives are not permitted within a <RequireAny> directive.

This doesn't work:

SetEnv env_is_unprotected 1
SetEnvIfNoCase Host ^dev\.example\.com$ !env_is_unprotected
SetEnvIfNoCase Host ^test\.example\.com$ !env_is_unprotected
Require valid-user
Require env env_is_unprotected

The documentation explains about SetEnv:

The internal environment variables set by this directive are set after most early request processing directives are run, such as access control and URI-to-filename mapping. If the environment variable you're setting is meant as input into this early phase of processing such as the RewriteRule directive, you should instead set the environment variable with SetEnvIf.

This works:

SetEnvIf Host . env_is_unprotected
SetEnvIfNoCase Host ^dev\.example\.com$ !env_is_unprotected
SetEnvIfNoCase Host ^test\.example\.com$ !env_is_unprotected
Require valid-user
Require env env_is_unprotected

This looks like a hack and takes hours to figure out. Have I failed to discover the proper way of accomplishing my very simple purpose? Is there a better way?

2 Answers 2

6

This is how I do it.
(Using Cj Case's nice citation as a comment to explain details. :D )

SetEnvIfNoCase HOST ^dev\.example\.com$ env_is_protected
SetEnvIfNoCase HOST ^test\.example\.com$ env_is_protected
<RequireAny>
    <RequireAll>
        # when the Require directive is negated it can only fail or return a neutral result, 
        # and therefore may never independently authorize a request
        # (reason why we need an additional "all granted" here!)
        Require all granted
        Require not env env_is_protected
    </RequireAll>
    AuthType Basic
    AuthName "Speak, friend, and enter."
    AuthUserFile /sites/example/conf/.htpasswd
    Require valid-user
</RequireAny>
Sign up to request clarification or add additional context in comments.

Comments

0

You're only able to use the "not" directive on a RequireAll block and not as an authentication directive.

The result of the Require directive may be negated through the use of the not option. As with the other negated authorization directive , when the Require directive is negated it can only fail or return a neutral result, and therefore may never independently authorize a request.

http://httpd.apache.org/docs/2.4/mod/mod_authz_core.html#require

This would probably work:

<Directory /your/protected/directory/>
  AuthType Basic
  AuthName "Speak, friend, and enter."
  AuthBasicProvider file
  AuthUserFile /sites/example/conf/.htpasswd
  AuthGroupFile /dev/null

  SetEnvIfNoCase Host ^dev\.example\.com$ env_is_protected
  SetEnvIfNoCase Host ^test\.example\.com$ env_is_protected

  <RequireAll>
    Require valid-user
    Require not env env_is_protected
  </RequireAll>
</Directory>

3 Comments

not env is invalid, the question explicitly says that.
Should be valid inside a RequireAll block as far as I can tell.
I suspect that this is the right answer, but I haven't accepted it yet because I haven't gotten around to testing it yet. It's on my to-do list, sorry to be so slow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.