]> 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>
Fri, 21 Feb 2014 02:19:52 +0000 (19:19 -0700)
committerAmos Jeffries <squid3@treenet.co.nz>
Fri, 21 Feb 2014 02:19:52 +0000 (19:19 -0700)
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 ecb2b1988891ad21727a61eb68b11e0e70fffea1..8926a08bc9305f60ff2a3dfc4ddeb2e3e303899f 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 08ccae847de4b3b706958e6352ed828c4e7df405..8d09ff302b5ab92f55573e9a3ccbf51ca87e3ce6 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 3a199f0046e05ebf4aa1e3a80f2cf5f0db6005aa..3158db9958b634a80f838c8a2b85c5b01ef9526f 100644 (file)
@@ -163,7 +163,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;
     }
@@ -190,6 +190,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;
@@ -223,8 +224,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));
     }
 }
 
@@ -249,7 +256,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 1f18af81066834690122c5d1453c13e40949bd99..2bf72436d43733b7a000a1ced1e9230e14f38471 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, "Nonce is too old. " <<
@@ -531,17 +532,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, "Sending type:" << hdrType <<
            " header: 'Digest realm=\"" << digestAuthRealm << "\", nonce=\"" <<
@@ -705,8 +712,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;
@@ -1028,14 +1035,24 @@ Auth::Digest::Config::decode(char const *proxy_auth, const char *aRequestRealm)
 
     /* 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, aRequestRealm);
+        debugs(29, 2, "Unexpected or invalid nonce received from " << username);
+        Auth::UserRequest::Pointer auth_request = authDigestLogUsername(username, digest_request, aRequestRealm);
+        auth_request->user()->credentials(Auth::Handshake);
         safe_free(username);
-        return rv;
+        return auth_request;
     }
 
     digest_request->nonce = nonce;
index 386109a3a19cb85e43389db6ce447109936f81cb..262935bea48424cc7f7196811a897e23b8ac9166 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
 {