From: Henrik Nordstrom Date: Fri, 21 Feb 2014 02:19:52 +0000 (-0700) Subject: Bug 3186, Bug 3628: Digest authentication always sending stale=false for nonce X-Git-Tag: SQUID_3_5_0_1~355 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=572d2e31eb73a7db23f4b00f14ac45bc2667ac29;p=thirdparty%2Fsquid.git Bug 3186, Bug 3628: Digest authentication always sending stale=false for nonce --- diff --git a/src/auth/digest/User.cc b/src/auth/digest/User.cc index ecb2b19888..8926a08bc9 100644 --- a/src/auth/digest/User.cc +++ b/src/auth/digest/User.cc @@ -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(link->data); + if (authDigestNonceIsStale(nonce)) + nonce = NULL; + } + return nonce; +} diff --git a/src/auth/digest/User.h b/src/auth/digest/User.h index 08ccae847d..8d09ff302b 100644 --- a/src/auth/digest/User.h +++ b/src/auth/digest/User.h @@ -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); diff --git a/src/auth/digest/UserRequest.cc b/src/auth/digest/UserRequest.cc index 3a199f0046..3158db9958 100644 --- a/src/auth/digest/UserRequest.cc +++ b/src/auth/digest/UserRequest.cc @@ -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::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(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(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_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)); } } diff --git a/src/auth/digest/auth_digest.cc b/src/auth/digest/auth_digest.cc index 1f18af8106..2bf72436d4 100644 --- a/src/auth/digest/auth_digest.cc +++ b/src/auth/digest/auth_digest.cc @@ -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::Config::Find("digest"))->CheckNonceCount) { - ++nonce->nc; - return -1; /* forced OK by configuration */ + /* Ignore client supplied NC */ + intnc = nonce->nc + 1; } if ((static_cast(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::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_user_request.getRaw()); - assert (digest_request != NULL); + Auth::Digest::User *digest_user = dynamic_cast(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; diff --git a/src/auth/digest/auth_digest.h b/src/auth/digest/auth_digest.h index 386109a3a1..262935bea4 100644 --- a/src/auth/digest/auth_digest.h +++ b/src/auth/digest/auth_digest.h @@ -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 {