From: Bradley Nicholes Date: Wed, 30 Nov 2005 04:22:48 +0000 (+0000) Subject: first cut at moving the require directive out of mod_core and implementing it as... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16011b5c9761af2834583d4f2696b1c142ee2964;p=thirdparty%2Fapache%2Fhttpd.git 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 --- diff --git a/include/http_core.h b/include/http_core.h index 62f9e95e409..60d0d0312c2 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -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 diff --git a/modules/aaa/mod_auth.h b/modules/aaa/mod_auth.h index ac44a423a31..b0a400aecd9 100644 --- a/modules/aaa/mod_auth.h +++ b/modules/aaa/mod_auth.h @@ -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 } diff --git a/modules/aaa/mod_authz_host.c b/modules/aaa/mod_authz_host.c index 582f32c7ac3..1da20614630 100644 --- a/modules/aaa/mod_authz_host.c +++ b/modules/aaa/mod_authz_host.c @@ -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 @@ -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, diff --git a/server/core.c b/server/core.c index cd71ce79918..57a03fedbee 100644 --- a/server/core.c +++ b/server/core.c @@ -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; } @@ -675,21 +663,51 @@ AP_DECLARE(const char *) ap_auth_type(request_rec *r) core_dir_config *conf; conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); + &core_module); 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; conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); + &core_module); 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);