From c69199bb22ce6d16080bc84c613823830c22c0d3 Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Fri, 9 Nov 2012 17:23:08 +1300 Subject: [PATCH] Upgrade Digest authentication to use key=value parameters * Update the Digest auth code in Squid to process the HelperReply key-pair notes list for data + output upgrade WARNING messages when old format responses are identified + handle TT result code (as an error with critical level ERROR message) + handle BH result code (as an error) * Adds a ha1="" key to Digest auth response protocol to pass the HA1. * Upgrade the Digest helpers to use OK/ERR/BH result codes and key=value parameters. --- helpers/digest_auth/LDAP/digest_pw_auth.cc | 6 +- .../digest_auth/eDirectory/digest_pw_auth.cc | 6 +- helpers/digest_auth/file/digest_file_auth.cc | 8 +-- src/auth/digest/UserRequest.cc | 62 +++++++++++++++---- 4 files changed, 58 insertions(+), 24 deletions(-) diff --git a/helpers/digest_auth/LDAP/digest_pw_auth.cc b/helpers/digest_auth/LDAP/digest_pw_auth.cc index ebf6ea1c4e..0dd29c9ddc 100644 --- a/helpers/digest_auth/LDAP/digest_pw_auth.cc +++ b/helpers/digest_auth/LDAP/digest_pw_auth.cc @@ -64,10 +64,10 @@ OutputHHA1(RequestData * requestData) requestData->error = 0; GetHHA1(requestData); if (requestData->error) { - SEND_ERR("No such user"); + SEND_ERR("message=\"No such user\""); return; } - printf("%s\n", requestData->HHA1); + printf("OK ha1=\"%s\"\n", requestData->HHA1); } static void @@ -76,7 +76,7 @@ DoOneRequest(char *buf) RequestData requestData; ParseBuffer(buf, &requestData); if (!requestData.parsed) { - SEND_ERR(""); + SEND_BH("message=\"Invalid line received\""); return; } OutputHHA1(&requestData); diff --git a/helpers/digest_auth/eDirectory/digest_pw_auth.cc b/helpers/digest_auth/eDirectory/digest_pw_auth.cc index 6087df6cfd..2640ac8dba 100644 --- a/helpers/digest_auth/eDirectory/digest_pw_auth.cc +++ b/helpers/digest_auth/eDirectory/digest_pw_auth.cc @@ -64,10 +64,10 @@ OutputHHA1(RequestData * requestData) requestData->error = 0; GetHHA1(requestData); if (requestData->error) { - SEND_ERR("No such user"); + SEND_ERR("message=\"No such user\""); return; } - printf("%s\n", requestData->HHA1); + printf("OK ha1=\"%s\"\n", requestData->HHA1); } static void @@ -76,7 +76,7 @@ DoOneRequest(char *buf) RequestData requestData; ParseBuffer(buf, &requestData); if (!requestData.parsed) { - SEND_ERR(""); + SEND_BH("message=\"Invalid line received\""); return; } OutputHHA1(&requestData); diff --git a/helpers/digest_auth/file/digest_file_auth.cc b/helpers/digest_auth/file/digest_file_auth.cc index b0ed8be907..0839ffe32e 100644 --- a/helpers/digest_auth/file/digest_file_auth.cc +++ b/helpers/digest_auth/file/digest_file_auth.cc @@ -38,8 +38,6 @@ #include "helpers/defines.h" #include "text_backend.h" -#define PROGRAM_NAME "digest_file_auth" - static void GetHHA1(RequestData * requestData) { @@ -68,10 +66,10 @@ OutputHHA1(RequestData * requestData) requestData->error = 0; GetHHA1(requestData); if (requestData->error) { - SEND_ERR("No such user"); + SEND_ERR("message=\"No such user\""); return; } - printf("%s\n", requestData->HHA1); + printf("OK ha1=\"%s\"\n", requestData->HHA1); } static void @@ -80,7 +78,7 @@ DoOneRequest(char *buf) RequestData requestData; ParseBuffer(buf, &requestData); if (!requestData.parsed) { - SEND_ERR(""); + SEND_BH("message=\"Invalid line received\""); return; } OutputHHA1(&requestData); diff --git a/src/auth/digest/UserRequest.cc b/src/auth/digest/UserRequest.cc index cd23866967..ea4c3e2df3 100644 --- a/src/auth/digest/UserRequest.cc +++ b/src/auth/digest/UserRequest.cc @@ -280,33 +280,69 @@ Auth::Digest::UserRequest::HandleReply(void *data, const HelperReply &reply) assert(replyData->auth_user_request != NULL); Auth::UserRequest::Pointer auth_user_request = replyData->auth_user_request; + static bool oldHelperWarningDone = false; switch (reply.result) { - case HelperReply::Error: { - /* allow this because the digest_request pointer is purely local */ - Auth::Digest::UserRequest *digest_request = dynamic_cast(auth_user_request.getRaw()); - assert(digest_request); + case HelperReply::Unknown: { + // Squid 3.3 and older the digest helper only returns a HA1 hash (no "OK") + // the HA1 will be found in content() for these responses. + if (!oldHelperWarningDone) { + debugs(29, DBG_IMPORTANT, "WARNING: Digest auth helper returned old format HA1 response. It needs to be upgraded."); + oldHelperWarningDone=true; + } - digest_request->user()->credentials(Auth::Failed); - digest_request->flags.invalid_password = 1; + /* allow this because the digest_request pointer is purely local */ + Auth::Digest::User *digest_user = dynamic_cast(auth_user_request->user().getRaw()); + assert(digest_user != NULL); - if (reply.other().hasContent()) - digest_request->setDenyMessage(reply.other().content()); + CvtBin(reply.other().content(), digest_user->HA1); + digest_user->HA1created = 1; } break; - case HelperReply::Unknown: // Squid 3.2 and older the digest helper only returns a HA1 hash (no "OK") case HelperReply::Okay: { /* allow this because the digest_request pointer is purely local */ Auth::Digest::User *digest_user = dynamic_cast(auth_user_request->user().getRaw()); assert(digest_user != NULL); - CvtBin(reply.other().content(), digest_user->HA1); - digest_user->HA1created = 1; + Note::Pointer ha1Note = reply.responseKeys.findByName("ha1"); + if (ha1Note != NULL) { + CvtBin(ha1Note->values[0]->value.termedBuf(), digest_user->HA1); + digest_user->HA1created = 1; + } else { + debugs(29, DBG_IMPORTANT, "ERROR: Digest auth helper did not produce a HA1. Using the wrong helper program? received: " << reply); + } } break; - default: - ; // XXX: handle other states properly. + case HelperReply::TT: + debugs(29, DBG_IMPORTANT, "ERROR: Digest auth does not support the result code received. Using the wrong helper program? received: " << reply); + // fall through to next case. Handle this as an ERR response. + + case HelperReply::BrokenHelper: + // TODO retry the broken lookup on another helper? + // fall through to next case for now. Handle this as an ERR response silently. + + case HelperReply::Error: { + /* allow this because the digest_request pointer is purely local */ + Auth::Digest::UserRequest *digest_request = dynamic_cast(auth_user_request.getRaw()); + assert(digest_request); + + digest_request->user()->credentials(Auth::Failed); + digest_request->flags.invalid_password = 1; + + Note::Pointer msgNote = reply.responseKeys.findByName("message"); + if (msgNote != NULL) { + digest_request->setDenyMessage(msgNote->values[0]->value.termedBuf()); + } else if (reply.other().hasContent()) { + // old helpers did send ERR result but a bare message string instead of message= key name. + digest_request->setDenyMessage(reply.other().content()); + if (!oldHelperWarningDone) { + debugs(29, DBG_IMPORTANT, "WARNING: Digest auth helper returned old format ERR response. It needs to be upgraded."); + oldHelperWarningDone=true; + } + } + } + break; } void *cbdata = NULL; -- 2.47.3