From: Chris Darroch Date: Wed, 14 Aug 2013 21:57:21 +0000 (+0000) Subject: Add AuthBasicUseDigestAlgorithm directive to allow migration of X-Git-Tag: 2.5.0-alpha~5191 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=785201bff8e467dfdf4760408240ca38299098c7;p=apache Add AuthBasicUseDigestAlgorithm directive to allow migration of passwords from digest to basic authentication. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1514064 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 3d4e8eff76..24c4284513 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_auth_basic: Add AuthBasicUseDigestAlgorithm directive to + allow migration of passwords from digest to basic authentication. + [Chris Darroch] + *) core: Add util_fcgi.h and associated definitions and support routines for FastCGI, based largely on mod_proxy_fcgi. [Jeff Trawick] diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index e7ff0dbf84..e2e75c06b5 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -2493 +2494 diff --git a/docs/manual/mod/mod_auth_basic.xml b/docs/manual/mod/mod_auth_basic.xml index 1e22d0a5c4..ea4e675bd8 100644 --- a/docs/manual/mod/mod_auth_basic.xml +++ b/docs/manual/mod/mod_auth_basic.xml @@ -180,4 +180,79 @@ username and password + +AuthBasicUseDigestAlgorithm +Check passwords against the authentication providers as if +Digest Authentication was in force instead of Basic Authentication. + +AuthBasicUseDigestAlgorithm MD5|Off +AuthBasicUseDigestAlgorithm Off +directory.htaccess + +AuthConfig + + +

Normally, when using Basic Authentication, the providers listed in + AuthBasicProvider + attempt to verify a user by checking their data stores for + a matching username and associated password. The stored passwords + are usually encrypted, but not necessarily so; each provider may + choose its own storage scheme for passwords.

+ +

When using AuthDigestProvider and Digest + Authentication, providers perform a similar check to find a matching + username in their data stores. However, unlike in the Basic + Authentication case, the value associated with each stored username + must be an encrypted string composed from the username, realm name, + and password. (See + + RFC 2617, Section 3.2.2.2 for more details on the format used + for this encrypted string.)

+ +

As a consequence of the difference in the stored values between + Basic and Digest Authentication, converting from Digest + Authentication to Basic Authentication generally requires that all + users be assigned new passwords, as their existing passwords cannot + be recovered from the password storage scheme imposed on those + providers which support Digest Authentication.

+ +

Setting the AuthBasicUseDigestAlgorithm directive + to MD5 will cause the user's Basic Authentication password + to be checked using the same encrypted format as for Digest + Authentication. First a string composed from the username, realm name, + and password is hashed with MD5; then the username and this encrypted + string are passed to the providers listed in + AuthBasicProvider + as if + AuthType + was set to Digest and Digest Authentication was in force. +

+ +

Through the use of AuthBasicUseDigestAlgorithm + a site may switch from Digest to Basic Authentication without + requiring users to be assigned new passwords.

+ + + The inverse process of switching from Basic to Digest + Authentication without assigning new passwords is generally + not possible. Only if the Basic Authentication passwords + have been stored in plain text or with a reversable encryption + scheme will it be possible to recover them and generate a + new data store following the Digest Authentication password + storage scheme. + + + + Only providers which support Digest Authentication will be able + to authenticate users when AuthBasicUseDigestAlgorithm + is set to MD5. Use of other providers will result + in an error response and the client will be denied access. + +
+
+ diff --git a/modules/aaa/mod_auth_basic.c b/modules/aaa/mod_auth_basic.c index b75e70e2a0..4c04ae496b 100644 --- a/modules/aaa/mod_auth_basic.c +++ b/modules/aaa/mod_auth_basic.c @@ -27,6 +27,7 @@ #include "http_log.h" #include "http_protocol.h" #include "http_request.h" +#include "util_md5.h" #include "ap_provider.h" #include "ap_expr.h" @@ -38,7 +39,9 @@ typedef struct { int authoritative; ap_expr_info_t *fakeuser; ap_expr_info_t *fakepass; + const char *use_digest_algorithm; int fake_set:1; + int use_digest_algorithm_set:1; int authoritative_set:1; } auth_basic_config_rec; @@ -70,6 +73,12 @@ static void *merge_auth_basic_dir_config(apr_pool_t *p, void *basev, void *overr overrides->fake_set ? overrides->fakepass : base->fakepass; newconf->fake_set = overrides->fake_set || base->fake_set; + newconf->use_digest_algorithm = + overrides->use_digest_algorithm_set ? overrides->use_digest_algorithm + : base->use_digest_algorithm; + newconf->use_digest_algorithm_set = + overrides->use_digest_algorithm_set || base->use_digest_algorithm_set; + newconf->providers = overrides->providers ? overrides->providers : base->providers; return newconf; @@ -175,6 +184,23 @@ static const char *add_basic_fake(cmd_parms * cmd, void *config, return NULL; } +static const char *set_use_digest_algorithm(cmd_parms *cmd, void *config, + const char *alg) +{ + auth_basic_config_rec *conf = (auth_basic_config_rec *)config; + + if (strcasecmp(alg, "Off") && strcasecmp(alg, "MD5")) { + return apr_pstrcat(cmd->pool, + "Invalid algorithm in " + "AuthBasicUseDigestAlgorithm: ", alg, NULL); + } + + conf->use_digest_algorithm = apr_pstrdup(cmd->pool, alg); + conf->use_digest_algorithm_set = 1; + + return NULL; +} + static const command_rec auth_basic_cmds[] = { AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG, @@ -186,6 +212,10 @@ static const command_rec auth_basic_cmds[] = "Fake basic authentication using the given expressions for " "username and password, 'off' to disable. Password defaults " "to 'password' if missing."), + AP_INIT_TAKE1("AuthBasicUseDigestAlgorithm", set_use_digest_algorithm, + NULL, OR_AUTHCFG, + "Set to 'MD5' to use the auth provider's authentication " + "check for digest auth, using a hash of 'user:realm:pass'"), {NULL} }; @@ -271,6 +301,8 @@ static int authenticate_basic_user(request_rec *r) auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config, &auth_basic_module); const char *sent_user, *sent_pw, *current_auth; + const char *realm = NULL; + const char *digest = NULL; int res; authn_status auth_result; authn_provider_list *current_provider; @@ -295,6 +327,15 @@ static int authenticate_basic_user(request_rec *r) return res; } + if (conf->use_digest_algorithm + && !strcasecmp(conf->use_digest_algorithm, "MD5")) { + realm = ap_auth_name(r); + digest = ap_md5(r->pool, + (unsigned char *)apr_pstrcat(r->pool, sent_user, ":", + realm, ":", + sent_pw, NULL)); + } + current_provider = conf->providers; do { const authn_provider *provider; @@ -320,8 +361,27 @@ static int authenticate_basic_user(request_rec *r) apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name); } + if (digest) { + char *password; - auth_result = provider->check_password(r, sent_user, sent_pw); + if (!provider->get_realm_hash) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02493) + "Authn provider does not support " + "AuthBasicUseDigestAlgorithm"); + auth_result = AUTH_GENERAL_ERROR; + break; + } + /* We expect the password to be hash of user:realm:password */ + auth_result = provider->get_realm_hash(r, sent_user, realm, + &password); + if (auth_result == AUTH_USER_FOUND) { + auth_result = strcmp(digest, password) ? AUTH_DENIED + : AUTH_GRANTED; + } + } + else { + auth_result = provider->check_password(r, sent_user, sent_pw); + } apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);