You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rj...@apache.org on 2013/10/03 20:22:49 UTC

svn commit: r1528957 - in /httpd/httpd/branches/2.4.x: ./ CHANGES STATUS docs/manual/ docs/manual/mod/ docs/manual/mod/mod_auth_basic.xml modules/aaa/mod_auth_basic.c

Author: rjung
Date: Thu Oct  3 18:22:48 2013
New Revision: 1528957

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

Proposed by: chrisd
Reviewed by: jim, rjung

Backport of r1514064 from trunk.

Modified:
    httpd/httpd/branches/2.4.x/   (props changed)
    httpd/httpd/branches/2.4.x/CHANGES
    httpd/httpd/branches/2.4.x/STATUS
    httpd/httpd/branches/2.4.x/docs/manual/   (props changed)
    httpd/httpd/branches/2.4.x/docs/manual/mod/   (props changed)
    httpd/httpd/branches/2.4.x/docs/manual/mod/mod_auth_basic.xml
    httpd/httpd/branches/2.4.x/modules/aaa/mod_auth_basic.c

Propchange: httpd/httpd/branches/2.4.x/
------------------------------------------------------------------------------
  Merged /httpd/httpd/trunk:r1514064

Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1528957&r1=1528956&r2=1528957&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Thu Oct  3 18:22:48 2013
@@ -2,6 +2,10 @@
 
 Changes with Apache 2.4.7
 
+  *) mod_auth_basic: Add AuthBasicUseDigestAlgorithm directive to
+     allow migration of passwords from digest to basic authentication.
+     [Chris Darroch]
+
   *) ab: Add a new -l parameter in order not to check the length of the responses.
      This can be usefull with dynamic pages.
      PR9945, PR27888, PR42040 [<ccikrs1 cranbrook edu>]

Modified: httpd/httpd/branches/2.4.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/STATUS?rev=1528957&r1=1528956&r2=1528957&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/STATUS (original)
+++ httpd/httpd/branches/2.4.x/STATUS Thu Oct  3 18:22:48 2013
@@ -97,13 +97,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  * mod_auth_basic: Add AuthBasicUseDigestAlgorithm directive to allow
-    migration of passwords from digest to basic authentication.
-    trunk patch: http://svn.apache.org/viewvc?view=revision&revision=1514064
-    2.4.x patch: trunk patch works, modulo CHANGES, next-number, and
-                 doc compatibility version note
-    +1: chrisd, jim, rjung
-
   * core: name-based vhosts printed twice in apachectl -S since
     dropping NameVirtualHost directive.
     trunk patch: http://svn.apache.org/r1485675 , http://svn.apache.org/r1525000

Propchange: httpd/httpd/branches/2.4.x/docs/manual/
------------------------------------------------------------------------------
  Merged /httpd/httpd/trunk/docs/manual:r1514064

Propchange: httpd/httpd/branches/2.4.x/docs/manual/mod/
------------------------------------------------------------------------------
  Merged /httpd/httpd/trunk/docs/manual/mod:r1514064

Modified: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_auth_basic.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/mod/mod_auth_basic.xml?rev=1528957&r1=1528956&r2=1528957&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/docs/manual/mod/mod_auth_basic.xml (original)
+++ httpd/httpd/branches/2.4.x/docs/manual/mod/mod_auth_basic.xml Thu Oct  3 18:22:48 2013
@@ -181,4 +181,80 @@ 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>
+<compatibility>Apache HTTP Server 2.4.7 and later</compatibility>
+
+<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/branches/2.4.x/modules/aaa/mod_auth_basic.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/aaa/mod_auth_basic.c?rev=1528957&r1=1528956&r2=1528957&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/aaa/mod_auth_basic.c (original)
+++ httpd/httpd/branches/2.4.x/modules/aaa/mod_auth_basic.c Thu Oct  3 18:22:48 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);