Commit 98a2f05c authored by Bradley Nicholes's avatar Bradley Nicholes
Browse files

first cut at moving the require directive out of mod_core and implementing it as a provider vector.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/authz-dev@349875 13f79535-47bb-0310-9956-ffa450edef68
parent b0e2d9da
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -454,9 +454,9 @@ typedef struct {
    /* Authentication stuff.  Groan... */
    
    int *satisfy; /* for every method one */
    char *ap_auth_type;
    char *ap_auth_name;
    apr_array_header_t *ap_requires;
    char *ap_auth_type; /* Deprecated see mod_authz_host */
    char *ap_auth_name; /* Deprecated see mod_authz_host */
    apr_array_header_t *ap_requires; /* Deprecated see mod_authz_host */

    /* Custom response config. These can contain text or a URL to redirect to.
     * if response_code_strings is NULL then there are none in the config,
@@ -680,6 +680,18 @@ APR_DECLARE_OPTIONAL_FN(void, ap_logio_add_bytes_out,
APR_DECLARE_OPTIONAL_FN(const char *, ap_ident_lookup,
                        (request_rec *r));

/* ----------------------------------------------------------------------
 *
 * authorization values with mod_authz_host
 */

APR_DECLARE_OPTIONAL_FN(const apr_array_header_t *, authz_host_ap_requires,
                        (request_rec *r));
/*
APR_DECLARE_OPTIONAL_FN(const char *, authz_host_ap_auth_type, (request_rec *r));
APR_DECLARE_OPTIONAL_FN(const char *, authz_host_ap_auth_name, (request_rec *r));
*/

/* ---------------------------------------------------------------------- */

#ifdef __cplusplus
+30 −0
Original line number Diff line number Diff line
@@ -35,10 +35,13 @@ extern "C" {
#endif

#define AUTHN_PROVIDER_GROUP "authn"
#define AUTHZ_PROVIDER_GROUP "authz"
#define AUTHN_DEFAULT_PROVIDER "file"
#define AUTHZ_DEFAULT_PROVIDER "valid-user"
    
#define AUTHZ_GROUP_NOTE "authz_group_note"
#define AUTHN_PROVIDER_NAME_NOTE "authn_provider_name"
#define AUTHZ_PROVIDER_NAME_NOTE "authz_provider_name"

typedef enum {
    AUTH_DENIED,
@@ -71,10 +74,37 @@ struct authn_provider_list {
    authn_provider_list *next;
};

typedef struct {
    /* Given a username and password, expected to return AUTH_GRANTED
    * if we can validate this user/password combination.
    */
    authn_status (*check_authorization)(request_rec *r);
} authz_provider;

/* A linked-list of authn providers. */
typedef struct authz_provider_list authz_provider_list;

struct authz_provider_list {
    const char *provider_name;
    const authz_provider *provider;
    authz_provider_list *next;
    /** Where the require line is in the config file. */
    apr_int64_t method_mask;
    /** The complete string from the command line */
    char *requirement;
};

/* Need to add an enum for authz_status.  Convert one of the authorization
   modules to deal with the new require directive.
*/


#if 0
typedef struct {
    /* For a given user, return a hash of all groups the user belongs to.  */
    apr_hash_t * (*get_user_groups)(request_rec *r, const char *user);
} authz_provider;
#endif

#ifdef __cplusplus
}
+246 −1
Original line number Diff line number Diff line
@@ -35,6 +35,10 @@
#include "http_config.h"
#include "http_log.h"
#include "http_request.h"
#include "http_protocol.h"
#include "ap_provider.h"

#include "mod_auth.h"

#if APR_HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -66,6 +70,8 @@ typedef struct {
    int order[METHODS];
    apr_array_header_t *allows;
    apr_array_header_t *denys;
    apr_array_header_t *ap_requires;
    authz_provider_list *providers;
} authz_host_dir_conf;

module AP_MODULE_DECLARE_DATA authz_host_module;
@@ -85,6 +91,35 @@ static void *create_authz_host_dir_config(apr_pool_t *p, char *dummy)
    return (void *)conf;
}

static void *merge_authz_host_dir_config(apr_pool_t *a, void *basev, void *newv)
{
    authz_host_dir_conf *base = (authz_host_dir_conf *)basev;
    authz_host_dir_conf *new = (authz_host_dir_conf *)newv;
    authz_host_dir_conf *conf;
    
    /* Create this conf by duplicating the base, replacing elements
    * (or creating copies for merging) where new-> values exist.
    */
    conf = (authz_host_dir_conf *)apr_palloc(a, sizeof(authz_host_dir_conf));
    memcpy(conf, base, sizeof(authz_host_dir_conf));

    /*
    if (new->ap_auth_type) {
        conf->ap_auth_type = new->ap_auth_type;
    }

    if (new->ap_auth_name) {
        conf->ap_auth_name = new->ap_auth_name;
    }
    */

    if (new->ap_requires) {
        conf->ap_requires = new->ap_requires;
    }

    return (void*)conf;
}

static const char *order(cmd_parms *cmd, void *dv, const char *arg)
{
    authz_host_dir_conf *d = (authz_host_dir_conf *) dv;
@@ -159,6 +194,85 @@ static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from,
    return NULL;
}

/*
 * Load an authorisation realm into our location configuration, applying the
 * usual rules that apply to realms.
 */
/*
static const char *set_authname(cmd_parms *cmd, void *mconfig,
                                const char *word1)
{
    authz_host_dir_conf *aconfig = (authz_host_dir_conf *)mconfig;

    aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1);
    return NULL;
}
*/

/*
static const char *require(cmd_parms *cmd, void *c_, const char *arg)
{
    require_line *r;
    authz_host_dir_conf *c = c_;

    if (!c->ap_requires) {
        c->ap_requires = apr_array_make(cmd->pool, 2, sizeof(require_line));
    }

    r = (require_line *)apr_array_push(c->ap_requires);
    r->requirement = apr_pstrdup(cmd->pool, arg);
    r->method_mask = cmd->limited;

    return NULL;
}
*/

static const char *add_authz_provider(cmd_parms *cmd, void *config,
                                      const char *arg)
{
    authz_host_dir_conf *conf = (authz_host_dir_conf*)config;
    authz_provider_list *newp;

    newp = apr_pcalloc(cmd->pool, sizeof(authz_provider_list));
    newp->provider_name = apr_pstrdup(cmd->pool, arg);
    newp->requirement = apr_pstrdup(cmd->pool, arg);
    newp->method_mask = cmd->limited;

    /* lookup and cache the actual provider now */
    newp->provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
                                        newp->provider_name, "0");

    if (newp->provider == NULL) {
        /* by the time they use it, the provider should be loaded and
        registered with us. */
        return apr_psprintf(cmd->pool,
                            "Unknown Authz provider: %s",
                            newp->provider_name);
    }

    if (!newp->provider->check_authorization) {
        /* if it doesn't provide the appropriate function, reject it */
        return apr_psprintf(cmd->pool,
                            "The '%s' Authz provider is not supported by any of the "
                                    "loaded authorization modules", newp->provider_name);
    }

    /* Add it to the list now. */
    if (!conf->providers) {
        conf->providers = newp;
    }
    else {
        authz_provider_list *last = conf->providers;

        while (last->next) {
            last = last->next;
        }
        last->next = newp;
    }

    return NULL;
}

static char its_an_allow;

static const command_rec authz_host_cmds[] =
@@ -169,8 +283,17 @@ static const command_rec authz_host_cmds[] =
                     "'from' followed by hostnames or IP-address wildcards"),
    AP_INIT_ITERATE2("deny", allow_cmd, NULL, OR_LIMIT,
                     "'from' followed by hostnames or IP-address wildcards"),
    AP_INIT_RAW_ARGS("Require", add_authz_provider, NULL, OR_AUTHCFG,
                     "Selects which authenticated users or groups may access a protected space"),
    {NULL}
};
/*
    AP_INIT_TAKE1("AuthType", ap_set_string_slot,
                  (void*)APR_OFFSETOF(authz_host_dir_conf, ap_auth_type), OR_AUTHCFG,
                  "An HTTP authorization type (e.g., \"Basic\")"),
    AP_INIT_TAKE1("AuthName", set_authname, NULL, OR_AUTHCFG,
                  "The authentication realm (e.g. \"Members Only\")"),
*/

static int in_domain(const char *domain, const char *what)
{
@@ -304,17 +427,139 @@ static int check_dir_access(request_rec *r)
    return ret;
}

static int authorize_user(request_rec *r)
{
    authz_host_dir_conf *conf = ap_get_module_config(r->per_dir_config,
            &authz_host_module);
    authn_status auth_result;
    authz_provider_list *current_provider;

    current_provider = conf->providers;
    do {
        const authz_provider *provider;

        /* For now, if a provider isn't set, we'll be nice and use the file
        * provider.
        */
        if (!current_provider) {
            provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP,
                                          AUTHZ_DEFAULT_PROVIDER, "0");

            if (!provider || !provider->check_authorization) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              "No Authz provider configured");
                auth_result = AUTH_GENERAL_ERROR;
                break;
            }
            apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE, AUTHZ_DEFAULT_PROVIDER);
        }
        else {
            provider = current_provider->provider;
            apr_table_setn(r->notes, AUTHZ_PROVIDER_NAME_NOTE, current_provider->provider_name);
        }


        auth_result = provider->check_authorization(r);

        apr_table_unset(r->notes, AUTHZ_PROVIDER_NAME_NOTE);

        /* Something occured. Stop checking. */
        if (auth_result != AUTH_DENIED) {
            break;
        }

        /* If we're not really configured for providers, stop now. */
        if (!conf->providers) {
            break;
        }

        current_provider = current_provider->next;
    } while (current_provider);

    if (auth_result != AUTH_GRANTED) {
        int return_code;

/* XXX need to deal with DECLINED vs DENIED.  DECLINED may not even
   be needed since we are only going to call registered require providers.
   I assume that it will deal with passing from one provider to the next
   according to the order and the Authz_xxx_Authoritative directives.
*/
        switch (auth_result) {
            case AUTH_DENIED:
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              "user %s: authorization failure for \"%s\": ",
                              r->user, r->uri);
                return_code = HTTP_UNAUTHORIZED;
                break;
            case AUTH_GENERAL_ERROR:
            default:
            /* We'll assume that the module has already said what its error
                * was in the logs.
            */
                return_code = HTTP_INTERNAL_SERVER_ERROR;
                break;
        }

        /* If we're returning 403, tell them to try again. */
        if (return_code == HTTP_UNAUTHORIZED) {
            ap_note_basic_auth_failure (r);
        }
        return return_code;
    }

    return OK;
}

static const apr_array_header_t *authz_host_ap_requires(request_rec *r)
{
    authz_host_dir_conf *conf;

    conf = (authz_host_dir_conf *)ap_get_module_config(r->per_dir_config,
        &authz_host_module);

    return conf->ap_requires;
}

/*
static const char *authz_host_ap_auth_type(request_rec *r)
{
    authz_host_dir_conf *conf;

    conf = (authz_host_dir_conf *)ap_get_module_config(r->per_dir_config,
        &authz_host_module);

    return conf->ap_auth_type;
}

static const char *authz_host_ap_auth_name(request_rec *r)
{
    authz_host_dir_conf *conf;

    conf = (authz_host_dir_conf *)ap_get_module_config(r->per_dir_config,
        &authz_host_module);

    return conf->ap_auth_name;
}
*/

static void register_hooks(apr_pool_t *p)
{
    APR_REGISTER_OPTIONAL_FN(authz_host_ap_requires);
    /*
    APR_REGISTER_OPTIONAL_FN(authz_host_ap_auth_type);
    APR_REGISTER_OPTIONAL_FN(authz_host_ap_auth_name);
    */

    /* This can be access checker since we don't require r->user to be set. */
    ap_hook_access_checker(check_dir_access,NULL,NULL,APR_HOOK_MIDDLE);
    ap_hook_auth_checker(authorize_user, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA authz_host_module =
{
    STANDARD20_MODULE_STUFF,
    create_authz_host_dir_config,   /* dir config creater */
    NULL,                           /* dir merger --- default is to override */
    merge_authz_host_dir_config,    /* dir merger --- default is to override */
    NULL,                           /* server config */
    NULL,                           /* merge server config */
    authz_host_cmds,
+46 −38
Original line number Diff line number Diff line
@@ -268,18 +268,6 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
        conf->ap_default_type = new->ap_default_type;
    }

    if (new->ap_auth_type) {
        conf->ap_auth_type = new->ap_auth_type;
    }

    if (new->ap_auth_name) {
        conf->ap_auth_name = new->ap_auth_name;
    }

    if (new->ap_requires) {
        conf->ap_requires = new->ap_requires;
    }

    if (conf->response_code_strings == NULL) {
        conf->response_code_strings = new->response_code_strings;
    }
@@ -680,6 +668,21 @@ AP_DECLARE(const char *) ap_auth_type(request_rec *r)
    return conf->ap_auth_type;
}

/*
 * Optional function coming from mod_ident, used for looking up ident user
 */
/*
static APR_OPTIONAL_FN_TYPE(authz_host_ap_auth_type) *azh_ap_auth_type;

AP_DECLARE(const char *) ap_auth_type(request_rec *r)
{
    if (azh_ap_auth_type) {
        return azh_ap_auth_type(r);
    }
    return NULL;
}
*/

AP_DECLARE(const char *) ap_auth_name(request_rec *r)
{
    core_dir_config *conf;
@@ -690,6 +693,21 @@ AP_DECLARE(const char *) ap_auth_name(request_rec *r)
    return conf->ap_auth_name;
}

/*
 * Optional function coming from mod_ident, used for looking up ident user
 */
/*
static APR_OPTIONAL_FN_TYPE(authz_host_ap_auth_name) *azh_ap_auth_name;

AP_DECLARE(const char *) ap_auth_name(request_rec *r)
{
    if (azh_ap_auth_name) {
        return azh_ap_auth_name(r);
    }
    return NULL;
}
*/

AP_DECLARE(const char *) ap_default_type(request_rec *r)
{
    core_dir_config *conf;
@@ -712,14 +730,17 @@ AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
    return conf->ap_document_root;
}

/*
 * Optional function coming from mod_ident, used for looking up ident user
 */
static APR_OPTIONAL_FN_TYPE(authz_host_ap_requires) *azh_ap_requires;

AP_DECLARE(const apr_array_header_t *) ap_requires(request_rec *r)
{
    core_dir_config *conf;

    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
                                                   &core_module);

    return conf->ap_requires;
    if (azh_ap_requires) {
        return azh_ap_requires(r);
    }
    return NULL;
}

AP_DECLARE(int) ap_satisfies(request_rec *r)
@@ -1684,22 +1705,6 @@ static const char *satisfy(cmd_parms *cmd, void *c_, const char *arg)
    return NULL;
}

static const char *require(cmd_parms *cmd, void *c_, const char *arg)
{
    require_line *r;
    core_dir_config *c = c_;

    if (!c->ap_requires) {
        c->ap_requires = apr_array_make(cmd->pool, 2, sizeof(require_line));
    }

    r = (require_line *)apr_array_push(c->ap_requires);
    r->requirement = apr_pstrdup(cmd->pool, arg);
    r->method_mask = cmd->limited;

    return NULL;
}

/*
 * Report a missing-'>' syntax error.
 */
@@ -3232,8 +3237,6 @@ AP_INIT_TAKE1("AuthType", ap_set_string_slot,
  "An HTTP authorization type (e.g., \"Basic\")"),
AP_INIT_TAKE1("AuthName", set_authname, NULL, OR_AUTHCFG,
  "The authentication realm (e.g. \"Members Only\")"),
AP_INIT_RAW_ARGS("Require", require, NULL, OR_AUTHCFG,
  "Selects which authenticated users or groups may access a protected space"),
AP_INIT_TAKE1("Satisfy", satisfy, NULL, OR_AUTHCFG,
  "access policy if both allow and require used ('all' or 'any')"),
#ifdef GPROF
@@ -3723,6 +3726,11 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte
{
    logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
    ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
    azh_ap_requires = APR_RETRIEVE_OPTIONAL_FN(authz_host_ap_requires);
    /*
    azh_ap_auth_type = APR_RETRIEVE_OPTIONAL_FN(authz_host_ap_auth_type);
    azh_ap_auth_name = APR_RETRIEVE_OPTIONAL_FN(authz_host_ap_auth_name);
    */

    ap_set_version(pconf);
    ap_setup_make_content_type(pconf);