httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bnicho...@apache.org
Subject svn commit: r427780 - in /httpd/httpd/trunk: docs/manual/mod/mod_authz_core.xml modules/aaa/mod_auth.h modules/aaa/mod_authz_core.c
Date Tue, 01 Aug 2006 22:54:39 GMT
Author: bnicholes
Date: Tue Aug  1 15:54:38 2006
New Revision: 427780

URL: http://svn.apache.org/viewvc?rev=427780&view=rev
Log:
Converted the reject directive to be definitive and enabled directory_merge to merge all of
the authorization rules and logic.

Modified:
    httpd/httpd/trunk/docs/manual/mod/mod_authz_core.xml
    httpd/httpd/trunk/modules/aaa/mod_auth.h
    httpd/httpd/trunk/modules/aaa/mod_authz_core.c

Modified: httpd/httpd/trunk/docs/manual/mod/mod_authz_core.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_authz_core.xml?rev=427780&r1=427779&r2=427780&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_authz_core.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_authz_core.xml Tue Aug  1 15:54:38 2006
@@ -112,8 +112,8 @@
 
 <directivesynopsis>
 <name>Reject</name>
-<description>Rejects which authenticated users can access
-a resource</description>
+<description>Rejects authenticated users or host based 
+requests from accessing a resource</description>
 <syntax>Reject <var>entity-name</var> [<var>entity-name</var>]
...</syntax>
 <contextlist><context>directory</context><context>.htaccess</context>
 </contextlist>
@@ -122,10 +122,12 @@
 <usage>
     <p>This directive is similar to the 
     <directive module="mod_authz_core">Require</directive> directive however
-    it rejects which authenticated users can access a resource.  The 
+    it rejects which authenticated users or host based requests from accessing a resource.
 The 
     restrictions are processed by authorization modules.  See the 
     <directive module="mod_authz_core">Require</directive> directive for details

-    about usage.</p>
+    about usage.  If found as part of the authorization rules, the reject directive
+    is definitive.  In other words, if the reject statements is satisfied, the entire request
+    is automatically rejected no matter what other require rules may exist.</p>
 </usage>
 
 <seealso><a href="../howto/auth.html">Authentication, Authorization,
@@ -220,6 +222,31 @@
 
 <seealso><a href="../howto/auth.html">Authentication, Authorization,
     and Access Control</a></seealso> 
+
+</directivesynopsis>
+
+<directivesynopsis type="section">
+<name>AuthzMergeRules</name>
+<description>Set to 'on' to allow the parent's &lt;Directory&gt; or &lt;Location&gt;

+authz rules to be merged into the current &lt;Directory&gt; or &lt;Location&gt;.
 
+Set to 'off' to disable merging. If set to 'off', only the authz rules defined in 
+the current &lt;Directory&gt; or &lt;Location&gt; block will apply.</description>
+<syntax>AuthMergeRules on | off</syntax>
+<default>AuthMergeRules on</default>
+<contextlist><context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>AuthConfig</override>
+
+<usage>
+    <p>By default all of the authorization rules within a &lt;Directory&gt;
+    &lt;Location&gt; hierarchy are merged together to form a single 
+    logical authorization operation.  If AuthzMergeRules is set to 'on', then
+    only the authorization rules that are contained with the current 
+    &lt;Directory&gt; or &lt;Location&gt; block are considered. This
+    allows the configuration to determine exactly how authorization will
+    be determine without having to take into consideration the 
+    authorization rules that may exist above it.</p>
+</usage>
 
 </directivesynopsis>
 

Modified: httpd/httpd/trunk/modules/aaa/mod_auth.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_auth.h?rev=427780&r1=427779&r2=427780&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_auth.h (original)
+++ httpd/httpd/trunk/modules/aaa/mod_auth.h Tue Aug  1 15:54:38 2006
@@ -69,7 +69,9 @@
 typedef enum {
     AUTHZ_DENIED,
     AUTHZ_GRANTED,
-    AUTHZ_GENERAL_ERROR
+    AUTHZ_GENERAL_ERROR,
+    AUTHZ_NEUTRAL,
+    AUTHZ_REJECTED
 } authz_status;
 
 typedef enum {

Modified: httpd/httpd/trunk/modules/aaa/mod_authz_core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authz_core.c?rev=427780&r1=427779&r2=427780&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_authz_core.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_authz_core.c Tue Aug  1 15:54:38 2006
@@ -57,7 +57,7 @@
    core request handling to allow the hooks to be called
    in all cases.  Is this function even necessary
    anymore?
- - Determine of merge_authz_dir_config is even 
+X- Determine of merge_authz_dir_config is even 
    necessary and remove if not
 X- Split the authz type from the arguments when the
    authz provider is registered and store the type
@@ -99,8 +99,10 @@
 
 typedef struct {
     authz_provider_list *providers;
+    authz_provider_list *rejects;
     authz_request_state req_state;
     int req_state_level;
+    int merge_rules;
 } authz_core_dir_conf;
 
 typedef struct authz_core_srv_conf {
@@ -109,6 +111,9 @@
 
 
 module AP_MODULE_DECLARE_DATA authz_core_module;
+static const char *merge_authz_provider(authz_core_dir_conf *conf, authz_provider_list *newp);
+static void walk_merge_provider_list(apr_pool_t *a, authz_core_dir_conf *conf, authz_provider_list
*providers);
+static const char *merge_authz_reject(authz_core_dir_conf *conf, authz_provider_list *newp);
 
 static void *create_authz_core_dir_config(apr_pool_t *p, char *dummy)
 {
@@ -117,10 +122,10 @@
 
     conf->req_state = AUTHZ_REQSTATE_ONE;
     conf->req_state_level = 0;
+    conf->merge_rules = 1;
     return (void *)conf;
 }
 
-#if 0
 static void *merge_authz_core_dir_config(apr_pool_t *a, void *basev, void *newv)
 {
     authz_core_dir_conf *base = (authz_core_dir_conf *)basev;
@@ -131,13 +136,33 @@
     * (or creating copies for merging) where new-> values exist.
     */
     conf = (authz_core_dir_conf *)apr_palloc(a, sizeof(authz_core_dir_conf));
-    memcpy(conf, new, sizeof(authz_core_dir_conf));
+    memcpy(conf, base, sizeof(authz_core_dir_conf));
 
-    conf->some_authz = base->some_authz == -1 ? 0:base->some_authz == 0 ? 0:new->some_authz;
+    /* Wipe out the providers and rejects lists so that 
+        they can be recreated by the merge process. */
+    conf->providers = NULL;
+    conf->rejects = NULL;
+
+    /* Only merge the base providers in if the merge_rules 
+        directive has been set. */
+    if (base->providers && new->merge_rules) {
+        walk_merge_provider_list (a, conf, base->providers);
+    }
+    if (new->providers) {
+        walk_merge_provider_list (a, conf, new->providers);
+    }
+
+    /* Only merge the base rejects in if the merge_rules 
+        directive has been set. */
+    if (base->rejects && new->merge_rules) {
+        walk_merge_provider_list (a, conf, base->rejects);
+    }
+    if (new->rejects) {
+        walk_merge_provider_list (a, conf, new->rejects);
+    }
 
     return (void*)conf;
 }
-#endif
 
 static void *create_authz_core_svr_config(apr_pool_t *p, server_rec *s)
 {
@@ -150,48 +175,45 @@
     return (void *) authcfg;
 }
 
-static const char *add_authz_provider(cmd_parms *cmd, void *config,
-                                      const char *arg)
+static void walk_merge_provider_list(apr_pool_t *a, authz_core_dir_conf *conf, authz_provider_list
*providers)
 {
-    authz_core_dir_conf *conf = (authz_core_dir_conf*)config;
-    authz_provider_list *newp;
-    const char *t, *w;
-
-    newp = apr_pcalloc(cmd->pool, sizeof(authz_provider_list));
-
-    t = arg;
-    w = ap_getword_white(cmd->pool, &t);
-
-    if (w)
-        newp->provider_name = apr_pstrdup(cmd->pool, w);
-    if (t)
-        newp->requirement = apr_pstrdup(cmd->pool, t);
-    newp->method_mask = cmd->limited;
+    authz_provider_list *newp = (authz_provider_list *)apr_palloc(a, sizeof(authz_provider_list));
+    memcpy(newp, providers, sizeof(authz_provider_list));
 
-    /* lookup and cache the actual provider now */
-    newp->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
-                                        newp->provider_name, "0");
-    newp->req_state = conf->req_state;
-    newp->req_state_level = conf->req_state_level;
-    newp->is_reject = (cmd->info != NULL);
-
-    /* by the time the config file is used, the provider should be loaded
-     * and registered with us.
-     */
-    if (newp->provider == NULL) {
-        return apr_psprintf(cmd->pool,
-                            "Unknown Authz provider: %s",
-                            newp->provider_name);
+    /* Since the merge is being done at a later time rather than
+        at configuration time, we need to fake the current
+        state of the list so that the new element get merged
+        into the correct location. The current state is 
+        derived from the state of the object to be merged. */
+    conf->req_state = newp->req_state;
+    conf->req_state_level = newp->req_state_level;
+    newp->one_next = NULL;
+    newp->all_next = NULL;
+
+    /* If the merging element is a reject then merge it into 
+        the reject list.  Otherwise merge it into the existing
+        provider logic. */
+    if (newp->is_reject) {
+        merge_authz_reject (conf, newp);
+    }
+    else {
+        merge_authz_provider(conf, newp);
     }
 
-    /* if the provider doesn't provide the appropriate function, reject it */
-    if (!newp->provider->check_authorization) {
-        return apr_psprintf(cmd->pool,
-                            "The '%s' Authz provider is not supported by any "
-                            "of the loaded authorization modules ",
-                            newp->provider_name);
+    /* Walk all of the elements recursively to allow each existing
+        element to be copied and merged into the final configuration.*/
+    if (providers->all_next) {
+        walk_merge_provider_list (a, conf, providers->all_next);
+    }
+    if (providers->one_next) {
+        walk_merge_provider_list (a, conf, providers->one_next);
     }
 
+    return;
+}
+
+static const char *merge_authz_provider(authz_core_dir_conf *conf, authz_provider_list *newp)
+{
     /* Add it to the list now. */
     if (!conf->providers) {
         conf->providers = newp;
@@ -286,6 +308,78 @@
     return NULL;
 }
 
+static const char *merge_authz_reject(authz_core_dir_conf *conf, authz_provider_list *newp)
+{
+    /* Since the rejects list is definitive, all reject elements
+        must be satisfied or the entire request is rejected. 
+        Therefore all of the elements are merged with AND operations.*/
+    newp->req_state = AUTHZ_REQSTATE_ALL;
+
+    /* Add it to the list now. */
+    if (!conf->rejects) {
+        conf->rejects = newp;
+    }
+    else {
+        authz_provider_list *last = conf->rejects;
+        while (last->all_next != NULL) {
+            last = last->all_next;
+        }
+        last->all_next = newp;
+    }
+
+    return NULL;
+}
+static const char *add_authz_provider(cmd_parms *cmd, void *config,
+                                      const char *arg)
+{
+    authz_core_dir_conf *conf = (authz_core_dir_conf*)config;
+    authz_provider_list *newp;
+    const char *t, *w;
+
+    newp = apr_pcalloc(cmd->pool, sizeof(authz_provider_list));
+
+    t = arg;
+    w = ap_getword_white(cmd->pool, &t);
+
+    if (w)
+        newp->provider_name = apr_pstrdup(cmd->pool, w);
+    if (t)
+        newp->requirement = apr_pstrdup(cmd->pool, t);
+    newp->method_mask = cmd->limited;
+
+    /* lookup and cache the actual provider now */
+    newp->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
+                                        newp->provider_name, "0");
+    newp->req_state = conf->req_state;
+    newp->req_state_level = conf->req_state_level;
+    newp->is_reject = (cmd->info != NULL);
+
+    /* by the time the config file is used, the provider should be loaded
+     * and registered with us.
+     */
+    if (newp->provider == NULL) {
+        return apr_psprintf(cmd->pool,
+                            "Unknown Authz provider: %s",
+                            newp->provider_name);
+    }
+
+    /* if the provider doesn't provide the appropriate function, reject it */
+    if (!newp->provider->check_authorization) {
+        return apr_psprintf(cmd->pool,
+                            "The '%s' Authz provider is not supported by any "
+                            "of the loaded authorization modules ",
+                            newp->provider_name);
+    }
+
+    /* Add the element to the correct list. */
+    if (newp->is_reject) {
+        return merge_authz_reject (conf, newp);
+    }
+    else {
+        return merge_authz_provider(conf, newp);
+    }
+}
+
 /* This is a fake authz provider that really merges various authz alias
  * configurations and then envokes them. 
  */
@@ -461,9 +555,8 @@
                      "Selects which authenticated users or groups may access "
                      "a protected space"),
     AP_INIT_RAW_ARGS("Reject", add_authz_provider, (void*)1, OR_AUTHCFG,
-                     "Rejects the specified authenticated users or groups "
-                     "from accessing "
-                     "a protected space"),
+                     "Rejects the specified authenticated users groups or "
+                     "host based requests from accessing a protected space"),
     AP_INIT_RAW_ARGS("<RequireAlias", authz_require_alias_section, NULL, RSRC_CONF,
                      "Container for authorization directives grouped under "
                      "an authz provider alias"),
@@ -473,6 +566,12 @@
     AP_INIT_RAW_ARGS("<SatisfyOne", authz_require_section, NULL, OR_AUTHCFG,
                      "Container for grouping require statements of which one " 
                      "must succeed for authorization to be granted"),
+    AP_INIT_FLAG("AuthzMergeRules", ap_set_flag_slot,
+                 (void *)APR_OFFSETOF(authz_core_dir_conf, merge_rules), OR_AUTHCFG,
+                 "Set to 'on' to allow the parent's <Directory> or <Location>
authz rules "
+                 "to be merged into the current <Directory> or <Location>.  Set
to 'off' "
+                 "to disable merging. If set to 'off', only the authz rules defined in "
+                 "the current <Directory> or <Location> block will apply. The
default is 'on'."),
     {NULL}
 };
 
@@ -502,7 +601,14 @@
     }
 
     if (current_provider->is_reject) {
-        auth_result = auth_result == AUTHZ_DENIED ? AUTHZ_GRANTED : AUTHZ_DENIED;
+        /* If the provider was called through a reject directive, then
+            alter the result accordingly.  If the original result was
+            Denied then the new result is Neutral since we can not grant
+            access simply because authorization was not rejected. */
+        auth_result = auth_result == AUTHZ_DENIED ? AUTHZ_NEUTRAL : AUTHZ_REJECTED;
+        if (auth_result == AUTHZ_REJECTED) {
+            return auth_result;
+        }
     }
 
     apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
@@ -513,11 +619,12 @@
          * embedded in a Require_all block then look to see if there 
          * is another Require_all node that needs to be satisfied 
          */
-        if (auth_result == AUTHZ_GRANTED) {
+        if ((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL)) {
             if ((current_provider->all_next) && 
                 (current_provider->all_next->req_state_level < current_provider->req_state_level))
{
-                auth_result = check_provider_list (r, current_provider->all_next,
+                authz_status temp_result = check_provider_list (r, current_provider->all_next,
                                                    current_provider->req_state_level);
+                auth_result = (temp_result == AUTHZ_NEUTRAL) ? auth_result : temp_result;
             }
             return auth_result;
         }
@@ -527,8 +634,12 @@
          * otherwise just return the auth_result 
          */
         if (current_provider->one_next) {
-            auth_result = check_provider_list (r, current_provider->one_next, 
+            authz_status temp_result = check_provider_list (r, current_provider->one_next,

                                                current_provider->req_state_level);
+            auth_result = (temp_result == AUTHZ_NEUTRAL) ? auth_result : temp_result;
+            if (auth_result == AUTHZ_REJECTED) {
+                return auth_result;
+            }
         }
         else
             return auth_result;
@@ -537,17 +648,23 @@
          * a Require_all block then look to see if there is another 
          * Require_all node that needs to be satisfied 
          */
-        if ((auth_result == AUTHZ_GRANTED) && (current_provider->all_next) &&
-            (current_provider->all_next->req_state_level < current_provider->req_state_level))
{
-            auth_result = check_provider_list (r, current_provider->all_next,
+        if (((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL))
+            && (current_provider->all_next) 
+            && (current_provider->all_next->req_state_level < current_provider->req_state_level))
{
+            authz_status temp_result = check_provider_list (r, current_provider->all_next,
                                                current_provider->req_state_level);
+            auth_result = (temp_result == AUTHZ_NEUTRAL) ? auth_result : temp_result;
+            if (auth_result == AUTHZ_REJECTED) {
+                return auth_result;
+            }
         }
         /* If the *last* auth_result was DENIED and we are inside of a 
          * Require_one block then look to see if there is another 
          * Require_one node that can be satisfied 
          */
-        else if ((auth_result == AUTHZ_DENIED) && (current_provider->one_next)
&&
-                 (current_provider->one_next->req_state_level < current_provider->req_state_level))
{
+        else if ((auth_result == AUTHZ_DENIED) 
+                 && (current_provider->one_next) 
+                 && (current_provider->one_next->req_state_level < current_provider->req_state_level))
{
             goto one_next;
         }
 
@@ -563,8 +680,9 @@
         if (auth_result == AUTHZ_DENIED) {
             if ((current_provider->one_next) && 
                 (current_provider->one_next->req_state_level < current_provider->req_state_level))
{
-                auth_result = check_provider_list (r, current_provider->one_next,
+                authz_status temp_result = check_provider_list (r, current_provider->one_next,
                                                    current_provider->req_state_level);
+                auth_result = (temp_result == AUTHZ_NEUTRAL) ? auth_result : temp_result;
             }
             return auth_result;
         }
@@ -574,8 +692,12 @@
          * otherwise just return the auth_result 
          */
         if (current_provider->all_next) {
-            auth_result = check_provider_list (r, current_provider->all_next,
+            authz_status temp_result = check_provider_list (r, current_provider->all_next,
                                                current_provider->req_state_level);
+            auth_result = (temp_result == AUTHZ_NEUTRAL) ? auth_result : temp_result;
+            if (auth_result == AUTHZ_REJECTED) {
+                return auth_result;
+            }
         }
         else
             return auth_result;
@@ -584,17 +706,24 @@
          * in a Require_one block then look to see if there is another 
          * Require_one node that can be satisfied 
          */
-        if ((auth_result == AUTHZ_DENIED) && (current_provider->one_next) &&
-            (current_provider->one_next->req_state_level < current_provider->req_state_level))
{
-            auth_result = check_provider_list (r, current_provider->one_next,
+        if ((auth_result == AUTHZ_DENIED) 
+            && (current_provider->one_next) 
+            && (current_provider->one_next->req_state_level < current_provider->req_state_level))
{
+
+            authz_status temp_result = check_provider_list (r, current_provider->one_next,
                                                current_provider->req_state_level);
+            auth_result = (temp_result == AUTHZ_NEUTRAL) ? auth_result : temp_result;
+            if (auth_result == AUTHZ_REJECTED) {
+                return auth_result;
+            }
         }
         /* If the *last* auth_result was GRANTED and we are inside of a 
          * Require_all block then look to see if there is another 
          * Require_all node that needs to be satisfied 
          */
-        else if ((auth_result == AUTHZ_GRANTED) && (current_provider->all_next)
&&
-                 (current_provider->all_next->req_state_level < current_provider->req_state_level))
{
+        else if (((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL))
+                 && (current_provider->all_next) 
+                 && (current_provider->all_next->req_state_level < current_provider->req_state_level))
{
             goto all_next;
         }
     }
@@ -619,25 +748,42 @@
         return DECLINED;
     }
 
-    current_provider = conf->providers;
-
+    /* First run through all of the rejected elements since
+        the reject directive is definitive. */
+    current_provider = conf->rejects;
     auth_result = check_provider_list (r, current_provider, 0);
 
+    /* if the authorization was not rejected out-right, then
+        run through the require logic. */
+    if ((auth_result == AUTHZ_GRANTED) || (auth_result == AUTHZ_NEUTRAL)) {
+        current_provider = conf->providers;
+        auth_result = check_provider_list (r, current_provider, 0);
+    }
+
     if (auth_result != AUTHZ_GRANTED) {
         int return_code;
 
         switch (auth_result) {
             case AUTHZ_DENIED:
+            case AUTHZ_REJECTED:
                 /* XXX If the deprecated Satisfy directive is set to anything
                    but ANY a failure in access control or authz will cause
                    an HTTP_UNAUTHORIZED.  Just the if statement
                    should be removed in 3.0 when the Satisfy directive
                    goes away. */
                 if (!note || (ap_satisfies(r) != SATISFY_ANY) || (note[0] == 'N')) {
-                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                                  "user %s: authorization failure for \"%s\": ",
-                                  r->user, r->uri);
-                    return_code = HTTP_UNAUTHORIZED;
+                    if (r->ap_auth_type == NULL) {
+                        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                                      "client denied by server configuration: %s",
+                                      r->filename); 
+                        return_code = HTTP_FORBIDDEN;
+                    }
+                    else {
+                        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                                      "user %s: authorization failure for \"%s\": ",
+                                      r->user, r->uri);
+                        return_code = HTTP_UNAUTHORIZED;
+                    }
                 }
                 else {
                     return_code = DECLINED;
@@ -703,7 +849,7 @@
 {
     STANDARD20_MODULE_STUFF,
     create_authz_core_dir_config,   /* dir config creater */
-    NULL,                           /* dir merger --- default is to override */
+    merge_authz_core_dir_config,    /* dir merger */
     create_authz_core_svr_config,   /* server config */
     NULL,                           /* merge server config */
     authz_cmds,



Mime
View raw message