From 5649f7c3980fb65738aca8188e61cd4a58a05c3e Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Mon, 18 Dec 2023 01:20:16 +0530 Subject: [PATCH] feat(#1003): oauth 2.0 client credentials --- .../RequestPane/Auth/AuthMode/index.js | 9 +++ .../RequestPane/Auth/OAuth2/StyledWrapper.js | 16 ++++ .../RequestPane/Auth/OAuth2/index.js | 78 +++++++++++++++++++ .../src/components/RequestPane/Auth/index.js | 6 ++ .../ReduxStore/slices/collections/index.js | 4 + .../bruno-app/src/utils/collections/index.js | 4 + .../src/ipc/network/prepare-request.js | 11 +++ packages/bruno-lang/v2/src/bruToJson.js | 18 ++++- packages/bruno-lang/v2/src/jsonToBru.js | 10 +++ .../bruno-lang/v2/tests/fixtures/request.bru | 6 ++ .../bruno-lang/v2/tests/fixtures/request.json | 5 ++ .../bruno-schema/src/collections/index.js | 15 +++- 12 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/OAuth2/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js diff --git a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js index 8eb4fee90..f26aa8651 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js @@ -71,6 +71,15 @@ const AuthMode = ({ item, collection }) => { > Digest Auth +
{ + dropdownTippyRef.current.hide(); + onModeChange('oauth2'); + }} + > + OAuth +
{ diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/StyledWrapper.js new file mode 100644 index 000000000..c2bb5d207 --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/StyledWrapper.js @@ -0,0 +1,16 @@ +import styled from 'styled-components'; + +const Wrapper = styled.div` + label { + font-size: 0.8125rem; + } + + .single-line-editor-wrapper { + padding: 0.15rem 0.4rem; + border-radius: 3px; + border: solid 1px ${(props) => props.theme.input.border}; + background-color: ${(props) => props.theme.input.bg}; + } +`; + +export default Wrapper; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js new file mode 100644 index 000000000..ec1dae40d --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/index.js @@ -0,0 +1,78 @@ +import React from 'react'; +import get from 'lodash/get'; +import { useTheme } from 'providers/Theme'; +import { useDispatch } from 'react-redux'; +import SingleLineEditor from 'components/SingleLineEditor'; +import { updateAuth } from 'providers/ReduxStore/slices/collections'; +import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; +import StyledWrapper from './StyledWrapper'; + +const OAuth2 = ({ item, collection }) => { + const dispatch = useDispatch(); + const { storedTheme } = useTheme(); + + const oAuth = item.draft ? get(item, 'draft.request.auth.oauth2', {}) : get(item, 'request.auth.oauth2', {}); + + const handleRun = () => dispatch(sendRequest(item, collection.uid)); + const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); + + const handleUsernameChange = (username) => { + dispatch( + updateAuth({ + mode: 'oauth2', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + grantType: oAuth.grantType, + username: username, + password: oAuth.password + } + }) + ); + }; + + const handlePasswordChange = (password) => { + dispatch( + updateAuth({ + mode: 'oauth2', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + grantType: oAuth.grantType, + username: oAuth.username, + password: password + } + }) + ); + }; + + return ( + + +
+ handleUsernameChange(val)} + onRun={handleRun} + collection={collection} + /> +
+ + +
+ handlePasswordChange(val)} + onRun={handleRun} + collection={collection} + /> +
+
+ ); +}; + +export default OAuth2; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js index bd388737e..ba1ee2700 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js @@ -5,11 +5,14 @@ import AwsV4Auth from './AwsV4Auth'; import BearerAuth from './BearerAuth'; import BasicAuth from './BasicAuth'; import DigestAuth from './DigestAuth'; +import OAuth2 from './OAuth2'; import StyledWrapper from './StyledWrapper'; const Auth = ({ item, collection }) => { const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode'); + console.log(item); + const getAuthView = () => { switch (authMode) { case 'awsv4': { @@ -24,6 +27,9 @@ const Auth = ({ item, collection }) => { case 'digest': { return ; } + case 'oauth2': { + return ; + } } }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index f464e5130..57dde52f3 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -415,6 +415,10 @@ export const collectionsSlice = createSlice({ item.draft.request.auth.mode = 'digest'; item.draft.request.auth.digest = action.payload.content; break; + case 'oauth2': + item.draft.request.auth.mode = 'oauth2'; + item.draft.request.auth.oauth2 = action.payload.content; + break; } } } diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index 05dd0fb43..681194f87 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -498,6 +498,10 @@ export const humanizeRequestAuthMode = (mode) => { label = 'Digest Auth'; break; } + case 'oauth2': { + label = 'OAuth 2.0'; + break; + } } return label; diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 761984e65..7e978b673 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -64,6 +64,17 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { username: get(request, 'auth.digest.username'), password: get(request, 'auth.digest.password') }; + break; + case 'oauth2': + const grantType = get(request, 'auth.oauth2.grantType'); + if (grantType === 'resourceOwnerPasswordCredentials') { + axiosRequest.data = { + grant_type: grantType, + username: get(request, 'auth.oauth2.username'), + password: get(request, 'auth.oauth2.password') + }; + } + break; } } diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index fbe289974..533839b14 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -23,7 +23,7 @@ const { outdentString } = require('../../v1/src/utils'); */ const grammar = ohm.grammar(`Bru { BruFile = (meta | http | query | headers | auths | bodies | varsandassert | script | tests | docs)* - auths = authawsv4 | authbasic | authbearer | authdigest + auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body bodyforms = bodyformurlencoded | bodymultipart @@ -80,6 +80,7 @@ const grammar = ohm.grammar(`Bru { authbasic = "auth:basic" dictionary authbearer = "auth:bearer" dictionary authdigest = "auth:digest" dictionary + authOAuth2 = "auth:oauth2" dictionary body = "body" st* "{" nl* textblock tagend bodyjson = "body:json" st* "{" nl* textblock tagend @@ -366,6 +367,21 @@ const sem = grammar.createSemantics().addAttribute('ast', { } }; }, + authOAuth2(_1, dictionary) { + const auth = mapPairListToKeyValPairs(dictionary.ast, false); + const grantTypeKey = _.find(auth, { name: 'grantType' }); + const usernameKey = _.find(auth, { name: 'username' }); + const passwordKey = _.find(auth, { name: 'password' }); + return { + auth: { + oauth2: { + grantType: grantTypeKey ? grantTypeKey.value : '', + username: usernameKey ? usernameKey.value : '', + password: passwordKey ? passwordKey.value : '' + } + } + }; + }, bodyformurlencoded(_1, dictionary) { return { body: { diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index f4959500a..e1b0dbeae 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -87,6 +87,16 @@ const jsonToBru = (json) => { bru += '\n}\n\n'; } + if (auth && auth.oauth2) { + bru += `auth:oauth2 { +${indentString(`grantType: ${auth.oauth2.grantType}`)} +${indentString(`username: ${auth.oauth2.username}`)} +${indentString(`password: ${auth.oauth2.password}`)} +} + +`; + } + if (auth && auth.awsv4) { bru += `auth:awsv4 { ${indentString(`accessKeyId: ${auth.awsv4.accessKeyId}`)} diff --git a/packages/bruno-lang/v2/tests/fixtures/request.bru b/packages/bruno-lang/v2/tests/fixtures/request.bru index 4855506a6..26044dc5c 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.bru +++ b/packages/bruno-lang/v2/tests/fixtures/request.bru @@ -22,6 +22,12 @@ headers { ~transaction-id: {{transactionId}} } +auth:oauth2 { + grantType: resourceOwnerPasswordCredentials + username: john + password: secret +} + auth:awsv4 { accessKeyId: A12345678 secretAccessKey: thisisasecret diff --git a/packages/bruno-lang/v2/tests/fixtures/request.json b/packages/bruno-lang/v2/tests/fixtures/request.json index c23c46474..c70e96945 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.json +++ b/packages/bruno-lang/v2/tests/fixtures/request.json @@ -45,6 +45,11 @@ } ], "auth": { + "oauth2": { + "grantType": "resourceOwnerPasswordCredentials", + "username": "john", + "password": "secret" + }, "awsv4": { "accessKeyId": "A12345678", "secretAccessKey": "thisisasecret", diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 37e6629af..3b0d37106 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -101,12 +101,23 @@ const authDigestSchema = Yup.object({ .noUnknown(true) .strict(); +const oAuth2Schema = Yup.object({ + grantType: Yup.string() + .oneOf(['clientCredentials', 'resourceOwnerPasswordCredentials']) + .required('grantType is required'), + username: Yup.string().nullable(), + password: Yup.string().nullable() +}) + .noUnknown(true) + .strict(); + const authSchema = Yup.object({ - mode: Yup.string().oneOf(['none', 'awsv4', 'basic', 'bearer', 'digest']).required('mode is required'), + mode: Yup.string().oneOf(['none', 'awsv4', 'basic', 'bearer', 'digest', 'oauth2']).required('mode is required'), awsv4: authAwsV4Schema.nullable(), basic: authBasicSchema.nullable(), bearer: authBearerSchema.nullable(), - digest: authDigestSchema.nullable() + digest: authDigestSchema.nullable(), + oauth2: oAuth2Schema.nullable() }) .noUnknown(true) .strict();