mirror of
https://github.com/usebruno/bruno.git
synced 2025-08-10 17:54:29 +02:00
ntlm auth
This commit is contained in:
41
package-lock.json
generated
41
package-lock.json
generated
@ -19,6 +19,7 @@
|
|||||||
"packages/bruno-graphql-docs"
|
"packages/bruno-graphql-docs"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios-ntlm": "^1.4.2",
|
||||||
"json-bigint": "^1.0.0",
|
"json-bigint": "^1.0.0",
|
||||||
"lossless-json": "^4.0.1"
|
"lossless-json": "^4.0.1"
|
||||||
},
|
},
|
||||||
@ -7158,6 +7159,18 @@
|
|||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios-ntlm": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-8mS/uhmSWiRBiFKQvysPbX1eDBp6e+eXskmasuAXRHrn1Zjgji3O/oGXzXLw7tOhyD9nho1vGjZ2OYOD3cCvHg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.1",
|
||||||
|
"des.js": "^1.1.0",
|
||||||
|
"dev-null": "^0.1.1",
|
||||||
|
"js-md4": "^0.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-jest": {
|
"node_modules/babel-jest": {
|
||||||
"version": "29.7.0",
|
"version": "29.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
|
||||||
@ -9240,6 +9253,16 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/des.js": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.1",
|
||||||
|
"minimalistic-assert": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/destroy": {
|
"node_modules/destroy": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||||
@ -9279,6 +9302,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
|
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/dev-null": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/didyoumean": {
|
"node_modules/didyoumean": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
@ -13146,6 +13175,12 @@
|
|||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/js-md4": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@ -14033,6 +14068,12 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/minimalistic-assert": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "5.1.6",
|
"version": "5.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
"rollup":"3.29.5"
|
"rollup":"3.29.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios-ntlm": "^1.4.2",
|
||||||
"json-bigint": "^1.0.0",
|
"json-bigint": "^1.0.0",
|
||||||
"lossless-json": "^4.0.1"
|
"lossless-json": "^4.0.1"
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,15 @@ const AuthMode = ({ collection }) => {
|
|||||||
>
|
>
|
||||||
Digest Auth
|
Digest Auth
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="dropdown-item"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
onModeChange('ntlm');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
NTLM Auth
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
label {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-line-editor-wrapper {
|
||||||
|
max-width: 400px;
|
||||||
|
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,110 @@
|
|||||||
|
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 { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
|
||||||
|
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const NTLMAuth = ({ collection }) => {
|
||||||
|
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { storedTheme } = useTheme();
|
||||||
|
|
||||||
|
const ntlmAuth = get(collection, 'root.request.auth.ntlm', {});
|
||||||
|
|
||||||
|
const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
|
||||||
|
|
||||||
|
|
||||||
|
const handleUsernameChange = (username) => {
|
||||||
|
dispatch(
|
||||||
|
updateCollectionAuth({
|
||||||
|
mode: 'ntlm',
|
||||||
|
collectionUid: collection.uid,
|
||||||
|
content: {
|
||||||
|
username: username,
|
||||||
|
password: ntlmAuth.password,
|
||||||
|
domain: ntlmAuth.domain
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePasswordChange = (password) => {
|
||||||
|
dispatch(
|
||||||
|
updateCollectionAuth({
|
||||||
|
mode: 'ntlm',
|
||||||
|
collectionUid: collection.uid,
|
||||||
|
content: {
|
||||||
|
username: ntlmAuth.username,
|
||||||
|
password: password,
|
||||||
|
domain: ntlmAuth.domain
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDomainChange = (domain) => {
|
||||||
|
dispatch(
|
||||||
|
updateCollectionAuth({
|
||||||
|
mode: 'ntlm',
|
||||||
|
collectionUid: collection.uid,
|
||||||
|
content: {
|
||||||
|
username: ntlmAuth.username,
|
||||||
|
password: ntlmAuth.password,
|
||||||
|
domain: domain
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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={ntlmAuth.username || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handleUsernameChange(val)}
|
||||||
|
collection={collection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="block font-medium mb-2">Password</label>
|
||||||
|
<div className="single-line-editor-wrapper">
|
||||||
|
<SingleLineEditor
|
||||||
|
value={ntlmAuth.password || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handlePasswordChange(val)}
|
||||||
|
collection={collection}
|
||||||
|
isSecret={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="block font-medium mb-2">Domain</label>
|
||||||
|
<div className="single-line-editor-wrapper">
|
||||||
|
<SingleLineEditor
|
||||||
|
value={ntlmAuth.domain || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handleDomainChange(val)}
|
||||||
|
collection={collection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</StyledWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NTLMAuth;
|
@ -11,6 +11,8 @@ import ApiKeyAuth from './ApiKeyAuth/';
|
|||||||
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
import OAuth2 from './OAuth2';
|
import OAuth2 from './OAuth2';
|
||||||
|
import NTLMAuth from './NTLMAuth';
|
||||||
|
|
||||||
|
|
||||||
const Auth = ({ collection }) => {
|
const Auth = ({ collection }) => {
|
||||||
const authMode = get(collection, 'root.request.auth.mode');
|
const authMode = get(collection, 'root.request.auth.mode');
|
||||||
@ -32,6 +34,9 @@ const Auth = ({ collection }) => {
|
|||||||
case 'digest': {
|
case 'digest': {
|
||||||
return <DigestAuth collection={collection} />;
|
return <DigestAuth collection={collection} />;
|
||||||
}
|
}
|
||||||
|
case 'ntlm': {
|
||||||
|
return <NTLMAuth collection={collection} />;
|
||||||
|
}
|
||||||
case 'oauth2': {
|
case 'oauth2': {
|
||||||
return <OAuth2 collection={collection} />;
|
return <OAuth2 collection={collection} />;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,15 @@ const AuthMode = ({ item, collection }) => {
|
|||||||
>
|
>
|
||||||
Digest Auth
|
Digest Auth
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="dropdown-item"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef?.current?.hide();
|
||||||
|
onModeChange('ntlm');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
NTLM Auth
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="dropdown-item"
|
className="dropdown-item"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
label {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-line-editor-wrapper {
|
||||||
|
max-width: 400px;
|
||||||
|
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,110 @@
|
|||||||
|
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 NTLMAuth = ({ item, collection }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { storedTheme } = useTheme();
|
||||||
|
|
||||||
|
const ntlmAuth = item.draft ? get(item, 'draft.request.auth.ntlm', {}) : get(item, 'request.auth.ntlm', {});
|
||||||
|
|
||||||
|
const handleRun = () => dispatch(sendRequest(item, collection.uid));
|
||||||
|
const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
|
||||||
|
|
||||||
|
const handleUsernameChange = (username) => {
|
||||||
|
dispatch(
|
||||||
|
updateAuth({
|
||||||
|
mode: 'ntlm',
|
||||||
|
collectionUid: collection.uid,
|
||||||
|
itemUid: item.uid,
|
||||||
|
content: {
|
||||||
|
username: username,
|
||||||
|
password: ntlmAuth.password,
|
||||||
|
domain: ntlmAuth.domain
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePasswordChange = (password) => {
|
||||||
|
dispatch(
|
||||||
|
updateAuth({
|
||||||
|
mode: 'ntlm',
|
||||||
|
collectionUid: collection.uid,
|
||||||
|
itemUid: item.uid,
|
||||||
|
content: {
|
||||||
|
username: ntlmAuth.username,
|
||||||
|
password: password,
|
||||||
|
domain: ntlmAuth.domain
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDomainChange = (domain) => {
|
||||||
|
dispatch(
|
||||||
|
updateAuth({
|
||||||
|
mode: 'ntlm',
|
||||||
|
collectionUid: collection.uid,
|
||||||
|
itemUid: item.uid,
|
||||||
|
content: {
|
||||||
|
username: ntlmAuth.username,
|
||||||
|
password: ntlmAuth.password,
|
||||||
|
domain: domain
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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={ntlmAuth.username || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handleUsernameChange(val)}
|
||||||
|
onRun={handleRun}
|
||||||
|
collection={collection}
|
||||||
|
item={item}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="block font-medium mb-2">Password</label>
|
||||||
|
<div className="single-line-editor-wrapper">
|
||||||
|
<SingleLineEditor
|
||||||
|
value={ntlmAuth.password || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handlePasswordChange(val)}
|
||||||
|
onRun={handleRun}
|
||||||
|
collection={collection}
|
||||||
|
item={item}
|
||||||
|
isSecret={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="block font-medium mb-2">Domain</label>
|
||||||
|
<div className="single-line-editor-wrapper">
|
||||||
|
<SingleLineEditor
|
||||||
|
value={ntlmAuth.domain || ''}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={handleSave}
|
||||||
|
onChange={(val) => handleDomainChange(val)}
|
||||||
|
onRun={handleRun}
|
||||||
|
collection={collection}
|
||||||
|
item={item}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</StyledWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NTLMAuth;
|
@ -6,6 +6,8 @@ import BearerAuth from './BearerAuth';
|
|||||||
import BasicAuth from './BasicAuth';
|
import BasicAuth from './BasicAuth';
|
||||||
import DigestAuth from './DigestAuth';
|
import DigestAuth from './DigestAuth';
|
||||||
import WsseAuth from './WsseAuth';
|
import WsseAuth from './WsseAuth';
|
||||||
|
import NTLMAuth from './NTLMAuth';
|
||||||
|
|
||||||
import ApiKeyAuth from './ApiKeyAuth';
|
import ApiKeyAuth from './ApiKeyAuth';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
import { humanizeRequestAuthMode } from 'utils/collections/index';
|
import { humanizeRequestAuthMode } from 'utils/collections/index';
|
||||||
@ -31,6 +33,9 @@ const Auth = ({ item, collection }) => {
|
|||||||
case 'digest': {
|
case 'digest': {
|
||||||
return <DigestAuth collection={collection} item={item} />;
|
return <DigestAuth collection={collection} item={item} />;
|
||||||
}
|
}
|
||||||
|
case 'ntlm': {
|
||||||
|
return <NTLMAuth collection={collection} item={item} />;
|
||||||
|
}
|
||||||
case 'oauth2': {
|
case 'oauth2': {
|
||||||
return <OAuth2 collection={collection} item={item} />;
|
return <OAuth2 collection={collection} item={item} />;
|
||||||
}
|
}
|
||||||
|
@ -473,6 +473,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 'ntlm':
|
||||||
|
item.draft.request.auth.mode = 'ntlm';
|
||||||
|
item.draft.request.auth.ntlm = action.payload.content;
|
||||||
|
break;
|
||||||
case 'oauth2':
|
case 'oauth2':
|
||||||
item.draft.request.auth.mode = 'oauth2';
|
item.draft.request.auth.mode = 'oauth2';
|
||||||
item.draft.request.auth.oauth2 = action.payload.content;
|
item.draft.request.auth.oauth2 = action.payload.content;
|
||||||
@ -1142,6 +1146,9 @@ export const collectionsSlice = createSlice({
|
|||||||
case 'digest':
|
case 'digest':
|
||||||
set(collection, 'root.request.auth.digest', action.payload.content);
|
set(collection, 'root.request.auth.digest', action.payload.content);
|
||||||
break;
|
break;
|
||||||
|
case 'ntlm':
|
||||||
|
set(collection, 'root.request.auth.ntlm', action.payload.content);
|
||||||
|
break;
|
||||||
case 'oauth2':
|
case 'oauth2':
|
||||||
set(collection, 'root.request.auth.oauth2', action.payload.content);
|
set(collection, 'root.request.auth.oauth2', action.payload.content);
|
||||||
break;
|
break;
|
||||||
|
@ -339,6 +339,13 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
|
|||||||
password: get(si.request, 'auth.digest.password', '')
|
password: get(si.request, 'auth.digest.password', '')
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case 'ntlm':
|
||||||
|
di.request.auth.ntlm = {
|
||||||
|
username: get(si.request, 'auth.ntlm.username', ''),
|
||||||
|
password: get(si.request, 'auth.ntlm.password', ''),
|
||||||
|
domain: get(si.request, 'auth.ntlm.domain', '')
|
||||||
|
};
|
||||||
|
break;
|
||||||
case 'oauth2':
|
case 'oauth2':
|
||||||
let grantType = get(si.request, 'auth.oauth2.grantType', '');
|
let grantType = get(si.request, 'auth.oauth2.grantType', '');
|
||||||
switch (grantType) {
|
switch (grantType) {
|
||||||
@ -674,6 +681,10 @@ export const humanizeRequestAuthMode = (mode) => {
|
|||||||
label = 'Digest Auth';
|
label = 'Digest Auth';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'ntlm': {
|
||||||
|
label = 'NTLM';
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'oauth2': {
|
case 'oauth2': {
|
||||||
label = 'OAuth 2.0';
|
label = 'OAuth 2.0';
|
||||||
break;
|
break;
|
||||||
|
@ -28,8 +28,10 @@
|
|||||||
"@usebruno/common": "0.1.0",
|
"@usebruno/common": "0.1.0",
|
||||||
"@usebruno/js": "0.12.0",
|
"@usebruno/js": "0.12.0",
|
||||||
"@usebruno/lang": "0.12.0",
|
"@usebruno/lang": "0.12.0",
|
||||||
|
"@usebruno/vm2": "^3.9.13",
|
||||||
"aws4-axios": "^3.3.0",
|
"aws4-axios": "^3.3.0",
|
||||||
"axios": "1.7.5",
|
"axios": "1.7.5",
|
||||||
|
"axios-ntlm": "^1.4.2",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chalk": "^3.0.0",
|
"chalk": "^3.0.0",
|
||||||
"decomment": "^0.9.5",
|
"decomment": "^0.9.5",
|
||||||
@ -41,7 +43,6 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
"socks-proxy-agent": "^8.0.2",
|
"socks-proxy-agent": "^8.0.2",
|
||||||
"@usebruno/vm2": "^3.9.13",
|
|
||||||
"xmlbuilder": "^15.1.1",
|
"xmlbuilder": "^15.1.1",
|
||||||
"yargs": "^17.6.2"
|
"yargs": "^17.6.2"
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,13 @@ const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEn
|
|||||||
request.awsv4config.profileName = _interpolate(request.awsv4config.profileName) || '';
|
request.awsv4config.profileName = _interpolate(request.awsv4config.profileName) || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interpolate vars for ntlmConfig auth
|
||||||
|
if (request.ntlmConfig) {
|
||||||
|
request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || '';
|
||||||
|
request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || '';
|
||||||
|
request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || '';
|
||||||
|
}
|
||||||
|
|
||||||
if (request) return request;
|
if (request) return request;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,6 +67,14 @@ const prepareRequest = (request, collectionRoot) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.auth.mode === 'ntlm') {
|
||||||
|
axiosRequest.ntlmConfig = {
|
||||||
|
username: get(request, 'auth.ntlm.username'),
|
||||||
|
password: get(request, 'auth.ntlm.password'),
|
||||||
|
domain: get(request, 'auth.ntlm.domain')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (request.auth.mode === 'bearer') {
|
if (request.auth.mode === 'bearer') {
|
||||||
axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
|
axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ const { shouldUseProxy, PatchedHttpsProxyAgent } = require('../utils/proxy-util'
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { createFormData } = require('../utils/common');
|
const { createFormData } = require('../utils/common');
|
||||||
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
|
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
|
||||||
|
const { NtlmClient } = require('axios-ntlm');
|
||||||
|
|
||||||
|
|
||||||
const onConsoleLog = (type, args) => {
|
const onConsoleLog = (type, args) => {
|
||||||
console[type](...args);
|
console[type](...args);
|
||||||
@ -193,8 +195,13 @@ const runSingleRequest = async function (
|
|||||||
|
|
||||||
let response, responseTime;
|
let response, responseTime;
|
||||||
try {
|
try {
|
||||||
// run request
|
|
||||||
const axiosInstance = makeAxiosInstance();
|
let axiosInstance = makeAxiosInstance();
|
||||||
|
if (request.ntlmConfig) {
|
||||||
|
axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance)
|
||||||
|
delete request.ntlmConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (request.awsv4config) {
|
if (request.awsv4config) {
|
||||||
// todo: make this happen in prepare-request.js
|
// todo: make this happen in prepare-request.js
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
"test": "node --experimental-vm-modules $(npx which jest)"
|
"test": "node --experimental-vm-modules $(npx which jest)"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"modulePaths": ["node_modules"]
|
"modulePaths": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/credential-providers": "3.658.1",
|
"@aws-sdk/credential-providers": "3.658.1",
|
||||||
@ -28,9 +30,11 @@
|
|||||||
"@usebruno/lang": "0.12.0",
|
"@usebruno/lang": "0.12.0",
|
||||||
"@usebruno/node-machine-id": "^2.0.0",
|
"@usebruno/node-machine-id": "^2.0.0",
|
||||||
"@usebruno/schema": "0.7.0",
|
"@usebruno/schema": "0.7.0",
|
||||||
|
"@usebruno/vm2": "^3.9.13",
|
||||||
"about-window": "^1.15.2",
|
"about-window": "^1.15.2",
|
||||||
"aws4-axios": "^3.3.0",
|
"aws4-axios": "^3.3.0",
|
||||||
"axios": "1.7.5",
|
"axios": "1.7.5",
|
||||||
|
"axios-ntlm": "^1.4.2",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"content-disposition": "^0.5.4",
|
"content-disposition": "^0.5.4",
|
||||||
@ -56,7 +60,6 @@
|
|||||||
"socks-proxy-agent": "^8.0.2",
|
"socks-proxy-agent": "^8.0.2",
|
||||||
"tough-cookie": "^4.1.3",
|
"tough-cookie": "^4.1.3",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"@usebruno/vm2": "^3.9.13",
|
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
@ -39,6 +39,7 @@ const Oauth2Store = require('../../store/oauth2');
|
|||||||
const iconv = require('iconv-lite');
|
const iconv = require('iconv-lite');
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
const { createFormData } = prepareRequest;
|
const { createFormData } = prepareRequest;
|
||||||
|
const { NtlmClient } = require('axios-ntlm');
|
||||||
|
|
||||||
const safeStringifyJSON = (data) => {
|
const safeStringifyJSON = (data) => {
|
||||||
try {
|
try {
|
||||||
@ -263,7 +264,15 @@ const configureRequest = async (
|
|||||||
...httpsAgentRequestFields
|
...httpsAgentRequestFields
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const axiosInstance = makeAxiosInstance();
|
|
||||||
|
|
||||||
|
let axiosInstance = makeAxiosInstance();
|
||||||
|
|
||||||
|
if (request.ntlmConfig) {
|
||||||
|
axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance)
|
||||||
|
delete request.ntlmConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (request.oauth2) {
|
if (request.oauth2) {
|
||||||
let requestCopy = cloneDeep(request);
|
let requestCopy = cloneDeep(request);
|
||||||
|
@ -230,6 +230,14 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc
|
|||||||
request.wsse.password = _interpolate(request.wsse.password) || '';
|
request.wsse.password = _interpolate(request.wsse.password) || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// interpolate vars for ntlmConfig auth
|
||||||
|
if (request.ntlmConfig) {
|
||||||
|
request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || '';
|
||||||
|
request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || '';
|
||||||
|
request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || '';
|
||||||
|
}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,6 +191,7 @@ const createFormData = (datas, collectionPath) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
|
const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
|
||||||
|
|
||||||
const collectionAuth = get(collectionRoot, 'request.auth');
|
const collectionAuth = get(collectionRoot, 'request.auth');
|
||||||
if (collectionAuth && request.auth.mode === 'inherit') {
|
if (collectionAuth && request.auth.mode === 'inherit') {
|
||||||
switch (collectionAuth.mode) {
|
switch (collectionAuth.mode) {
|
||||||
@ -219,6 +220,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
|
|||||||
password: get(collectionAuth, 'digest.password')
|
password: get(collectionAuth, 'digest.password')
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case 'ntlm':
|
||||||
|
axiosRequest.ntlmConfig = {
|
||||||
|
username: get(collectionAuth, 'ntlm.username'),
|
||||||
|
password: get(collectionAuth, 'ntlm.password'),
|
||||||
|
domain: get(collectionAuth, 'ntlm.domain')
|
||||||
|
};
|
||||||
|
break;
|
||||||
case 'wsse':
|
case 'wsse':
|
||||||
const username = get(request, 'auth.wsse.username', '');
|
const username = get(request, 'auth.wsse.username', '');
|
||||||
const password = get(request, 'auth.wsse.password', '');
|
const password = get(request, 'auth.wsse.password', '');
|
||||||
@ -275,6 +283,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
|
|||||||
password: get(request, 'auth.digest.password')
|
password: get(request, 'auth.digest.password')
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case 'ntlm':
|
||||||
|
axiosRequest.ntlmConfig = {
|
||||||
|
username: get(request, 'auth.ntlm.username'),
|
||||||
|
password: get(request, 'auth.ntlm.password'),
|
||||||
|
domain: get(request, 'auth.ntlm.domain')
|
||||||
|
};
|
||||||
|
break;
|
||||||
case 'oauth2':
|
case 'oauth2':
|
||||||
const grantType = get(request, 'auth.oauth2.grantType');
|
const grantType = get(request, 'auth.oauth2.grantType');
|
||||||
switch (grantType) {
|
switch (grantType) {
|
||||||
|
@ -23,7 +23,7 @@ const { outdentString } = require('../../v1/src/utils');
|
|||||||
*/
|
*/
|
||||||
const grammar = ohm.grammar(`Bru {
|
const grammar = ohm.grammar(`Bru {
|
||||||
BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)*
|
BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)*
|
||||||
auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 | authwsse | authapikey
|
auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM | authOAuth2 | authwsse | authapikey
|
||||||
bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
|
bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
|
||||||
bodyforms = bodyformurlencoded | bodymultipart
|
bodyforms = bodyformurlencoded | bodymultipart
|
||||||
params = paramspath | paramsquery
|
params = paramspath | paramsquery
|
||||||
@ -87,6 +87,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
|
||||||
|
authNTLM = "auth:ntlm" dictionary
|
||||||
authOAuth2 = "auth:oauth2" dictionary
|
authOAuth2 = "auth:oauth2" dictionary
|
||||||
authwsse = "auth:wsse" dictionary
|
authwsse = "auth:wsse" dictionary
|
||||||
authapikey = "auth:apikey" dictionary
|
authapikey = "auth:apikey" dictionary
|
||||||
@ -435,6 +436,26 @@ const sem = grammar.createSemantics().addAttribute('ast', {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
authNTLM(_1, dictionary) {
|
||||||
|
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
|
||||||
|
const usernameKey = _.find(auth, { name: 'username' });
|
||||||
|
const passwordKey = _.find(auth, { name: 'password' });
|
||||||
|
const domainKey = _.find(auth, { name: 'domain' });
|
||||||
|
|
||||||
|
const username = usernameKey ? usernameKey.value : '';
|
||||||
|
const password = passwordKey ? passwordKey.value : '';
|
||||||
|
const domain = passwordKey ? domainKey.value : '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
auth: {
|
||||||
|
ntlm: {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
domain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
authOAuth2(_1, dictionary) {
|
authOAuth2(_1, dictionary) {
|
||||||
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
|
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
|
||||||
const grantTypeKey = _.find(auth, { name: 'grant_type' });
|
const grantTypeKey = _.find(auth, { name: 'grant_type' });
|
||||||
|
@ -4,7 +4,7 @@ const { outdentString } = require('../../v1/src/utils');
|
|||||||
|
|
||||||
const grammar = ohm.grammar(`Bru {
|
const grammar = ohm.grammar(`Bru {
|
||||||
BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)*
|
BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)*
|
||||||
auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 | authwsse | authapikey
|
auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM |authOAuth2 | authwsse | authapikey
|
||||||
|
|
||||||
nl = "\\r"? "\\n"
|
nl = "\\r"? "\\n"
|
||||||
st = " " | "\\t"
|
st = " " | "\\t"
|
||||||
@ -42,6 +42,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
|
||||||
|
authNTLM = "auth:ntlm" dictionary
|
||||||
authOAuth2 = "auth:oauth2" dictionary
|
authOAuth2 = "auth:oauth2" dictionary
|
||||||
authwsse = "auth:wsse" dictionary
|
authwsse = "auth:wsse" dictionary
|
||||||
authapikey = "auth:apikey" dictionary
|
authapikey = "auth:apikey" dictionary
|
||||||
@ -245,6 +246,26 @@ const sem = grammar.createSemantics().addAttribute('ast', {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
authNTLM(_1, dictionary) {
|
||||||
|
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
|
||||||
|
const usernameKey = _.find(auth, { name: 'username' });
|
||||||
|
const passwordKey = _.find(auth, { name: 'password' });
|
||||||
|
const domainKey = _.find(auth, { name: 'domain' });
|
||||||
|
|
||||||
|
const username = usernameKey ? usernameKey.value : '';
|
||||||
|
const password = passwordKey ? passwordKey.value : '';
|
||||||
|
const domain = domainKey ? domainKey.value : '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
auth: {
|
||||||
|
ntlm: {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
domain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
authOAuth2(_1, dictionary) {
|
authOAuth2(_1, dictionary) {
|
||||||
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
|
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
|
||||||
const grantTypeKey = _.find(auth, { name: 'grant_type' });
|
const grantTypeKey = _.find(auth, { name: 'grant_type' });
|
||||||
|
@ -165,6 +165,18 @@ ${indentString(`password: ${auth?.digest?.password || ''}`)}
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (auth && auth.ntlm) {
|
||||||
|
bru += `auth:ntlm {
|
||||||
|
${indentString(`username: ${auth?.ntlm?.username || ''}`)}
|
||||||
|
${indentString(`password: ${auth?.ntlm?.password || ''}`)}
|
||||||
|
${indentString(`domain: ${auth?.ntlm?.domain || ''}`)}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
if (auth && auth.oauth2) {
|
if (auth && auth.oauth2) {
|
||||||
switch (auth?.oauth2?.grantType) {
|
switch (auth?.oauth2?.grantType) {
|
||||||
case 'password':
|
case 'password':
|
||||||
|
@ -120,6 +120,17 @@ ${indentString(`username: ${auth.digest.username}`)}
|
|||||||
${indentString(`password: ${auth.digest.password}`)}
|
${indentString(`password: ${auth.digest.password}`)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth && auth.ntlm) {
|
||||||
|
bru += `auth:ntlm {
|
||||||
|
${indentString(`username: ${auth.ntlm.username}`)}
|
||||||
|
${indentString(`password: ${auth.ntlm.password}`)}
|
||||||
|
${indentString(`domain: ${auth.ntlm.domain}`)}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,17 @@ const authDigestSchema = Yup.object({
|
|||||||
.noUnknown(true)
|
.noUnknown(true)
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const authNTLMSchema = Yup.object({
|
||||||
|
username: Yup.string().nullable(),
|
||||||
|
password: Yup.string().nullable(),
|
||||||
|
domain: Yup.string().nullable()
|
||||||
|
|
||||||
|
})
|
||||||
|
.noUnknown(true)
|
||||||
|
.strict();
|
||||||
|
|
||||||
const authApiKeySchema = Yup.object({
|
const authApiKeySchema = Yup.object({
|
||||||
key: Yup.string().nullable(),
|
key: Yup.string().nullable(),
|
||||||
value: Yup.string().nullable(),
|
value: Yup.string().nullable(),
|
||||||
@ -194,11 +205,12 @@ const oauth2Schema = Yup.object({
|
|||||||
|
|
||||||
const authSchema = Yup.object({
|
const authSchema = Yup.object({
|
||||||
mode: Yup.string()
|
mode: Yup.string()
|
||||||
.oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'oauth2', 'wsse', 'apikey'])
|
.oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'ntlm', 'oauth2', 'wsse', 'apikey'])
|
||||||
.required('mode is required'),
|
.required('mode is required'),
|
||||||
awsv4: authAwsV4Schema.nullable(),
|
awsv4: authAwsV4Schema.nullable(),
|
||||||
basic: authBasicSchema.nullable(),
|
basic: authBasicSchema.nullable(),
|
||||||
bearer: authBearerSchema.nullable(),
|
bearer: authBearerSchema.nullable(),
|
||||||
|
ntlm: authNTLMSchema.nullable(),
|
||||||
digest: authDigestSchema.nullable(),
|
digest: authDigestSchema.nullable(),
|
||||||
oauth2: oauth2Schema.nullable(),
|
oauth2: oauth2Schema.nullable(),
|
||||||
wsse: authWsseSchema.nullable(),
|
wsse: authWsseSchema.nullable(),
|
||||||
|
Reference in New Issue
Block a user