Commit b52b6af9 authored by Bradley Nicholes's avatar Bradley Nicholes
Browse files

debugged the require_one and require_all linked list set up to make sure that...

debugged the require_one and require_all linked list set up to make sure that the lists are being created to match the logic that is layed out in the configuration file.  Also debugged the authz provider handling to make sure that the 'and/or' logic is being followed as the providers are checked and return the authorization result

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/authz-dev@359160 13f79535-47bb-0310-9956-ffa450edef68
parent ea0c5c05
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ typedef enum {
} authz_status;

typedef enum {
	AUTHZ_REQSTATE_DEFAULT,
	AUTHZ_REQSTATE_ONE,
	AUTHZ_REQSTATE_ALL
} authz_request_state;
@@ -104,8 +103,8 @@ struct authz_provider_list {
	authz_provider_list *all_next;
    /** If a Limit method is in effect, this field will be set */
    apr_int64_t method_mask;
	/** If a request status is in effect, this filed will be set */
	authz_request_state req_state;
    int req_state_level;
    /** String following 'require <provider>' from config file */
    char *requirement;
};
+283 −193
Original line number Diff line number Diff line
@@ -69,13 +69,18 @@ X- Change the status code to AUTHZ_DENIED, AUTHZ_GRANTED
- Determine if setting the AUTHZ_PROVIDER_NAME_NOTE note
   is even necessary.  This was used in authn to support
   authn_alias.  Is there a need for an authz_alias?
- Move the Satisfy directive out of mod_core and into
   mod_authz_core.
- Expand the Satisfy directive to handle 'and' and 'or'
   logic for determining which authorization must succeed
   vs. may succeed
- Remove the Satisfy directive and replace it with the
   <RequireAll>, <RequireOne> directives
X- Implement the <RequireAll> <RequireOne> block directives
   to handle the 'and' and 'or' logic for authorization.
X- Remove the AuthzXXXAuthoritative directives from all of
   the authz providers
- Implement the Reject directive that will deny authorization
   if the argument is true
- Fold the Reject directive into the <RequireAll> <RequireOne>
   logic
- Reimplement the host based authorization 'allow', 'deny'
   and 'order' as authz providers   
      
*/

@@ -105,7 +110,7 @@ static void *create_authz_core_dir_config(apr_pool_t *p, char *dummy)
    authz_core_dir_conf *conf =
            (authz_core_dir_conf *)apr_pcalloc(p, sizeof(authz_core_dir_conf));

	conf->req_state = AUTHZ_REQSTATE_DEFAULT;
    conf->req_state = AUTHZ_REQSTATE_ONE;
    conf->req_state_level = 0;
    return (void *)conf;
}
@@ -146,7 +151,6 @@ static const char *add_authz_provider(cmd_parms *cmd, void *config,
    const char *t, *w;

    newp = apr_pcalloc(cmd->pool, sizeof(authz_provider_list));
    /* XXX: Split this out to the name and then the rest of the directive. */

    t = arg;
    w = ap_getword_white(cmd->pool, &t);
@@ -161,6 +165,7 @@ static const char *add_authz_provider(cmd_parms *cmd, void *config,
    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;

    /* by the time the config file is used, the provider should be loaded
     * and registered with us.
@@ -187,29 +192,77 @@ static const char *add_authz_provider(cmd_parms *cmd, void *config,
        authz_provider_list *last = conf->providers;
        int level = conf->req_state_level;

        /* if the level is 0 then take care of the implicit 'or'
           operation at this level. */
        if (level == 0) {
            /* Just run through the Require_one list and add the
                node */
            while (last->one_next) {
                last = last->one_next;
            }
            last->one_next = newp;
        } 
        else {
            /* Traverse the list to find the last entry.Each level 
               indicates a transition in the logic. */
		do {
            for (;level;level--) {
                /* if we are in a Require_all block then run through
                    all of the Require_all nodes to the end of the list */
                if (last->req_state == AUTHZ_REQSTATE_ALL) {
                    while (last->all_next) {
                        last = last->all_next;
                    }
                    /* If the end of the list contains a node state
                        change then run through all of the Require_one
                        nodes to the end of that list */
                    if (level >= last->req_state_level) {
                        while (last->one_next) {
                            last = last->one_next;
                        }
                    }
                    continue;
                }
			if (last->all_next) {
                /* if we are in a Require_one block then run through
                    all of the Require_one nodes to the end of the list */
                if (last->req_state == AUTHZ_REQSTATE_ONE) {
                    while (last->one_next) {
                        last = last->one_next;
                    }
                    /* If the end of the list contains a node state
                        change then run through all of the Require_all
                        nodes to the end of that list */
                    if (level >= last->req_state_level) {
                        while (last->all_next) {
                            last = last->all_next;
                        }
                    }
                    continue;
                }
            }
		} while (level--);

            /* The current state flag indicates which way the transition should
               go.  If ALL then take the all_next path, otherwise one_next */
		if (conf->req_state == AUTHZ_REQSTATE_ALL) {
            if (last->req_state == AUTHZ_REQSTATE_ALL) {
                /* If we already have an all_next node, then
                   we must have dropped back a level so assign
                   the node to one_next */
                if (!last->all_next) {
                    last->all_next = newp;
                }
                else
                    last->one_next = newp;
            }
            else {
                /* If we already have a one_next node, then
                   we must have dropped back a level so assign
                   the node to all_next */
                if (!last->one_next) {
                    last->one_next = newp;
                }
                else
                    last->all_next = newp;
            }
        }
    }

    return NULL;
@@ -336,11 +389,6 @@ static const char *authz_require_section(cmd_parms *cmd, void *mconfig, const ch
//      (authz_core_srv_conf *)ap_get_module_config(cmd->server->module_config,
//                                                   &authz_core_module);

    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
    if (err != NULL) {
        return err;
    }

    if (endp == NULL) {
        return apr_pstrcat(cmd->pool, cmd->cmd->name,
                           "> directive missing closing '>'", NULL);
@@ -360,7 +408,7 @@ static const char *authz_require_section(cmd_parms *cmd, void *mconfig, const ch
       the req_state and the level will allow it to traverse the list to find
       the last element in the provider calling list. */
    old_reqstate = conf->req_state;
	if (strcasecmp (arg, "RequireAll") == 0) {
    if (strcasecmp (cmd->directive->directive, "<RequireAll") == 0) {
        conf->req_state = AUTHZ_REQSTATE_ALL;
    }
    else {
@@ -388,20 +436,19 @@ static const command_rec authz_cmds[] =
    AP_INIT_RAW_ARGS("<RequireAlias", authz_require_alias_section, NULL, RSRC_CONF,
                     "Container for authorization directives grouped under "
                     "an authz provider alias"),
	AP_INIT_RAW_ARGS("<RequireAll", authz_require_section, NULL, RSRC_CONF,
    AP_INIT_RAW_ARGS("<RequireAll", authz_require_section, NULL, OR_AUTHCFG,
                     "Container for grouping require statements that must all " 
                     "succeed for authorization to be granted"),
	AP_INIT_RAW_ARGS("<RequireOne", authz_require_section, NULL, RSRC_CONF,
    AP_INIT_RAW_ARGS("<RequireOne", authz_require_section, NULL, OR_AUTHCFG,
                     "Container for grouping require statements of which one " 
                     "must succeed for authorization to be granted"),
    {NULL}
};

static authz_status check_provider_list (request_rec *r, authz_provider_list *current_provider)
static authz_status check_provider_list (request_rec *r, authz_provider_list *current_provider, int prev_level)
{
    authz_status auth_result = AUTHZ_DENIED;

	do {
    const authz_provider *provider;

    /* For now, if a provider isn't set, we'll be nice and use the file
@@ -415,7 +462,7 @@ static authz_status check_provider_list (request_rec *r, authz_provider_list *cu
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                          "No default authz provider configured");
            auth_result = AUTHZ_GENERAL_ERROR;
				break;
            return auth_result;
        }
        apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE,
                       AUTHZ_DEFAULT_PROVIDER);
@@ -430,7 +477,7 @@ static authz_status check_provider_list (request_rec *r, authz_provider_list *cu
    authorization before calling the provider */
    if (!(current_provider->method_mask & 
        (AP_METHOD_BIT << r->method_number))) {
			continue;
        return AUTHZ_DENIED;
    }

    auth_result = provider->check_authorization(r,
@@ -438,40 +485,83 @@ static authz_status check_provider_list (request_rec *r, authz_provider_list *cu

    apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);

		/* Something occured. Stop checking. */
		/* XXX: We need to figure out what the implications of multiple
		 * require directives are.  Must all satisfy?  Can we leverage
		 * satisfy here then?
		 */
    /* If the current node is a Require_One type */
    if (current_provider->req_state == AUTHZ_REQSTATE_ONE) {
        /* if the auth_result of *this* node was GRANTED and we are 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) {
				break;
            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,
                                                   current_provider->req_state_level);
            }
			if (current_provider->all_next) {
				auth_result = check_provider_list (r, current_provider->all_next);
				if (auth_result == AUTHZ_GRANTED) {
					break;
            return auth_result;
        }
        one_next:

        /* Traverse forward to the next Require_one node it one exists 
            otherwise just return the auth_result */
        if (current_provider->one_next) {
            auth_result = check_provider_list (r, current_provider->one_next, 
                                               current_provider->req_state_level);
        }
			current_provider = current_provider->one_next;
			continue;
        else
            return auth_result;

        /* if the *last* auth_result was GRANTED and we are 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) && (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,
                                               current_provider->req_state_level);
        }
             /* 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)) {
            goto one_next;
        }

		if (current_provider->req_state == AUTHZ_REQSTATE_ALL) {
			if (auth_result == AUTHZ_DENIED) {
				break;
        return auth_result;
    }
			if (current_provider->one_next) {
				auth_result = check_provider_list (r, current_provider->one_next);

    /* If the current node is a Require_All type */
    if (current_provider->req_state == AUTHZ_REQSTATE_ALL) {
        /* if the auth_result of *this* node was DENIED and we are embedded 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) {
					break;
            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,
                                                   current_provider->req_state_level);
            }
            return auth_result;
        }
			current_provider = current_provider->all_next;
			continue;
        all_next:

        /* Traverse forward to the next Require_all node it one exists 
            otherwise just return the auth_result */
        if (current_provider->all_next) {
            auth_result = check_provider_list (r, current_provider->all_next,
                                               current_provider->req_state_level);
        }
        else
            return auth_result;

	} while (current_provider);
        /* if the *last* auth_result was DENIED and we are embedded 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,
                                               current_provider->req_state_level);
        }
             /* 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)) {
            goto all_next;
        }
    }

    return auth_result;
}
@@ -492,7 +582,7 @@ static int authorize_user(request_rec *r)

    current_provider = conf->providers;

	auth_result = check_provider_list (r, current_provider);
    auth_result = check_provider_list (r, current_provider, 0);

    if (auth_result != AUTHZ_GRANTED) {
        int return_code;