summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBradley Nicholes <bnicholes@apache.org>2005-12-21 20:11:42 +0000
committerBradley Nicholes <bnicholes@apache.org>2005-12-21 20:11:42 +0000
commitf0ffb8921b2417d2bccf10c27e61a0f43328be54 (patch)
tree0c5b92c240cd31c9eee98267f67460a0d8b5ba37
parentaf65af1f786469fe7b0f2474859567fcfa137a45 (diff)
downloadhttpd-f0ffb8921b2417d2bccf10c27e61a0f43328be54.tar.gz
added the directives <RequireAll>, <RequireOne> and <RequireAlias>
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/authz-dev@358364 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--modules/aaa/mod_auth.h11
-rw-r--r--modules/aaa/mod_authz_core.c383
2 files changed, 331 insertions, 63 deletions
diff --git a/modules/aaa/mod_auth.h b/modules/aaa/mod_auth.h
index 1d13ca03e4..d485abb19a 100644
--- a/modules/aaa/mod_auth.h
+++ b/modules/aaa/mod_auth.h
@@ -57,6 +57,12 @@ typedef enum {
AUTHZ_GENERAL_ERROR
} authz_status;
+typedef enum {
+ AUTHZ_REQSTATE_DEFAULT,
+ AUTHZ_REQSTATE_ONE,
+ AUTHZ_REQSTATE_ALL
+} authz_request_state;
+
typedef struct {
/* Given a username and password, expected to return AUTH_GRANTED
* if we can validate this user/password combination.
@@ -94,9 +100,12 @@ typedef struct authz_provider_list authz_provider_list;
struct authz_provider_list {
const char *provider_name;
const authz_provider *provider;
- authz_provider_list *next;
+ authz_provider_list *one_next;
+ 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;
/** String following 'require <provider>' from config file */
char *requirement;
};
diff --git a/modules/aaa/mod_authz_core.c b/modules/aaa/mod_authz_core.c
index df026f8da3..b2594afea2 100644
--- a/modules/aaa/mod_authz_core.c
+++ b/modules/aaa/mod_authz_core.c
@@ -29,10 +29,11 @@
#define APR_WANT_BYTEFUNC
#include "apr_want.h"
+#define CORE_PRIVATE
#include "ap_config.h"
#include "httpd.h"
-#include "http_core.h"
#include "http_config.h"
+#include "http_core.h"
#include "http_log.h"
#include "http_request.h"
#include "http_protocol.h"
@@ -48,8 +49,8 @@
X- Convert all of the authz modules to providers
- Remove the ap_requires field from the request_rec
-- Remove the ap_requires field from authz_dir_conf
-- Remove the function ap_requires() and authz_ap_requires()
+X- Remove the ap_requires field from authz_dir_conf
+X- Remove the function ap_requires() and authz_ap_requires()
since their functionality is no longer supported
or necessary in the refactoring
- Remove the calls to ap_some_auth_required() in the
@@ -78,10 +79,25 @@ X- Remove the AuthzXXXAuthoritative directives from all of
*/
+typedef struct provider_alias_rec {
+ char *provider_name;
+ char *provider_alias;
+ char *provider_args;
+ ap_conf_vector_t *sec_auth;
+ const authz_provider *provider;
+} provider_alias_rec;
+
typedef struct {
authz_provider_list *providers;
+ authz_request_state req_state;
+ int req_state_level;
} authz_core_dir_conf;
+typedef struct authz_core_srv_conf {
+ apr_hash_t *alias_rec;
+} authz_core_srv_conf;
+
+
module AP_MODULE_DECLARE_DATA authz_core_module;
static void *create_authz_core_dir_config(apr_pool_t *p, char *dummy)
@@ -89,6 +105,8 @@ 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_level = 0;
return (void *)conf;
}
@@ -109,6 +127,17 @@ static void *merge_authz_core_dir_config(apr_pool_t *a, void *basev, void *newv)
}
#endif
+static void *create_authz_core_svr_config(apr_pool_t *p, server_rec *s)
+{
+
+ authz_core_srv_conf *authcfg;
+
+ authcfg = (authz_core_srv_conf *) apr_pcalloc(p, sizeof(authz_core_srv_conf));
+ authcfg->alias_rec = apr_hash_make(p);
+
+ return (void *) authcfg;
+}
+
static const char *add_authz_provider(cmd_parms *cmd, void *config,
const char *arg)
{
@@ -131,6 +160,7 @@ static const char *add_authz_provider(cmd_parms *cmd, void *config,
/* 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;
/* by the time the config file is used, the provider should be loaded
* and registered with us.
@@ -155,24 +185,297 @@ static const char *add_authz_provider(cmd_parms *cmd, void *config,
}
else {
authz_provider_list *last = conf->providers;
-
- while (last->next) {
- last = last->next;
- }
- last->next = newp;
+ int level = conf->req_state_level;
+
+ /* Traverse the list to find the last entry.Each level
+ indicates a transition in the logic. */
+ do {
+ while (last->one_next) {
+ last = last->one_next;
+ continue;
+ }
+ if (last->all_next) {
+ 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) {
+ last->all_next = newp;
+ }
+ else {
+ last->one_next = newp;
+ }
}
return NULL;
}
+/* This is a fake authz provider that really merges various authz alias
+ configurations and then envokes them. */
+static authz_status authz_alias_check_authorization(request_rec *r,
+ const char *require_args)
+{
+ /* Look up the provider alias in the alias list */
+ /* Get the the dir_config and call ap_Merge_per_dir_configs() */
+ /* Call the real provider->check_authorization() function */
+ /* return the result of the above function call */
+
+ const char *provider_name = apr_table_get(r->notes, AUTHZ_PROVIDER_NAME_NOTE);
+ authz_status ret = AUTHZ_DENIED;
+ authz_core_srv_conf *authcfg =
+ (authz_core_srv_conf *)ap_get_module_config(r->server->module_config,
+ &authz_core_module);
+
+ if (provider_name) {
+ provider_alias_rec *prvdraliasrec = apr_hash_get(authcfg->alias_rec,
+ provider_name, APR_HASH_KEY_STRING);
+ ap_conf_vector_t *orig_dir_config = r->per_dir_config;
+
+ /* If we found the alias provider in the list, then merge the directory
+ configurations and call the real provider */
+ if (prvdraliasrec) {
+ r->per_dir_config = ap_merge_per_dir_configs(r->pool, orig_dir_config,
+ prvdraliasrec->sec_auth);
+ ret = prvdraliasrec->provider->check_authorization(r, prvdraliasrec->provider_args);
+ r->per_dir_config = orig_dir_config;
+ }
+ }
+
+ return ret;
+}
+
+static const authz_provider authz_alias_provider =
+{
+ &authz_alias_check_authorization,
+};
+
+static const char *authz_require_alias_section(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+ int old_overrides = cmd->override;
+ const char *endp = ap_strrchr_c(arg, '>');
+ const char *args;
+ char *provider_alias;
+ char *provider_name;
+ char *provider_args;
+ const char *errmsg;
+ ap_conf_vector_t *new_authz_config = ap_create_per_dir_config(cmd->pool);
+ authz_core_srv_conf *authcfg =
+ (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);
+ }
+
+ args = apr_pstrndup(cmd->pool, arg, endp - arg);
+
+ if (!args[0]) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "> directive requires additional arguments", NULL);
+ }
+
+ /* Pull the real provider name and the alias name from the block header */
+ provider_name = ap_getword_conf(cmd->pool, &args);
+ provider_alias = ap_getword_conf(cmd->pool, &args);
+ provider_args = ap_getword_conf(cmd->pool, &args);
+
+ if (!provider_name[0] || !provider_alias[0]) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "> directive requires additional arguments", NULL);
+ }
+
+ /* walk the subsection configuration to get the per_dir config that we will
+ merge just before the real provider is called. */
+ cmd->override = OR_ALL|ACCESS_CONF;
+ errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_authz_config);
+
+ if (!errmsg) {
+ provider_alias_rec *prvdraliasrec = apr_pcalloc(cmd->pool, sizeof(provider_alias_rec));
+ const authz_provider *provider = ap_lookup_provider(AUTHZ_PROVIDER_GROUP, provider_name,"0");
+
+ /* Save off the new directory config along with the original provider name
+ and function pointer data */
+ prvdraliasrec->sec_auth = new_authz_config;
+ prvdraliasrec->provider_name = provider_name;
+ prvdraliasrec->provider_alias = provider_alias;
+ prvdraliasrec->provider_args = provider_args;
+ prvdraliasrec->provider = provider;
+
+ apr_hash_set(authcfg->alias_rec, provider_alias, APR_HASH_KEY_STRING, prvdraliasrec);
+
+ /* Register the fake provider so that we get called first */
+ ap_register_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, provider_alias, "0",
+ &authz_alias_provider);
+ }
+
+ cmd->override = old_overrides;
+
+ return errmsg;
+}
+
+static const char *authz_require_section(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+ int old_overrides = cmd->override;
+ const char *endp = ap_strrchr_c(arg, '>');
+ const char *args;
+ const char *errmsg;
+ authz_request_state old_reqstate;
+ authz_core_dir_conf *conf = (authz_core_dir_conf*)mconfig;
+// authz_core_srv_conf *authcfg =
+// (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);
+ }
+
+ args = apr_pstrndup(cmd->pool, arg, endp - arg);
+
+ if (args[0]) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ "> directive doesn't take additional arguments", NULL);
+ }
+
+ /* Save off the current request state so that we can go back to it after walking
+ the subsection. Indicate a transition in the logic incrementing the level.
+ After the subsection walk the level will be decremented to indicate the
+ path to follow. As the require directives are read by the configuration
+ 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) {
+ conf->req_state = AUTHZ_REQSTATE_ALL;
+ }
+ else {
+ conf->req_state = AUTHZ_REQSTATE_ONE;
+ }
+ conf->req_state_level++;
+ cmd->override = OR_ALL|ACCESS_CONF;
+
+ /* walk the subsection configuration to get the per_dir config that we will
+ merge just before the real provider is called. */
+ errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
+
+ conf->req_state_level--;
+ conf->req_state = old_reqstate;
+ cmd->override = old_overrides;
+
+ return errmsg;
+}
+
static const command_rec authz_cmds[] =
{
AP_INIT_RAW_ARGS("Require", add_authz_provider, NULL, OR_AUTHCFG,
"Selects which authenticated users or groups may access "
"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"),
+ AP_INIT_RAW_ARGS("<RequireAll", authz_require_section, NULL, RSRC_CONF,
+ "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,
+ "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)
+{
+ 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
+ * 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 default authz provider configured");
+ auth_result = AUTHZ_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);
+ }
+
+ /* check to make sure that the request method requires
+ authorization before calling the provider */
+ if (!(current_provider->method_mask &
+ (AP_METHOD_BIT << r->method_number))) {
+ continue;
+ }
+
+ auth_result = provider->check_authorization(r,
+ current_provider->requirement);
+
+ 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 (current_provider->req_state == AUTHZ_REQSTATE_ONE) {
+ if (auth_result == AUTHZ_GRANTED) {
+ break;
+ }
+ if (current_provider->all_next) {
+ auth_result = check_provider_list (r, current_provider->all_next);
+ if (auth_result == AUTHZ_GRANTED) {
+ break;
+ }
+ }
+ current_provider = current_provider->one_next;
+ continue;
+ }
+
+ if (current_provider->req_state == AUTHZ_REQSTATE_ALL) {
+ if (auth_result == AUTHZ_DENIED) {
+ break;
+ }
+ if (current_provider->one_next) {
+ auth_result = check_provider_list (r, current_provider->one_next);
+ if (auth_result == AUTHZ_DENIED) {
+ break;
+ }
+ }
+ current_provider = current_provider->all_next;
+ continue;
+ }
+
+ } while (current_provider);
+
+ return auth_result;
+}
+
static int authorize_user(request_rec *r)
{
authz_core_dir_conf *conf = ap_get_module_config(r->per_dir_config,
@@ -180,60 +483,16 @@ static int authorize_user(request_rec *r)
authz_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 default authz provider configured");
- auth_result = AUTHZ_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);
- }
-
- /* check to make sure that the request method requires
- authorization before calling the provider */
- if (!(current_provider->method_mask &
- (AP_METHOD_BIT << r->method_number))) {
- continue;
- }
-
- auth_result = provider->check_authorization(r,
- current_provider->requirement);
-
- 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 (auth_result != AUTHZ_DENIED) {
- break;
- }
+ /* If we're not really configured for providers, stop now. */
+ if (!conf->providers) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "no authorization providers configured");
+ return HTTP_UNAUTHORIZED;
+ }
- /* If we're not really configured for providers, stop now. */
- if (!conf->providers) {
- break;
- }
+ current_provider = conf->providers;
- current_provider = current_provider->next;
- } while (current_provider);
+ auth_result = check_provider_list (r, current_provider);
if (auth_result != AUTHZ_GRANTED) {
int return_code;
@@ -281,7 +540,7 @@ static int authz_some_auth_required(request_rec *r)
break;
}
- current_provider = current_provider->next;
+ current_provider = current_provider->one_next;
}
return req_authz;
@@ -299,7 +558,7 @@ module AP_MODULE_DECLARE_DATA authz_core_module =
STANDARD20_MODULE_STUFF,
create_authz_core_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
- NULL, /* server config */
+ create_authz_core_svr_config, /* server config */
NULL, /* merge server config */
authz_cmds,
register_hooks /* register hooks */