forked from extern/bruno
feat(#1003): oauth 2.0 client credentials
This commit is contained in:
parent
454e0e5260
commit
5649f7c398
@ -71,6 +71,15 @@ const AuthMode = ({ item, collection }) => {
|
|||||||
>
|
>
|
||||||
Digest Auth
|
Digest Auth
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="dropdown-item"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
onModeChange('oauth2');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
OAuth
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -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;
|
@ -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 (
|
||||||
|
<StyledWrapper className="mt-2 w-full">
|
||||||
|
<label className="block font-medium mb-2">Username</label>
|
||||||
|
<div className="single-line-editor-wrapper mb-2">
|
||||||
|
<SingleLineEditor
|
||||||
|
value={oAuth.username || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handleUsernameChange(val)}
|
||||||
|
onRun={handleRun}
|
||||||
|
collection={collection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="block font-medium mb-2">Password</label>
|
||||||
|
<div className="single-line-editor-wrapper">
|
||||||
|
<SingleLineEditor
|
||||||
|
value={oAuth.password || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handlePasswordChange(val)}
|
||||||
|
onRun={handleRun}
|
||||||
|
collection={collection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</StyledWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OAuth2;
|
@ -5,11 +5,14 @@ import AwsV4Auth from './AwsV4Auth';
|
|||||||
import BearerAuth from './BearerAuth';
|
import BearerAuth from './BearerAuth';
|
||||||
import BasicAuth from './BasicAuth';
|
import BasicAuth from './BasicAuth';
|
||||||
import DigestAuth from './DigestAuth';
|
import DigestAuth from './DigestAuth';
|
||||||
|
import OAuth2 from './OAuth2';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
|
||||||
const Auth = ({ item, collection }) => {
|
const Auth = ({ item, collection }) => {
|
||||||
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
|
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
|
||||||
|
|
||||||
|
console.log(item);
|
||||||
|
|
||||||
const getAuthView = () => {
|
const getAuthView = () => {
|
||||||
switch (authMode) {
|
switch (authMode) {
|
||||||
case 'awsv4': {
|
case 'awsv4': {
|
||||||
@ -24,6 +27,9 @@ const Auth = ({ item, collection }) => {
|
|||||||
case 'digest': {
|
case 'digest': {
|
||||||
return <DigestAuth collection={collection} item={item} />;
|
return <DigestAuth collection={collection} item={item} />;
|
||||||
}
|
}
|
||||||
|
case 'oauth2': {
|
||||||
|
return <OAuth2 collection={collection} item={item} />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -415,6 +415,10 @@ export const collectionsSlice = createSlice({
|
|||||||
item.draft.request.auth.mode = 'digest';
|
item.draft.request.auth.mode = 'digest';
|
||||||
item.draft.request.auth.digest = action.payload.content;
|
item.draft.request.auth.digest = action.payload.content;
|
||||||
break;
|
break;
|
||||||
|
case 'oauth2':
|
||||||
|
item.draft.request.auth.mode = 'oauth2';
|
||||||
|
item.draft.request.auth.oauth2 = action.payload.content;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,6 +498,10 @@ export const humanizeRequestAuthMode = (mode) => {
|
|||||||
label = 'Digest Auth';
|
label = 'Digest Auth';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'oauth2': {
|
||||||
|
label = 'OAuth 2.0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return label;
|
return label;
|
||||||
|
@ -64,6 +64,17 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
|
|||||||
username: get(request, 'auth.digest.username'),
|
username: get(request, 'auth.digest.username'),
|
||||||
password: get(request, 'auth.digest.password')
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ const { outdentString } = require('../../v1/src/utils');
|
|||||||
*/
|
*/
|
||||||
const grammar = ohm.grammar(`Bru {
|
const grammar = ohm.grammar(`Bru {
|
||||||
BruFile = (meta | http | query | headers | auths | bodies | varsandassert | script | tests | docs)*
|
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
|
bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
|
||||||
bodyforms = bodyformurlencoded | bodymultipart
|
bodyforms = bodyformurlencoded | bodymultipart
|
||||||
|
|
||||||
@ -80,6 +80,7 @@ const grammar = ohm.grammar(`Bru {
|
|||||||
authbasic = "auth:basic" dictionary
|
authbasic = "auth:basic" dictionary
|
||||||
authbearer = "auth:bearer" dictionary
|
authbearer = "auth:bearer" dictionary
|
||||||
authdigest = "auth:digest" dictionary
|
authdigest = "auth:digest" dictionary
|
||||||
|
authOAuth2 = "auth:oauth2" dictionary
|
||||||
|
|
||||||
body = "body" st* "{" nl* textblock tagend
|
body = "body" st* "{" nl* textblock tagend
|
||||||
bodyjson = "body:json" 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) {
|
bodyformurlencoded(_1, dictionary) {
|
||||||
return {
|
return {
|
||||||
body: {
|
body: {
|
||||||
|
@ -87,6 +87,16 @@ const jsonToBru = (json) => {
|
|||||||
bru += '\n}\n\n';
|
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) {
|
if (auth && auth.awsv4) {
|
||||||
bru += `auth:awsv4 {
|
bru += `auth:awsv4 {
|
||||||
${indentString(`accessKeyId: ${auth.awsv4.accessKeyId}`)}
|
${indentString(`accessKeyId: ${auth.awsv4.accessKeyId}`)}
|
||||||
|
@ -22,6 +22,12 @@ headers {
|
|||||||
~transaction-id: {{transactionId}}
|
~transaction-id: {{transactionId}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auth:oauth2 {
|
||||||
|
grantType: resourceOwnerPasswordCredentials
|
||||||
|
username: john
|
||||||
|
password: secret
|
||||||
|
}
|
||||||
|
|
||||||
auth:awsv4 {
|
auth:awsv4 {
|
||||||
accessKeyId: A12345678
|
accessKeyId: A12345678
|
||||||
secretAccessKey: thisisasecret
|
secretAccessKey: thisisasecret
|
||||||
|
@ -45,6 +45,11 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": {
|
"auth": {
|
||||||
|
"oauth2": {
|
||||||
|
"grantType": "resourceOwnerPasswordCredentials",
|
||||||
|
"username": "john",
|
||||||
|
"password": "secret"
|
||||||
|
},
|
||||||
"awsv4": {
|
"awsv4": {
|
||||||
"accessKeyId": "A12345678",
|
"accessKeyId": "A12345678",
|
||||||
"secretAccessKey": "thisisasecret",
|
"secretAccessKey": "thisisasecret",
|
||||||
|
@ -101,12 +101,23 @@ const authDigestSchema = Yup.object({
|
|||||||
.noUnknown(true)
|
.noUnknown(true)
|
||||||
.strict();
|
.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({
|
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(),
|
awsv4: authAwsV4Schema.nullable(),
|
||||||
basic: authBasicSchema.nullable(),
|
basic: authBasicSchema.nullable(),
|
||||||
bearer: authBearerSchema.nullable(),
|
bearer: authBearerSchema.nullable(),
|
||||||
digest: authDigestSchema.nullable()
|
digest: authDigestSchema.nullable(),
|
||||||
|
oauth2: oAuth2Schema.nullable()
|
||||||
})
|
})
|
||||||
.noUnknown(true)
|
.noUnknown(true)
|
||||||
.strict();
|
.strict();
|
||||||
|
Loading…
Reference in New Issue
Block a user