From 57a85e535cde95bb0f33a0bf424424af889532b8 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Wed, 18 Dec 2024 19:03:19 +0530 Subject: [PATCH 1/6] fix: add lodash import for utility functions --- packages/bruno-app/src/utils/importers/common.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/bruno-app/src/utils/importers/common.js b/packages/bruno-app/src/utils/importers/common.js index c99048419..f9f594255 100644 --- a/packages/bruno-app/src/utils/importers/common.js +++ b/packages/bruno-app/src/utils/importers/common.js @@ -1,5 +1,6 @@ import each from 'lodash/each'; import get from 'lodash/get'; +import _ from 'lodash'; import cloneDeep from 'lodash/cloneDeep'; import { uuid, normalizeFileName } from 'utils/common'; From 26daee5d981043bcdb7e08572b22a2bbb1af9660 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Tue, 24 Dec 2024 15:37:59 +0530 Subject: [PATCH 2/6] fix: improve parsing of authentication details in digest interceptor --- .../src/ipc/network/digestauth-helper.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/bruno-electron/src/ipc/network/digestauth-helper.js b/packages/bruno-electron/src/ipc/network/digestauth-helper.js index 67f738db5..625d40c56 100644 --- a/packages/bruno-electron/src/ipc/network/digestauth-helper.js +++ b/packages/bruno-electron/src/ipc/network/digestauth-helper.js @@ -45,9 +45,15 @@ function addDigestInterceptor(axiosInstance, request) { console.debug(error.response.headers['www-authenticate']); const authDetails = error.response.headers['www-authenticate'] - .split(', ') - .map((v) => v.split('=').map(stripQuotes)) - .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}); + .split(',') + .map((pair) => pair.split('=').map((item) => item.trim()).map(stripQuotes)) + .reduce((acc, [key, value]) => { + if (key && value !== undefined) { + acc[key] = value; + } + return acc; + }, {}); + console.debug(authDetails); const nonceCount = '00000001'; From 284519cd437d9d6f8cca1f052de7667ddb3d7e95 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Thu, 26 Dec 2024 07:51:55 +0530 Subject: [PATCH 3/6] fix: improve digest authorization header `opaque` --- .../src/ipc/network/digestauth-helper.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/bruno-electron/src/ipc/network/digestauth-helper.js b/packages/bruno-electron/src/ipc/network/digestauth-helper.js index 625d40c56..b1dbf7c7b 100644 --- a/packages/bruno-electron/src/ipc/network/digestauth-helper.js +++ b/packages/bruno-electron/src/ipc/network/digestauth-helper.js @@ -24,7 +24,6 @@ function md5(input) { function addDigestInterceptor(axiosInstance, request) { const { username, password } = request.digestConfig; - console.debug(request); if (!isStrPresent(username) || !isStrPresent(password)) { @@ -54,30 +53,36 @@ function addDigestInterceptor(axiosInstance, request) { return acc; }, {}); - console.debug(authDetails); + console.debug("Auth Details: \n", authDetails); const nonceCount = '00000001'; const cnonce = crypto.randomBytes(24).toString('hex'); if (authDetails.algorithm && authDetails.algorithm.toUpperCase() !== 'MD5') { - console.warn(`Unsupported Digest algorithm: ${algo}`); + console.warn(`Unsupported Digest algorithm: ${authDetails.algorithm}`); return Promise.reject(error); } else { authDetails.algorithm = 'MD5'; } + const uri = new URL(request.url).pathname; const HA1 = md5(`${username}:${authDetails['Digest realm']}:${password}`); const HA2 = md5(`${request.method}:${uri}`); - const response = md5(`${HA1}:${authDetails.nonce}:${nonceCount}:${cnonce}:auth:${HA2}`); + const response = md5( + `${HA1}:${authDetails.nonce}:${nonceCount}:${cnonce}:auth:${HA2}` + ); const authorizationHeader = - `Digest username="${username}",realm="${authDetails['Digest realm']}",` + + `Digest username="${username}",realm="${authDetails.realm}",` + `nonce="${authDetails.nonce}",uri="${uri}",qop="auth",algorithm="${authDetails.algorithm}",` + - `response="${response}",nc="${nonceCount}",cnonce="${cnonce}"`; + `response="${response}",nc="${nonceCount}",cnonce="${cnonce}"` + + (authDetails.opaque ? `,opaque="${authDetails.opaque}"` : ''); + originalRequest.headers['Authorization'] = authorizationHeader; console.debug(`Authorization: ${originalRequest.headers['Authorization']}`); delete originalRequest.digestConfig; + return axiosInstance(originalRequest); } From 625140d1f42efb5177c912558de3e5cd58242823 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Thu, 26 Dec 2024 08:10:40 +0530 Subject: [PATCH 4/6] fix: enhance digest authentication --- .../src/ipc/network/digestauth-helper.js | 58 ++++++++++++++----- .../auth/digest auth/simple digest auth.bru | 20 +++++++ 2 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru diff --git a/packages/bruno-electron/src/ipc/network/digestauth-helper.js b/packages/bruno-electron/src/ipc/network/digestauth-helper.js index b1dbf7c7b..f01ba86df 100644 --- a/packages/bruno-electron/src/ipc/network/digestauth-helper.js +++ b/packages/bruno-electron/src/ipc/network/digestauth-helper.js @@ -2,7 +2,7 @@ const crypto = require('crypto'); const { URL } = require('url'); function isStrPresent(str) { - return str && str !== '' && str !== 'undefined'; + return str && str.trim() !== '' && str.trim() !== 'undefined'; } function stripQuotes(str) { @@ -15,7 +15,10 @@ function containsDigestHeader(response) { } function containsAuthorizationHeader(originalRequest) { - return Boolean(originalRequest.headers['Authorization']); + return Boolean( + originalRequest.headers['Authorization'] || + originalRequest.headers['authorization'] + ); } function md5(input) { @@ -24,10 +27,10 @@ function md5(input) { function addDigestInterceptor(axiosInstance, request) { const { username, password } = request.digestConfig; - console.debug(request); + console.debug('Digest Auth Interceptor Initialized'); if (!isStrPresent(username) || !isStrPresent(password)) { - console.warn('Required Digest Auth fields are not present'); + console.warn('Required Digest Auth fields (username/password) are not present'); return; } @@ -36,23 +39,37 @@ function addDigestInterceptor(axiosInstance, request) { (error) => { const originalRequest = error.config; + // Prevent retry loops + if (originalRequest._retry) { + return Promise.reject(error); + } + originalRequest._retry = true; + if ( error.response?.status === 401 && containsDigestHeader(error.response) && !containsAuthorizationHeader(originalRequest) ) { + console.debug('Processing Digest Authentication Challenge'); console.debug(error.response.headers['www-authenticate']); const authDetails = error.response.headers['www-authenticate'] .split(',') .map((pair) => pair.split('=').map((item) => item.trim()).map(stripQuotes)) .reduce((acc, [key, value]) => { - if (key && value !== undefined) { - acc[key] = value; + const normalizedKey = key.toLowerCase().replace('digest ', ''); + if (normalizedKey && value !== undefined) { + acc[normalizedKey] = value; } return acc; }, {}); + // Validate required auth details + if (!authDetails.realm || !authDetails.nonce) { + console.warn('Missing required auth details (realm or nonce)'); + return Promise.reject(error); + } + console.debug("Auth Details: \n", authDetails); const nonceCount = '00000001'; @@ -65,20 +82,35 @@ function addDigestInterceptor(axiosInstance, request) { authDetails.algorithm = 'MD5'; } - const uri = new URL(request.url).pathname; - const HA1 = md5(`${username}:${authDetails['Digest realm']}:${password}`); + const uri = new URL(request.url, request.baseURL || 'http://localhost').pathname; // Handle relative URLs + const HA1 = md5(`${username}:${authDetails.realm}:${password}`); const HA2 = md5(`${request.method}:${uri}`); const response = md5( `${HA1}:${authDetails.nonce}:${nonceCount}:${cnonce}:auth:${HA2}` ); - const authorizationHeader = - `Digest username="${username}",realm="${authDetails.realm}",` + - `nonce="${authDetails.nonce}",uri="${uri}",qop="auth",algorithm="${authDetails.algorithm}",` + - `response="${response}",nc="${nonceCount}",cnonce="${cnonce}"` + - (authDetails.opaque ? `,opaque="${authDetails.opaque}"` : ''); + const headerFields = [ + `username="${username}"`, + `realm="${authDetails.realm}"`, + `nonce="${authDetails.nonce}"`, + `uri="${uri}"`, + `qop="auth"`, + `algorithm="${authDetails.algorithm}"`, + `response="${response}"`, + `nc="${nonceCount}"`, + `cnonce="${cnonce}"`, + ]; + if (authDetails.opaque) { + headerFields.push(`opaque="${authDetails.opaque}"`); + } + + const authorizationHeader = `Digest ${headerFields.join(', ')}`; + + // Ensure headers are initialized + originalRequest.headers = originalRequest.headers || {}; originalRequest.headers['Authorization'] = authorizationHeader; + console.debug(`Authorization: ${originalRequest.headers['Authorization']}`); delete originalRequest.digestConfig; diff --git a/packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru b/packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru new file mode 100644 index 000000000..b0d41b2e8 --- /dev/null +++ b/packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru @@ -0,0 +1,20 @@ +meta { + name: simple digest auth + type: http + seq: 1 +} + +get { + url: https://httpbin.org/digest-auth/qop/one/two + body: none + auth: digest +} + +headers { + accept: application/json +} + +auth:digest { + username: one + password: two +} From b612da4f3c27e96ba980971c08dfd68804f4e718 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Thu, 26 Dec 2024 08:17:43 +0530 Subject: [PATCH 5/6] fix: updates --- packages/bruno-app/src/utils/importers/common.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/bruno-app/src/utils/importers/common.js b/packages/bruno-app/src/utils/importers/common.js index e12e829b9..88c4c7872 100644 --- a/packages/bruno-app/src/utils/importers/common.js +++ b/packages/bruno-app/src/utils/importers/common.js @@ -1,6 +1,5 @@ import each from 'lodash/each'; import get from 'lodash/get'; -import _ from 'lodash'; import cloneDeep from 'lodash/cloneDeep'; import { uuid, normalizeFileName } from 'utils/common'; From 907f6a19adaafd6d1788480c2105eb631941e579 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Thu, 26 Dec 2024 10:40:51 +0530 Subject: [PATCH 6/6] revert: digest auth testbench --- .../auth/digest auth/simple digest auth.bru | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru diff --git a/packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru b/packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru deleted file mode 100644 index b0d41b2e8..000000000 --- a/packages/bruno-tests/collection/auth/digest auth/simple digest auth.bru +++ /dev/null @@ -1,20 +0,0 @@ -meta { - name: simple digest auth - type: http - seq: 1 -} - -get { - url: https://httpbin.org/digest-auth/qop/one/two - body: none - auth: digest -} - -headers { - accept: application/json -} - -auth:digest { - username: one - password: two -}