Apache 2.4 — how to close entire site except one s

2020-07-25 10:25发布

问题:

We are using the new authentication and authorization framework offered by Apache-2.4 and need to close the entire site (Location /) to unauthorized access except for one subdirectory (Location /foo), where there authorizing cookie can be obtained. It would seem, that AuthMerging is the directive to use, but things do not work:

    <Location />
            AuthType                form
            AuthFormProvider        foo
            Session                 On
            SessionCookieName       ti2f
            Include                 conf/sessionpw.conf
            AuthName                TI
            <RequireAll>
                    Require         foo ipaddress
                    Require         foo expiration
            </RequireAll>
            ErrorDocument           401     /foo/
    </Location>

    <Location /foo>
            AuthMerging Or
            Require  all granted
            DirectoryIndex index.php
    </Location>

Unfortunately, access to /foo remains blocked -- 401 Unauthorized. With LogLevel cranked up I can see the following messages logged by mod_authz_core:

authorization result of Require all granted: granted
authorization result of <RequireAny>: granted
authorization result of AuthMerging Any: granted
authorization result of Require all granted: granted
authorization result of <RequireAny>: granted
authorization result of AuthMerging Any: granted
authorization result of Require foo ipaddress: denied (no authenticated user yet)
authorization result of Require foo expiration: denied (no authenticated user yet)
authorization result of <RequireAll>: denied (no authenticated user yet)
authorization result of <RequireAny>: denied (no authenticated user yet)

With AuthMerging set to "Or" for sublocation /foo, why is Apache examining the parent location's require-directives at all after "Require all granted" grants?

回答1:

Use LocationMatch instead:

<LocationMatch "!^/foo">
   # lock down everything EXCEPT /foo
</LocationMatch>


回答2:

After some debugging, I was able to figure things out. The odd thing about Apache's authorization core (and, reportedly, it was even worse in Apache-2.2) is that the rules, if any, may be applied multiple time per hit. For example, in the case above, this happened three times for the same request -- for "/foo/"

  1. For the actual "/foo/". This was processed according to the rules for Location /foo/ and granted as expected.
  2. For "/foo/index.php". This was also processed according to the rules for Location /foo/ and granted incidentally. This explains, why I saw two such grants logged for each hit.
  3. Because we use PHP FPM to process PHP-files, the request was passed through the authz rules yet again -- as "/php-fpm/foo/index.php". This time it had to go through the top-level Location /, because it never occured to us, we need to have a separate Location /php-fpm/ as well...

Whether the current Apache's behavior is buggy or merely odd is still being debated, but my solution was to describe my sublocation thus:

    <LocationMatch ^(/php-fpm)?/foo/>
            Require         all granted
            DirectoryIndex  index.php
    </LocationMatch>

AuthMerging is not even necessary in this case. Or I could also just add another Location -- for /php-fpm/. Either way, once the problem is understood, solutions are available...