From 01a62d66cc2953cc57e0c6aa49132070b42d8ea3 Mon Sep 17 00:00:00 2001 From: lohxt1 Date: Wed, 5 Feb 2025 16:06:41 +0530 Subject: [PATCH] oauth2 postman import fix and include client certs and proxy config while fetching access token --- .../Auth/OAuth2/AuthorizationCode/index.js | 2 +- .../Auth/OAuth2/ClientCredentials/index.js | 2 +- .../Auth/OAuth2/PasswordCredentials/index.js | 2 +- .../ReduxStore/slices/collections/actions.js | 4 +- .../src/utils/importers/postman-collection.js | 57 +++++++++++++++++++ packages/bruno-electron/src/ipc/collection.js | 21 ++++++- packages/bruno-electron/src/utils/request.js | 36 +++++++++--- 7 files changed, 109 insertions(+), 15 deletions(-) diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js index f0da10f76..3ffad9067 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js @@ -49,7 +49,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu requestCopy.headers = {}; toggleFetchingToken(true); try { - await dispatch(fetchOauth2Credentials({ request: requestCopy, collection })); + await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); toggleFetchingToken(false); toast.success('token fetched successfully!'); } diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js index e1e95e33d..518a21efb 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/ClientCredentials/index.js @@ -30,7 +30,7 @@ const OAuth2ClientCredentials = ({ save, item = {}, request, handleRun, updateAu requestCopy.headers = {}; toggleFetchingToken(true); try { - await dispatch(fetchOauth2Credentials({ request: requestCopy, collection })); + await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); toggleFetchingToken(false); toast.success('Token fetched successfully!'); } diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js index 4202601a9..54c5e0142 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/PasswordCredentials/index.js @@ -30,7 +30,7 @@ const OAuth2PasswordCredentials = ({ save, item = {}, request, handleRun, update requestCopy.headers = {}; toggleFetchingToken(true); try { - await dispatch(fetchOauth2Credentials({ request: requestCopy, collection })); + await dispatch(fetchOauth2Credentials({ itemUid: item.uid, request: requestCopy, collection })); toggleFetchingToken(false); toast.success('Token fetched successfully!'); } diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 6b98bf68d..01618bfd2 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -1196,10 +1196,10 @@ export const hydrateCollectionWithUiStateSnapshot = (payload) => (dispatch, getS }; export const fetchOauth2Credentials = (payload) => async (dispatch, getState) => { - const { request, collection } = payload; + const { request, collection, itemUid } = payload; return new Promise((resolve, reject) => { ipcRenderer - .invoke('renderer:fetch-oauth2-credentials', { request, collection }) + .invoke('renderer:fetch-oauth2-credentials', { itemUid, request, collection }) .then(({ credentials, url, collectionUid, credentialsId }) => { dispatch(collectionAddOauth2CredentialsByUrl({ credentials, url, collectionUid, credentialsId })); resolve(credentials); diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js index b5a685e71..72e57e942 100644 --- a/packages/bruno-app/src/utils/importers/postman-collection.js +++ b/packages/bruno-app/src/utils/importers/postman-collection.js @@ -425,6 +425,63 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) = value: authValues.value, placement: "header" //By default we are placing the apikey values in headers! } + } else if (auth.type === 'oauth2'){ + const findValueUsingKey = (key) => { + return auth?.oauth2?.find(v => v?.key == key)?.value || '' + } + const oauth2GrantTypeMaps = { + 'authorization_code_with_pkce': 'authorization_code', + 'authorization_code': 'authorization_code', + 'client_credentials': 'client_credentials', + 'password_credentials': 'password_credentials' + } + const grantType = oauth2GrantTypeMaps[findValueUsingKey('grant_type')]; + if (grantType) { + brunoRequestItem.request.auth.mode = 'oauth2'; + switch(grantType) { + case 'authorization_code': + brunoRequestItem.request.auth.oauth2 = { + grantType: 'authorization_code', + authorizationUrl: findValueUsingKey('authUrl'), + callbackUrl: findValueUsingKey('redirect_uri'), + accessTokenUrl: findValueUsingKey('accessTokenUrl'), + clientId: findValueUsingKey('clientId'), + clientSecret: findValueUsingKey('clientSecret'), + scope: findValueUsingKey('scope'), + state: findValueUsingKey('state'), + pkce: Boolean(findValueUsingKey('grant_type') == 'authorization_code_with_pkce'), + tokenPlacement: findValueUsingKey('addTokenTo') == 'header' ? 'header' : 'url', + credentialsPlacement: findValueUsingKey('client_authentication') == 'body' ? 'body' : 'basic_auth_header' + }; + break; + case 'password_credentials': + brunoRequestItem.request.auth.oauth2 = { + grantType: 'password', + accessTokenUrl: findValueUsingKey('accessTokenUrl'), + username: findValueUsingKey('username'), + password: findValueUsingKey('password'), + clientId: findValueUsingKey('clientId'), + clientSecret: findValueUsingKey('clientSecret'), + scope: findValueUsingKey('scope'), + state: findValueUsingKey('state'), + tokenPlacement: findValueUsingKey('addTokenTo') == 'header' ? 'header' : 'url', + credentialsPlacement: findValueUsingKey('client_authentication') == 'body' ? 'body' : 'basic_auth_header' + }; + break; + case 'client_credentials': + brunoRequestItem.request.auth.oauth2 = { + grantType: 'client_credentials', + accessTokenUrl: findValueUsingKey('accessTokenUrl'), + clientId: findValueUsingKey('clientId'), + clientSecret: findValueUsingKey('clientSecret'), + scope: findValueUsingKey('scope'), + state: findValueUsingKey('state'), + tokenPlacement: findValueUsingKey('addTokenTo') == 'header' ? 'header' : 'url', + credentialsPlacement: findValueUsingKey('client_authentication') == 'body' ? 'body' : 'basic_auth_header' + }; + break; + } + } } } diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 1b865e4fc..fc0b6cb83 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -34,9 +34,10 @@ const CollectionSecurityStore = require('../store/collection-security'); const UiStateSnapshotStore = require('../store/ui-state-snapshot'); const Oauth2Store = require('../store/oauth2'); const interpolateVars = require('./network/interpolate-vars'); -const { getEnvVars } = require('../utils/collection'); +const { getEnvVars, getTreePathFromCollectionToItem, mergeVars } = require('../utils/collection'); const { getProcessEnvVars } = require('../store/process-env'); const { getOAuth2TokenUsingAuthorizationCode, getOAuth2TokenUsingClientCredentials, getOAuth2TokenUsingPasswordCredentials, refreshOauth2Token } = require('../utils/oauth2'); +const { configureRequestWithCertsAndProxy } = require('../utils/request'); const environmentSecretsStore = new EnvironmentSecretsStore(); const collectionSecurityStore = new CollectionSecurityStore(); @@ -792,15 +793,29 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); - ipcMain.handle('renderer:fetch-oauth2-credentials', async (event, { request, collection }) => { + ipcMain.handle('renderer:fetch-oauth2-credentials', async (event, { itemUid, request, collection }) => { try { if (request.oauth2) { let requestCopy = _.cloneDeep(request); - const { uid: collectionUid, runtimeVariables, environments = [], activeEnvironmentUid } = collection; + const { uid: collectionUid, pathname: collectionPath, runtimeVariables, environments = [], activeEnvironmentUid } = collection; const environment = _.find(environments, (e) => e.uid === activeEnvironmentUid); const envVars = getEnvVars(environment); const processEnvVars = getProcessEnvVars(collectionUid); + const partialItem = { uid: itemUid }; + const requestTreePath = getTreePathFromCollectionToItem(collection, partialItem); + if (requestTreePath && requestTreePath.length > 0) { + mergeVars(collection, requestCopy, requestTreePath); + } + interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars); + requestCopy = await configureRequestWithCertsAndProxy({ + collectionUid, + request: requestCopy, + envVars, + runtimeVariables, + processEnvVars, + collectionPath + }); const { oauth2: { grantType }} = requestCopy || {}; let credentials, url, credentialsId; switch (grantType) { diff --git a/packages/bruno-electron/src/utils/request.js b/packages/bruno-electron/src/utils/request.js index f0dbd981d..cf085eae0 100644 --- a/packages/bruno-electron/src/utils/request.js +++ b/packages/bruno-electron/src/utils/request.js @@ -432,19 +432,14 @@ const mapHeaders = (requestHeaders, collectionHeaders) => { return headers; }; -const configureRequest = async ( +const configureRequestWithCertsAndProxy = async ({ collectionUid, request, envVars, runtimeVariables, processEnvVars, collectionPath -) => { - const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; - if (!protocolRegex.test(request.url)) { - request.url = `http://${request.url}`; - } - +}) => { /** * @see https://github.com/usebruno/bruno/issues/211 set keepAlive to true, this should fix socket hang up errors * @see https://github.com/nodejs/node/pull/43522 keepAlive was changed to true globally on Node v19+ @@ -604,6 +599,32 @@ const configureRequest = async ( ...httpsAgentRequestFields }); } + + return request; +} + +const configureRequest = async ( + collectionUid, + request, + envVars, + runtimeVariables, + processEnvVars, + collectionPath +) => { + const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; + if (!protocolRegex.test(request.url)) { + request.url = `http://${request.url}`; + } + + request = await configureRequestWithCertsAndProxy({ + collectionUid, + request, + envVars, + runtimeVariables, + processEnvVars, + collectionPath + }); + const axiosInstance = makeAxiosInstance(); if (request.ntlmConfig) { @@ -751,6 +772,7 @@ module.exports = { prepareGqlIntrospectionRequest, setAuthHeaders, getJsSandboxRuntime, + configureRequestWithCertsAndProxy, configureRequest, parseDataFromResponse }