From: Stefan Fritsch Date: Sat, 18 Dec 2010 17:11:14 +0000 (+0000) Subject: Add new AuthzSendForbiddenOnFailure directive to allow sending '403 FORBIDDEN' X-Git-Tag: 2.3.11~368 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e4603be7f515e922e91db452d8300b4219ac6e9f;p=apache Add new AuthzSendForbiddenOnFailure directive to allow sending '403 FORBIDDEN' instead of '401 UNAUTHORIZED' if authorization fails for an authenticated user PR: 40721 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1050677 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 5c9b7ecb92..3df0c31da2 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.3.11 + *) mod_authz_core: Add AuthzSendForbiddenOnFailure directive to allow + sending '403 FORBIDDEN' instead of '401 UNAUTHORIZED' if authorization + fails for an authenticated user. PR 40721. [Stefan Fritsch] Changes with Apache 2.3.10 diff --git a/docs/manual/mod/mod_authz_core.xml b/docs/manual/mod/mod_authz_core.xml index 1a29a8d693..262240d486 100644 --- a/docs/manual/mod/mod_authz_core.xml +++ b/docs/manual/mod/mod_authz_core.xml @@ -27,7 +27,7 @@ Base mod_authz_core.c authz_core_module -Available in Apache 2.3 and later +Available in Apache HTTPD 2.3 and later

This module provides core authorization capabilities so that @@ -585,4 +585,26 @@ alias + +AuthzSendForbiddenOnFailure +Send '403 FORBIDDEN' instead of '401 UNAUTHORIZED' if +authentication succeeds but authorization fails + +AuthzSendForbiddenOnFailure On|Off +AuthzSendForbiddenOnFailure Off +directory.htaccess + +Available in Apache HTTPD 2.3.11 and later + + +

If authentication succeeds but authorization fails, Apache HTTPD will + respond with an HTTP response code of '401 UNAUTHORIZED' by default. This + usually causes browsers to display the password dialogue to the user + again, which is not wanted in all situations. + AuthzSendForbiddenOnFailure allows to change the + response code to '403 FORBIDDEN'.

+ + + + diff --git a/modules/aaa/mod_authz_core.c b/modules/aaa/mod_authz_core.c index 217f0b026a..0919a061a0 100644 --- a/modules/aaa/mod_authz_core.c +++ b/modules/aaa/mod_authz_core.c @@ -59,7 +59,8 @@ typedef struct provider_alias_rec { typedef enum { AUTHZ_LOGIC_AND, AUTHZ_LOGIC_OR, - AUTHZ_LOGIC_OFF + AUTHZ_LOGIC_OFF, + AUTHZ_LOGIC_UNSET } authz_logic_op; typedef struct authz_section_conf authz_section_conf; @@ -80,10 +81,13 @@ typedef struct authz_core_dir_conf authz_core_dir_conf; struct authz_core_dir_conf { authz_section_conf *section; - authz_logic_op op; authz_core_dir_conf *next; + authz_logic_op op; + signed char authz_forbidden_on_fail; }; +#define UNSET -1 + typedef struct authz_core_srv_conf { apr_hash_t *alias_rec; } authz_core_srv_conf; @@ -96,7 +100,8 @@ static void *create_authz_core_dir_config(apr_pool_t *p, char *dummy) { authz_core_dir_conf *conf = apr_pcalloc(p, sizeof(*conf)); - conf->op = AUTHZ_LOGIC_OFF; + conf->op = AUTHZ_LOGIC_UNSET; + conf->authz_forbidden_on_fail = UNSET; conf->next = authz_core_first_dir_conf; authz_core_first_dir_conf = conf; @@ -111,7 +116,13 @@ static void *merge_authz_core_dir_config(apr_pool_t *p, authz_core_dir_conf *new = (authz_core_dir_conf *)newv; authz_core_dir_conf *conf; - if (new->op == AUTHZ_LOGIC_OFF || !(base->section || new->section)) { + if (new->op == AUTHZ_LOGIC_UNSET && !new->section && base->section ) { + /* Only authz_forbidden_on_fail has been set in new. Don't treat + * it as a new auth config w.r.t. AuthMerging */ + conf = apr_pmemdup(p, base, sizeof(*base)); + } + else if (new->op == AUTHZ_LOGIC_OFF || new->op == AUTHZ_LOGIC_UNSET || + !(base->section || new->section)) { conf = apr_pmemdup(p, new, sizeof(*new)); } else { @@ -145,6 +156,11 @@ static void *merge_authz_core_dir_config(apr_pool_t *p, conf->op = new->op; } + if (new->authz_forbidden_on_fail == UNSET) + conf->authz_forbidden_on_fail = base->authz_forbidden_on_fail; + else + conf->authz_forbidden_on_fail = new->authz_forbidden_on_fail; + return (void*)conf; } @@ -655,6 +671,12 @@ static const command_rec authz_cmds[] = "controls how a , , or similar " "directive's authorization directives are combined with " "those of its predecessor"), + AP_INIT_FLAG("AuthzSendForbiddenOnFailure", ap_set_flag_slot_char, + (void *)APR_OFFSETOF(authz_core_dir_conf, authz_forbidden_on_fail), + OR_AUTHCFG, + "Controls if an authorization failure should result in a " + "'403 FORBIDDEN' response instead of the HTTP-conforming " + "'401 UNAUTHORIZED'"), {NULL} }; @@ -816,20 +838,23 @@ static int authorize_user_core(request_rec *r, int after_authn) return HTTP_FORBIDDEN; } else { - /* XXX: maybe we want to return FORBIDDEN here, too??? */ ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, r, "user %s: authorization failure for \"%s\": ", r->user, r->uri); - /* - * If we're returning 401 to an authenticated user, tell them to - * try again. If unauthenticated, note_auth_failure has already - * been called during auth. - */ - if (r->user) - ap_note_auth_failure(r); - - return HTTP_UNAUTHORIZED; + if (conf->authz_forbidden_on_fail > 0) { + return HTTP_FORBIDDEN; + } + else { + /* + * If we're returning 401 to an authenticated user, tell them to + * try again. If unauthenticated, note_auth_failure has already + * been called during auth. + */ + if (r->user) + ap_note_auth_failure(r); + return HTTP_UNAUTHORIZED; + } } } else {