httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chris Darroch <>
Subject Re: AuthzMergeRules blocks everything in default configuration
Date Wed, 29 Oct 2008 22:17:57 GMT
Dan Poirier wrote:

> I like the idea of replacing ON with AND and OR.  It would not
> only provide more control, but make it explicit what kind of merging
> was going to happen.
> I have mixed thoughts about changing the default to OFF.  
> Cons: That would mean every container directive would have to specify
> some sort of access control (or at least AuthzMergeRules AND) or it'd
> be wide open, right?

   I don't think so; at least, that's not what I was intending.
Rather, something much like 2.2's behaviour: containers that don't
specify any authz are simply protected by the "nearest" container
merged ahead of them that does specify authz.

   I'm hoping to put this thread to bed shortly with the patches
available here:

   My intent is to finish up the necessary documentation changes
and get everything committed to trunk in the next few days.  (Fingers

   In the meantime, an overview follows.  Many, many thanks are
due to Brad Nicholes, whose massive refactoring of the authn/z
system makes all of this work possible.

1) <Limit> and <LimitExcept> are made nestable, with an error in
   the case where all methods are configured out.  There are also some
   tuneups related to <Limit>/<LimitExcept> being intended to contain
   authz configurations only and to not be functional outside <Directory>/

2) A setting of "AuthType None" is allowed, which sets ap_auth_type() to
   NULL and thus provides a way to turn off authentication for a
   sub-directory.  This corresponds to several convenient ways in 2.4 to
   turn off authorization, including "Require all granted" (and, at a
   deeper level, the new "SatisfySections Off").

3) The mod_authz_core.c module is rewritten to attempt to deal with the
   issues discussed on this thread and the previous one, as well as
   those described at the end of this email.  The authz_provider_list
   two-pronged linked lists are replaced by a tree structure that mirrors
   what is configured via <SatisfyAll> and <SatisfyAny>.

   A pair of negative authz containers are introduced, <SatisfyNotAll>
   and <SatisfyNotAny>, which negate their operands in the same
   manner as Reject.  Thus we have the following table:

      Require			A
      Reject			!A
      <SatisfyAll>		(A && B && ...)
      <SatisfyAny>              (A || B || ...)
      <SatisfyNotAll>           !(A && B && ...)
      <SatisfyNotAny>           !(A || B || ...)

   The <SatisfyAny> directive is renamed from <SatisfyOne> so as not
   to imply XOR-like functionality (requiring exactly one successful

   A number of configuration-time checks are implemented to warn
   administrators regarding redundant or non-functional authz
   configurations. In particular, since the negative authz directives
   can not contribute meaningfully to OR-like blocks, as they
   can only supply neutral (AUTHZ_NEUTRAL) or false (AUTHZ_DENIED)
   values, they are simply not allowed in these containers.  (The
   code should support them, though, if this check is ever removed.)
   Similarly, AND-like blocks without only negative authz directives
   also produce a configuration-time error.

   The MergeAuthzRules directive is renamed SatisfySections and
   take three possible values, Off, All, and And.  The default is Off,
   meaning that as directory configuration sections are merged,
   new authz configurations replace previously merged ones.  However,
   a directory section may specify "SatisfySections All" to force
   its predecessor's authz to be successful as well as its own.
   The "SatisfySections Any" option permits either the predecessor
   or current section's authz to grant the user access.  Note that
   the setting of SatisfySections continues to be local only to
   the directory section it appears in; it is not inherited to
   subsequent sections as they are merged.

   The default setting of SatisfySections is Off, corresponding to
   traditional pre-2.4 authz logic.  Within a directory section,
   the default logic corresponds to an AND-like block (i.e., <SatisfyAll>),
   which differs from the pre-2.4 logic whereby the first Require
   statement to succeed authorized the request.

   Legacy 2.2 configurations should, I hope, work with few or no
   changes as a result of these revisions.  Few administrators, I hope,
   have configurations with multiple Require directives in a section; e.g.:

      <Directory /foo>
          Require group shirt
          Require group shoes

   If they do, these would need to be revised to either place all the
   items in a single Require directive (e.g., Require group shirt shoes)
   or to use a <SatisfyAny> section.  I feel this makes the overall
   intent of the configuration directives clearer, since it is not
   apparent that the example above grants access to members of either
   group, not just those who are members of both.

   It also means that the following 2.4-style configuration makes
   intuitive sense, because the negative Reject directive only has
   meaning in an AND-like context:

      <Directory /foo>
          Require group shirt
          Reject user noshoes

   However, if this proves to be a point of considerable difficulty
   for people upgrading to 2.4, it is straightforward to make the
   default logic of a section be OR-like by editing the
   create_default_section() function in mod_authz_core.c.

   The legacy Satisfy directive's logic is already largely handled in
   request.c in 2.4, so mod_access_compat.c could be simplified slightly.

   The <Limit> and <LimitExcept> directives are handled by
   tracking the currently applicable set of methods for all Require/Reject
   directives within a section and its sub-sections.  When the
   request's method does not apply to an authz section, we can then
   immediately return either AUTHZ_GRANTED or AUTHZ_NEUTRAL, depending
   on whether we are in an AND-like or OR-like context, respectively.

4) The mod_authn_default.c and mod_authz_default.c modules are removed,
   shifting the small amount of remaining functionality they provide into
   mod_authn_core.c and mod_authz_core.c.  The existence of both "core"
   and "default" authn/z modules appeared likely to be a source of some
   confusion (especially since they can all be made optional at runtime).

   The mod_authz_default.c module, in particular, was also almost
   entirely obviated by the mod_authz_core.c rewrite, and removing
   it clarified the code paths in many cases where administrators
   likely failed to create a sensible configuration, e.g., by engaging
   authentication with an AuthType directive but configuring not
   authorization to match.

   That's about it for now; comments welcome.  Just for historical
purposes, some things I ran into with the authz_provider_list
two-pronged linked lists with prompted the rewrite:

   First, there were some configurations which could send the
check_provider_list() function into an infinite loop.  For example, with
the following configuration, if one authenticated as user "foo" (i.e.,
a user not in any of the Require directives), the function recursed until
it reached the end of the list(s), received AUTHZ_DENIED from the last
invocation, and then the second-last invocation would loop on the goto
one_next statement.  Since nothing had changed, it just repeated the final
invocation over and over.

AuthzMergeRules Off
  Require user who
    Require user tar
  Require user dis

   Second, the two-pronged authz_provider_list lists seemed to lead to
incorrect authorization behaviour when directives were moved around in
the configuration file in innocuous ways.  For example, with the following
configuration, logging in as user "foo" would succeed:

Require valid-user
 Require user who
 Require user foo

   Moving the first statement to the end of the configuration caused
the user to be rejected, though:

 Require user who
 Require user foo
Require valid-user

   The difference was that in the first case, the linked lists looked
roughly like this:

"Require valid-user"
  req_state =  AUTHZ_REQSTATE_ALL
  all_next  -> "Require user who"
                 req_state =  AUTHZ_REQSTATE_ONE
                 one_next  -> "Require user foo"
                                req_state = AUTHZ_REQSTATE_ONE

while in the second case, they looked like this:

"Require user who"
  req_state =  AUTHZ_REQSTATE_ONE
  all_next  -> "Require valid-user"
                 req_state =  AUTHZ_REQSTATE_ALL
                 all_next  -> "Require user foo"
                                req_state = AUTHZ_REQSTATE_ONE

   When check_provider_list() received AUTHZ_DENIED after testing
user "foo" against "Require user who", it found a NULL one_next
pointer and just returned AUTHZ_DENIED, rather than proceeding
any further.


GPG Key ID: 366A375B
GPG Key Fingerprint: 485E 5041 17E1 E2BB C263  E4DE C8E3 FA36 366A 375B

View raw message