From bba5971fe6be5f21ff39602cfe93342eb37c5745 Mon Sep 17 00:00:00 2001 From: Devesh Kumar Date: Fri, 5 Sep 2025 11:39:54 +0530 Subject: [PATCH 1/5] fix: Multiple digest auth headers not filtered by opted algorithm --- lib/authorizer/digest.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/authorizer/digest.js b/lib/authorizer/digest.js index 985cc37d9..3ada0109d 100644 --- a/lib/authorizer/digest.js +++ b/lib/authorizer/digest.js @@ -136,12 +136,17 @@ _extractField = function (string, regexp) { * there can be more than one header with the same key. So need to loop over and check each one. * * @param {VariableList} headers - + * @param {String} selectedAlgorithm - The user opted algorithm (MD5, SHA-256 etc) * @private */ -function _getDigestAuthHeader (headers) { +function _getDigestAuthHeader (headers, selectedAlgorithm) { return headers.find(function (property) { return (property.key.toLowerCase() === WWW_AUTHENTICATE) && - (_.startsWith(String(property.value).toLowerCase(), DIGEST_PREFIX.toLowerCase())); + (_.startsWith(String(property.value).toLowerCase(), DIGEST_PREFIX.toLowerCase())) && + (selectedAlgorithm ? + String(property.value).toLowerCase().includes(`algorithm=${selectedAlgorithm.toLowerCase()}`) : + // If no algorithm is selected, fall back to the first default one + true); }); } @@ -314,6 +319,7 @@ module.exports = { var code, nonceCount, + algorithm, realm, nonce, qop, @@ -323,7 +329,9 @@ module.exports = { code = response.code; nonceCount = auth.get('nonceCount'); - authHeader = _getDigestAuthHeader(response.headers); + algorithm = auth.get('algorithm'); + + authHeader = _getDigestAuthHeader(response.headers, algorithm); // If code is forbidden or unauthorized, and an auth header exists, // we can extract the realm & the nonce, and replay the request. From 6d3b8f8909190d6294fecd155e42423bd4746e9e Mon Sep 17 00:00:00 2001 From: Devesh Kumar Date: Fri, 5 Sep 2025 11:56:29 +0530 Subject: [PATCH 2/5] Update header resolution logic to account for lack of algorithm value in header --- lib/authorizer/digest.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/authorizer/digest.js b/lib/authorizer/digest.js index 3ada0109d..ca0040e3d 100644 --- a/lib/authorizer/digest.js +++ b/lib/authorizer/digest.js @@ -140,14 +140,27 @@ _extractField = function (string, regexp) { * @private */ function _getDigestAuthHeader (headers, selectedAlgorithm) { - return headers.find(function (property) { + const digestAuthHeaders = headers.filter(function (property) { return (property.key.toLowerCase() === WWW_AUTHENTICATE) && - (_.startsWith(String(property.value).toLowerCase(), DIGEST_PREFIX.toLowerCase())) && - (selectedAlgorithm ? - String(property.value).toLowerCase().includes(`algorithm=${selectedAlgorithm.toLowerCase()}`) : - // If no algorithm is selected, fall back to the first default one - true); + (_.startsWith(String(property.value).toLowerCase(), DIGEST_PREFIX.toLowerCase())); }); + + if (selectedAlgorithm) { + const headerWithMatchingOptedAlgorithm = digestAuthHeaders.find(function (header) { + const headerValue = String(header.value).toLowerCase(); + + if (!headerValue.includes('algorithm=')) { + // This is an MD5 header. Ref: https://datatracker.ietf.org/doc/html/rfc7616 + return selectedAlgorithm.toLowerCase() === 'md5'; + } + + return headerValue.includes(`algorithm=${selectedAlgorithm.toLowerCase()}`); + }); + + return headerWithMatchingOptedAlgorithm; + } + + return digestAuthHeaders.length ? digestAuthHeaders[0] : null; } /** From cbcf48871ae17de5d96c8f9e326b4217f78ce3ce Mon Sep 17 00:00:00 2001 From: Devesh Kumar Date: Fri, 5 Sep 2025 12:01:38 +0530 Subject: [PATCH 3/5] tests: Preserve existing behaviour if opted algorithm isn't found --- lib/authorizer/digest.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/authorizer/digest.js b/lib/authorizer/digest.js index ca0040e3d..dbc9eb795 100644 --- a/lib/authorizer/digest.js +++ b/lib/authorizer/digest.js @@ -157,7 +157,9 @@ function _getDigestAuthHeader (headers, selectedAlgorithm) { return headerValue.includes(`algorithm=${selectedAlgorithm.toLowerCase()}`); }); - return headerWithMatchingOptedAlgorithm; + if (headerWithMatchingOptedAlgorithm) { + return headerWithMatchingOptedAlgorithm; + } } return digestAuthHeaders.length ? digestAuthHeaders[0] : null; From 90b1a3375fd97f32fab3ea2bab3a936a347daa21 Mon Sep 17 00:00:00 2001 From: Devesh Kumar Date: Mon, 8 Sep 2025 00:11:05 +0530 Subject: [PATCH 4/5] refactor: Update header matching return logic --- lib/authorizer/digest.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/authorizer/digest.js b/lib/authorizer/digest.js index dbc9eb795..cd0fa6518 100644 --- a/lib/authorizer/digest.js +++ b/lib/authorizer/digest.js @@ -145,24 +145,24 @@ function _getDigestAuthHeader (headers, selectedAlgorithm) { (_.startsWith(String(property.value).toLowerCase(), DIGEST_PREFIX.toLowerCase())); }); + let headerWithMatchingOptedAlgorithm; + if (selectedAlgorithm) { - const headerWithMatchingOptedAlgorithm = digestAuthHeaders.find(function (header) { + const targetAlgorithm = selectedAlgorithm.toLowerCase(); + + headerWithMatchingOptedAlgorithm = digestAuthHeaders.find(function (header) { const headerValue = String(header.value).toLowerCase(); if (!headerValue.includes('algorithm=')) { // This is an MD5 header. Ref: https://datatracker.ietf.org/doc/html/rfc7616 - return selectedAlgorithm.toLowerCase() === 'md5'; + return targetAlgorithm === 'md5'; } - return headerValue.includes(`algorithm=${selectedAlgorithm.toLowerCase()}`); + return headerValue.includes(`algorithm=${targetAlgorithm}`); }); - - if (headerWithMatchingOptedAlgorithm) { - return headerWithMatchingOptedAlgorithm; - } } - return digestAuthHeaders.length ? digestAuthHeaders[0] : null; + return headerWithMatchingOptedAlgorithm || digestAuthHeaders[0]; } /** From 439e2e2c072e666b0f68dc00bcab7a5582e46cd5 Mon Sep 17 00:00:00 2001 From: Appurva Murawat Date: Mon, 8 Sep 2025 17:29:18 +0530 Subject: [PATCH 5/5] chore: add changelog --- CHANGELOG.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index 53d141676..b07dd64b8 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -3,6 +3,7 @@ unreleased: - GH-1522 Add support for referencing pre-defined collection requests using `pm.execution.runRequest` fixed bugs: - GH-1523 Fixed downloadedBytes tracking for redirected requests + - GH-1524 Fixed a bug where incorrect digest auth header was getting used to compute hash. chores: - Updated dependencies