You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ch...@apache.org on 2013/08/14 23:57:21 UTC

svn commit: r1514064 - in /httpd/httpd/trunk: CHANGES docs/log-message-tags/next-number docs/manual/mod/mod_auth_basic.xml modules/aaa/mod_auth_basic.c

Author: chrisd
Date: Wed Aug 14 21:57:21 2013
New Revision: 1514064

URL: http://svn.apache.org/r1514064
Log:
Add AuthBasicUseDigestAlgorithm directive to allow migration of
passwords from digest to basic authentication.

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/docs/manual/mod/mod_auth_basic.xml
    httpd/httpd/trunk/modules/aaa/mod_auth_basic.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1514064&r1=1514063&r2=1514064&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Wed Aug 14 21:57:21 2013
@@ -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]

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1514064&r1=1514063&r2=1514064&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Wed Aug 14 21:57:21 2013
@@ -1 +1 @@
-2493
+2494

Modified: httpd/httpd/trunk/docs/manual/mod/mod_auth_basic.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_auth_basic.xml?rev=1514064&r1=1514063&r2=1514064&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_auth_basic.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_auth_basic.xml Wed Aug 14 21:57:21 2013
@@ -180,4 +180,79 @@ username and password</description>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>AuthBasicUseDigestAlgorithm</name>
+<description>Check passwords against the authentication providers as if
+Digest Authentication was in force instead of Basic Authentication.
+</description>
+<syntax>AuthBasicUseDigestAlgorithm MD5|Off</syntax>
+<default>AuthBasicUseDigestAlgorithm Off</default>
+<contextlist><context>directory</context><context>.htaccess</context>
+</contextlist>
+<override>AuthConfig</override>
+
+<usage>
+    <p>Normally, when using Basic Authentication, the providers listed in
+    <directive module="mod_auth_basic">AuthBasicProvider</directive>
+    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.</p>
+
+    <p>When using <directive
+    module="mod_auth_digest">AuthDigestProvider</directive> 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
+    <a href="http://tools.ietf.org/html/rfc2617#section-3.2.2.2">
+    RFC 2617, Section 3.2.2.2</a> for more details on the format used
+    for this encrypted string.)</p>
+
+    <p>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.</p>
+
+    <p>Setting the <directive
+    module="mod_auth_basic">AuthBasicUseDigestAlgorithm</directive> directive
+    to <code>MD5</code> 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
+    <directive module="mod_auth_basic">AuthBasicProvider</directive>
+    as if
+    <directive module="mod_authn_core">AuthType</directive>
+    was set to <code>Digest</code> and Digest Authentication was in force.
+    </p>
+
+    <p>Through the use of <directive
+    module="mod_auth_basic">AuthBasicUseDigestAlgorithm</directive>
+    a site may switch from Digest to Basic Authentication without
+    requiring users to be assigned new passwords.</p>
+
+    <note>
+      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.
+    </note>
+
+    <note>
+      Only providers which support Digest Authentication will be able
+      to authenticate users when <directive
+      module="mod_auth_basic">AuthBasicUseDigestAlgorithm</directive>
+      is set to <code>MD5</code>.  Use of other providers will result
+      in an error response and the client will be denied access.
+    </note>
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>

Modified: httpd/httpd/trunk/modules/aaa/mod_auth_basic.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_auth_basic.c?rev=1514064&r1=1514063&r2=1514064&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_auth_basic.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_auth_basic.c Wed Aug 14 21:57:21 2013
@@ -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
             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_pa
     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(reque
     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(reque
         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(reque
             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);