]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 3186, Bug 3628: Digest authentication always sending stale=false for nonce
authorHenrik Nordstrom <hno@squid-cache.org>
Wed, 5 Mar 2014 02:48:25 +0000 (19:48 -0700)
committerAmos Jeffries <squid3@treenet.co.nz>
Wed, 5 Mar 2014 02:48:25 +0000 (19:48 -0700)
src/auth/UserRequest.cc
src/auth/digest/User.cc
src/auth/digest/User.h
src/auth/digest/UserRequest.cc
src/auth/digest/auth_digest.cc
src/auth/digest/auth_digest.h

index b2a61995f4d65804fb28a871af5138fb094b2bfb..dca283ff58a66ffc1049cb1b6e10f89da90bfd2a 100644 (file)
@@ -523,9 +523,12 @@ Auth::UserRequest::addReplyAuthHeader(HttpReply * rep, Auth::UserRequest::Pointe
             for (Auth::ConfigVector::iterator  i = Auth::TheConfig.begin(); i != Auth::TheConfig.end(); ++i) {
                 Auth::Config *scheme = *i;
 
-                if (scheme->active())
-                    scheme->fixHeader(NULL, rep, type, request);
-                else
+                if (scheme->active()) {
+                    if (auth_user_request != NULL && auth_user_request->scheme()->type() == scheme->type())
+                        scheme->fixHeader(auth_user_request, rep, type, request);
+                    else
+                        scheme->fixHeader(NULL, rep, type, request);
+                } else
                     debugs(29, 4, HERE << "Configured scheme " << scheme->type() << " not Active");
             }
         }
index 1cf7dd0ba51b5df061ee5569484e093b84bf916b..c54080ccc115d75ef2d0a9a7857c0124a2c9bca7 100644 (file)
@@ -50,3 +50,16 @@ Auth::Digest::User::ttl() const
 
     return min(nonce_ttl, global_ttl);
 }
+
+digest_nonce_h *
+Auth::Digest::User::currentNonce()
+{
+    digest_nonce_h *nonce = NULL;
+    dlink_node *link = nonces.tail;
+    if (link) {
+        nonce = static_cast<digest_nonce_h *>(link->data);
+        if (authDigestNonceIsStale(nonce))
+            nonce = NULL;
+    }
+    return nonce;
+}
index 2e86534d0ff6e56e15f5f863b70148124996ea72..a660b706823b682348dd11b72b23655ffb63b2e8 100644 (file)
@@ -25,6 +25,8 @@ public:
 
     /* what nonces have been allocated to this user */
     dlink_list nonces;
+
+    digest_nonce_h * currentNonce();
 };
 
 MEMPROXY_CLASS_INLINE(Auth::Digest::User);
index 161161f8065f72726f1d46dfddffe73e84b11a04..f625bd864842b770be1ffc1c6c3d0edc451f6283 100644 (file)
@@ -154,7 +154,7 @@ Auth::Digest::UserRequest::authenticate(HttpRequest * request, ConnStateData * c
     /* check for stale nonce */
     if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) {
         debugs(29, 3, "user '" << auth_user->username() << "' validated OK but nonce stale");
-        auth_user->credentials(Auth::Failed);
+        auth_user->credentials(Auth::Handshake);
         digest_request->setDenyMessage("Stale nonce");
         return;
     }
@@ -181,6 +181,7 @@ Auth::Digest::UserRequest::module_direction()
     case Auth::Ok:
         return Auth::CRED_VALID;
 
+    case Auth::Handshake:
     case Auth::Failed:
         /* send new challenge */
         return Auth::CRED_CHALLENGE;
@@ -214,8 +215,14 @@ Auth::Digest::UserRequest::addAuthenticationInfoHeader(HttpReply * rep, int acce
 
     if ((static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->authenticateProgram) && authDigestNonceLastRequest(nonce)) {
         flags.authinfo_sent = true;
-        debugs(29, 9, HERE << "Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
-        httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
+        Auth::Digest::User *digest_user = dynamic_cast<Auth::Digest::User *>(user().getRaw());
+        digest_nonce_h *nextnonce = digest_user->currentNonce();
+        if (!nextnonce || authDigestNonceLastRequest(nonce)) {
+            nextnonce = authenticateDigestNonceNew();
+            authDigestUserLinkNonce(digest_user, nextnonce);
+        }
+        debugs(29, 9, "Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nextnonce) << "\"");
+        httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nextnonce));
     }
 }
 
@@ -240,7 +247,13 @@ Auth::Digest::UserRequest::addAuthenticationInfoTrailer(HttpReply * rep, int acc
     type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
 
     if ((static_cast<Auth::Digest::Config*>(digestScheme::GetInstance()->getConfig())->authenticate) && authDigestNonceLastRequest(nonce)) {
-        debugs(29, 9, HERE << "Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
+        Auth::Digest::User *digest_user = dynamic_cast<Auth::Digest::User *>(auth_user_request->user().getRaw());
+        nonce = digest_user->currentNonce();
+        if (!nonce) {
+            nonce = authenticateDigestNonceNew();
+            authDigestUserLinkNonce(digest_user, nonce);
+        }
+        debugs(29, 9, "Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
         httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
     }
 }
index 60abc1f83120b106e08b6ff0c39690eeec17e8e5..7cc32766d77f322d278f9aa96e6393768321d3e3 100644 (file)
@@ -102,10 +102,8 @@ static HttpHeaderFieldInfo *DigestFieldsInfo = NULL;
 
 static void authenticateDigestNonceCacheCleanup(void *data);
 static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64);
-static digest_nonce_h *authenticateDigestNonceNew(void);
 static void authenticateDigestNonceDelete(digest_nonce_h * nonce);
 static void authenticateDigestNonceSetup(void);
-static int authDigestNonceIsStale(digest_nonce_h * nonce);
 static void authDigestNonceEncode(digest_nonce_h * nonce);
 static void authDigestNonceLink(digest_nonce_h * nonce);
 #if NOT_USED
@@ -125,7 +123,7 @@ authDigestNonceEncode(digest_nonce_h * nonce)
     nonce->key = xstrdup(base64_encode_bin((char *) &(nonce->noncedata), sizeof(digest_nonce_data)));
 }
 
-static digest_nonce_h *
+digest_nonce_h *
 authenticateDigestNonceNew(void)
 {
     digest_nonce_h *newnonce = static_cast < digest_nonce_h * >(digest_nonce_pool->alloc());
@@ -379,8 +377,8 @@ authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9])
 
     /* is the nonce-count ok ? */
     if (!static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->CheckNonceCount) {
-        ++nonce->nc;
-        return -1;              /* forced OK by configuration */
+        /* Ignore client supplied NC */
+        intnc = nonce->nc + 1;
     }
 
     if ((static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->NonceStrictness && intnc != nonce->nc + 1) ||
@@ -390,16 +388,15 @@ authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9])
         return 0;
     }
 
-    /* seems ok */
     /* increment the nonce count - we've already checked that intnc is a
      *  valid representation for us, so we don't need the test here.
      */
     nonce->nc = intnc;
 
-    return -1;
+    return !authDigestNonceIsStale(nonce);
 }
 
-static int
+int
 authDigestNonceIsStale(digest_nonce_h * nonce)
 {
     /* do we have a nonce ? */
@@ -407,6 +404,10 @@ authDigestNonceIsStale(digest_nonce_h * nonce)
     if (!nonce)
         return -1;
 
+    /* Is it already invalidated? */
+    if (!nonce->flags.valid)
+        return -1;
+
     /* has it's max duration expired? */
     if (nonce->noncedata.creationtime + static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->noncemaxduration < current_time.tv_sec) {
         debugs(29, 4, "authDigestNonceIsStale: Nonce is too old. " <<
@@ -530,17 +531,23 @@ Auth::Digest::Config::fixHeader(Auth::UserRequest::Pointer auth_user_request, Ht
     if (!authenticateProgram)
         return;
 
-    int stale = 0;
+    bool stale = false;
+    digest_nonce_h *nonce = NULL;
 
+    /* on a 407 or 401 we always use a new nonce */
     if (auth_user_request != NULL) {
-        Auth::Digest::UserRequest *digest_request = dynamic_cast<Auth::Digest::UserRequest*>(auth_user_request.getRaw());
-        assert (digest_request != NULL);
+        Auth::Digest::User *digest_user = dynamic_cast<Auth::Digest::User *>(auth_user_request->user().getRaw());
 
-        stale = !digest_request->flags.invalid_password;
+        if (digest_user) {
+            stale = digest_user->credentials() == Auth::Handshake;
+            if (stale) {
+                nonce = digest_user->currentNonce();
+            }
+        }
+    }
+    if (!nonce) {
+        nonce = authenticateDigestNonceNew();
     }
-
-    /* on a 407 or 401 we always use a new nonce */
-    digest_nonce_h *nonce = authenticateDigestNonceNew();
 
     debugs(29, 9, HERE << "Sending type:" << hdrType <<
            " header: 'Digest realm=\"" << digestAuthRealm << "\", nonce=\"" <<
@@ -703,8 +710,8 @@ authDigestNonceUserUnlink(digest_nonce_h * nonce)
     nonce->user = NULL;
 }
 
-/* authDigestUserLinkNonce: add a nonce to a given user's struct */
-static void
+/* authDigesteserLinkNonce: add a nonce to a given user's struct */
+void
 authDigestUserLinkNonce(Auth::Digest::User * user, digest_nonce_h * nonce)
 {
     dlink_node *node;
@@ -1026,14 +1033,24 @@ Auth::Digest::Config::decode(char const *proxy_auth)
 
     /* now the nonce */
     nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
+    /* check that we're not being hacked / the username hasn't changed */
+    if (nonce && nonce->user && strcmp(username, nonce->user->username())) {
+        debugs(29, 2, "Username for the nonce does not equal the username for the request");
+        nonce = NULL;
+    }
+    /* check for stale nonce */
+    if (authDigestNonceIsStale(nonce)) {
+        debugs(29, 3, "The received nonce is stale from " << username);
+        digest_request->setDenyMessage("Stale nonce");
+        nonce = NULL;
+    }
     if (!nonce) {
         /* we couldn't find a matching nonce! */
-        debugs(29, 2, "Unexpected or invalid nonce received");
-        if (digest_request->user() != NULL)
-            digest_request->user()->credentials(Auth::Failed);
-        rv = authDigestLogUsername(username, digest_request);
+        debugs(29, 2, "Unexpected or invalid nonce received from " << username);
+        Auth::UserRequest::Pointer auth_request = authDigestLogUsername(username, digest_request);
+        auth_request->user()->credentials(Auth::Handshake);
         safe_free(username);
-        return rv;
+        return auth_request;
     }
 
     digest_request->nonce = nonce;
index 1b3892d61854669eb328f762ead6f1ce21b0b6a1..21dbf99649c1a12720707e516d6b2e0c2f422ce4 100644 (file)
@@ -52,10 +52,13 @@ struct _digest_nonce_h : public hash_link {
 
 void authDigestNonceUnlink(digest_nonce_h * nonce);
 int authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]);
+int authDigestNonceIsStale(digest_nonce_h * nonce);
 const char *authenticateDigestNonceNonceb64(const digest_nonce_h * nonce);
 int authDigestNonceLastRequest(digest_nonce_h * nonce);
 void authenticateDigestNonceShutdown(void);
 void authDigestNoncePurge(digest_nonce_h * nonce);
+void authDigestUserLinkNonce(Auth::Digest::User * user, digest_nonce_h * nonce);
+digest_nonce_h *authenticateDigestNonceNew(void);
 
 namespace Auth
 {