------------------------------------------------------------ revno: 13727 revision-id: squid3@treenet.co.nz-20150118042451-bdsb3imuettire14 parent: squid3@treenet.co.nz-20150118042058-627ovv02n28qan8h fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=3997 author: Amos Jeffries , Steve Hill committer: Amos Jeffries branch nick: 3.5 timestamp: Sat 2015-01-17 20:24:51 -0800 message: Bug 3997: Excessive NTLM or Negotiate auth helper annotations With the transaction annotations feature added in Squid-3.4 auth helper response values get recorded as annotatiions. In the case of NTLM and Negotiate authentication the helper response contains a large credentials token which changes frequently. Also, user credentials state is cached. In the case of NTLM and Negotiate the active credentials are cached in the TCP connection state data, but also for the cache mgr helper reports make use of caching in a global username cache. When these two features are combined, the global username cache for mgr reporting accumulates all TCP connection specific token= values presented by the client on all its connections, and any changes to the token over its lifetime. The result is that for users performing either many transactions, or staying connected for long periods the memory consumption from unnecesarily stored tokens is excessive. When clients do both the machine memory can be consumed, and the CPU can reach 100% consumption just walking the annotations lists during regular operations. To fix this we drop the security credentials tokens from cached annotations list in NTLM and Negotiate. Digest is also included though its HA1 token value is static it has similar privacy issues related to storage. Also, use the new 3.5 API for username cache key creation to build the global username cache key for NTLM/Negotiate using the TCP connection specific token so that credentials and associated tokens do not get accidentally shared between connections and the manager can accurately report users. ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20150118042451-bdsb3imuettire14 # target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5 # testament_sha1: 00d63f5b44940cdd6248a8b387b5f4b68f0ca72b # timestamp: 2015-01-18 04:27:35 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5 # base_revision_id: squid3@treenet.co.nz-20150118042058-\ # 627ovv02n28qan8h # # Begin patch === modified file 'src/auth/digest/UserRequest.cc' --- src/auth/digest/UserRequest.cc 2015-01-13 09:13:49 +0000 +++ src/auth/digest/UserRequest.cc 2015-01-18 04:24:51 +0000 @@ -329,6 +329,8 @@ // add new helper kv-pair notes to the credentials object // so that any transaction using those credentials can access them auth_user_request->user()->notes.appendNewOnly(&reply.notes); + // remove any private credentials detail which got added. + auth_user_request->user()->notes.remove("ha1"); static bool oldHelperWarningDone = false; switch (reply.result) { === modified file 'src/auth/negotiate/Config.cc' --- src/auth/negotiate/Config.cc 2015-01-13 09:13:49 +0000 +++ src/auth/negotiate/Config.cc 2015-01-18 04:24:51 +0000 @@ -261,6 +261,8 @@ auth_user_request->user(newUser); auth_user_request->user()->auth_type = Auth::AUTH_NEGOTIATE; + auth_user_request->user()->BuildUserKey(proxy_auth, aRequestRealm); + /* all we have to do is identify that it's Negotiate - the helper does the rest */ debugs(29, 9, HERE << "decode Negotiate authentication"); return auth_user_request; === modified file 'src/auth/negotiate/UserRequest.cc' --- src/auth/negotiate/UserRequest.cc 2015-01-13 09:13:49 +0000 +++ src/auth/negotiate/UserRequest.cc 2015-01-18 04:24:51 +0000 @@ -260,6 +260,8 @@ // add new helper kv-pair notes to the credentials object // so that any transaction using those credentials can access them auth_user_request->user()->notes.appendNewOnly(&reply.notes); + // remove any private credentials detail which got added. + auth_user_request->user()->notes.remove("token"); Auth::Negotiate::UserRequest *lm_request = dynamic_cast(auth_user_request.getRaw()); assert(lm_request != NULL); @@ -312,8 +314,7 @@ /* connection is authenticated */ debugs(29, 4, HERE << "authenticated user " << auth_user_request->user()->username()); - /* see if this is an existing user with a different proxy_auth - * string */ + /* see if this is an existing user */ AuthUserHashPointer *usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->userKey())); Auth::User::Pointer local_auth_user = lm_request->user(); while (usernamehash && (usernamehash->user()->auth_type != Auth::AUTH_NEGOTIATE || === modified file 'src/auth/ntlm/Config.cc' --- src/auth/ntlm/Config.cc 2015-01-13 09:13:49 +0000 +++ src/auth/ntlm/Config.cc 2015-01-18 04:24:51 +0000 @@ -241,6 +241,8 @@ auth_user_request->user(newUser); auth_user_request->user()->auth_type = Auth::AUTH_NTLM; + auth_user_request->user()->BuildUserKey(proxy_auth, aRequestRealm); + /* all we have to do is identify that it's NTLM - the helper does the rest */ debugs(29, 9, HERE << "decode: NTLM authentication"); return auth_user_request; === modified file 'src/auth/ntlm/UserRequest.cc' --- src/auth/ntlm/UserRequest.cc 2015-01-13 09:13:49 +0000 +++ src/auth/ntlm/UserRequest.cc 2015-01-18 04:24:51 +0000 @@ -255,6 +255,8 @@ // add new helper kv-pair notes to the credentials object // so that any transaction using those credentials can access them auth_user_request->user()->notes.appendNewOnly(&reply.notes); + // remove any private credentials detail which got added. + auth_user_request->user()->notes.remove("token"); Auth::Ntlm::UserRequest *lm_request = dynamic_cast(auth_user_request.getRaw()); assert(lm_request != NULL); @@ -306,8 +308,7 @@ debugs(29, 4, HERE << "Successfully validated user via NTLM. Username '" << userLabel << "'"); /* connection is authenticated */ debugs(29, 4, HERE << "authenticated user " << auth_user_request->user()->username()); - /* see if this is an existing user with a different proxy_auth - * string */ + /* see if this is an existing user */ AuthUserHashPointer *usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->userKey())); Auth::User::Pointer local_auth_user = lm_request->user(); while (usernamehash && (usernamehash->user()->auth_type != Auth::AUTH_NTLM ||