From 5500070b4956d27e4603ba6a9b4ab704b0ff81fb Mon Sep 17 00:00:00 2001 From: tlaloc911 <29415755+tlaloc911@users.noreply.github.com> Date: Mon, 13 Jan 2025 07:18:26 -0600 Subject: [PATCH] ntlm auth (#3329) Co-authored-by: Anoop M D --- .../CollectionSettings/Auth/AuthMode/index.js | 9 ++ .../Auth/NTLMAuth/StyledWrapper.js | 17 +++ .../CollectionSettings/Auth/NTLMAuth/index.js | 110 ++++++++++++++++++ .../CollectionSettings/Auth/index.js | 5 + .../RequestPane/Auth/AuthMode/index.js | 9 ++ .../Auth/NTLMAuth/StyledWrapper.js | 17 +++ .../RequestPane/Auth/NTLMAuth/index.js | 110 ++++++++++++++++++ .../src/components/RequestPane/Auth/index.js | 5 + .../ReduxStore/slices/collections/index.js | 7 ++ .../bruno-app/src/utils/collections/index.js | 11 ++ packages/bruno-cli/package.json | 2 + .../bruno-cli/src/runner/interpolate-vars.js | 7 ++ .../bruno-cli/src/runner/prepare-request.js | 8 ++ .../src/runner/run-single-request.js | 11 +- packages/bruno-electron/package.json | 7 +- .../bruno-electron/src/ipc/network/index.js | 11 +- .../src/ipc/network/interpolate-vars.js | 8 ++ .../src/ipc/network/prepare-request.js | 15 +++ packages/bruno-lang/v2/src/bruToJson.js | 23 +++- .../bruno-lang/v2/src/collectionBruToJson.js | 23 +++- packages/bruno-lang/v2/src/jsonToBru.js | 12 ++ .../bruno-lang/v2/src/jsonToCollectionBru.js | 11 ++ .../bruno-schema/src/collections/index.js | 14 ++- 23 files changed, 444 insertions(+), 8 deletions(-) create mode 100644 packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js index 7dabb4c71..2c541cc28 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js @@ -79,6 +79,15 @@ const AuthMode = ({ collection }) => { > Digest Auth +
{ + dropdownTippyRef.current.hide(); + onModeChange('ntlm'); + }} + > + NTLM Auth +
{ diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js new file mode 100644 index 000000000..316d3a7c5 --- /dev/null +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js @@ -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; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js new file mode 100644 index 000000000..341c805dc --- /dev/null +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js @@ -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 ( + + +
+ handleUsernameChange(val)} + collection={collection} + /> +
+ + +
+ handlePasswordChange(val)} + collection={collection} + isSecret={true} + /> +
+ + +
+ handleDomainChange(val)} + collection={collection} + /> +
+
+ ); +}; + +export default NTLMAuth; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/index.js index 05efc17b2..c19ae9873 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/index.js @@ -11,6 +11,8 @@ import ApiKeyAuth from './ApiKeyAuth/'; import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import OAuth2 from './OAuth2'; +import NTLMAuth from './NTLMAuth'; + const Auth = ({ collection }) => { const authMode = get(collection, 'root.request.auth.mode'); @@ -32,6 +34,9 @@ const Auth = ({ collection }) => { case 'digest': { return ; } + case 'ntlm': { + return ; + } case 'oauth2': { return ; } 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 dfbaba7fa..1e3bedc2f 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js @@ -70,6 +70,15 @@ const AuthMode = ({ item, collection }) => { > Digest Auth
+
{ + dropdownTippyRef?.current?.hide(); + onModeChange('ntlm'); + }} + > + NTLM Auth +
{ diff --git a/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js new file mode 100644 index 000000000..316d3a7c5 --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js @@ -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; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js new file mode 100644 index 000000000..65e756041 --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js @@ -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 ( + + +
+ handleUsernameChange(val)} + onRun={handleRun} + collection={collection} + item={item} + /> +
+ + +
+ handlePasswordChange(val)} + onRun={handleRun} + collection={collection} + item={item} + isSecret={true} + /> +
+ + +
+ handleDomainChange(val)} + onRun={handleRun} + collection={collection} + item={item} + /> +
+
+ ); +}; + +export default NTLMAuth; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js index 1515e5224..743d23267 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js @@ -6,6 +6,8 @@ import BearerAuth from './BearerAuth'; import BasicAuth from './BasicAuth'; import DigestAuth from './DigestAuth'; import WsseAuth from './WsseAuth'; +import NTLMAuth from './NTLMAuth'; + import ApiKeyAuth from './ApiKeyAuth'; import StyledWrapper from './StyledWrapper'; import { humanizeRequestAuthMode } from 'utils/collections/index'; @@ -31,6 +33,9 @@ const Auth = ({ item, collection }) => { case 'digest': { return ; } + case 'ntlm': { + 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 10f552ec5..d4ad48921 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -473,6 +473,10 @@ export const collectionsSlice = createSlice({ item.draft.request.auth.mode = 'digest'; item.draft.request.auth.digest = action.payload.content; break; + case 'ntlm': + item.draft.request.auth.mode = 'ntlm'; + item.draft.request.auth.ntlm = action.payload.content; + break; case 'oauth2': item.draft.request.auth.mode = 'oauth2'; item.draft.request.auth.oauth2 = action.payload.content; @@ -1144,6 +1148,9 @@ export const collectionsSlice = createSlice({ case 'digest': set(collection, 'root.request.auth.digest', action.payload.content); break; + case 'ntlm': + set(collection, 'root.request.auth.ntlm', action.payload.content); + break; case 'oauth2': set(collection, 'root.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 d770c60a3..bc6c731f4 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -340,6 +340,13 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {} password: get(si.request, 'auth.digest.password', '') }; 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': let grantType = get(si.request, 'auth.oauth2.grantType', ''); switch (grantType) { @@ -680,6 +687,10 @@ export const humanizeRequestAuthMode = (mode) => { label = 'Digest Auth'; break; } + case 'ntlm': { + label = 'NTLM'; + break; + } case 'oauth2': { label = 'OAuth 2.0'; break; diff --git a/packages/bruno-cli/package.json b/packages/bruno-cli/package.json index adfc93658..8353e8ba8 100644 --- a/packages/bruno-cli/package.json +++ b/packages/bruno-cli/package.json @@ -50,8 +50,10 @@ "@usebruno/common": "0.1.0", "@usebruno/js": "0.12.0", "@usebruno/lang": "0.12.0", + "@usebruno/vm2": "^3.9.13", "aws4-axios": "^3.3.0", "axios": "1.7.5", + "axios-ntlm": "^1.4.2", "chai": "^4.3.7", "chalk": "^3.0.0", "decomment": "^0.9.5", diff --git a/packages/bruno-cli/src/runner/interpolate-vars.js b/packages/bruno-cli/src/runner/interpolate-vars.js index 8e0ff300c..88cee00cb 100644 --- a/packages/bruno-cli/src/runner/interpolate-vars.js +++ b/packages/bruno-cli/src/runner/interpolate-vars.js @@ -165,6 +165,13 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc 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; }; diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js index 0ed866760..f031ff0aa 100644 --- a/packages/bruno-cli/src/runner/prepare-request.js +++ b/packages/bruno-cli/src/runner/prepare-request.js @@ -68,6 +68,14 @@ const prepareRequest = (item = {}, collection = {}) => { }; } + 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') { axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`; } diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 29ed749b9..67bda8021 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -23,6 +23,8 @@ const { parseDataFromResponse } = require('../utils/common'); const { getCookieStringForUrl, saveCookies, shouldUseCookies } = require('../utils/cookies'); const { createFormData } = require('../utils/form-data'); const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; +const { NtlmClient } = require('axios-ntlm'); + const onConsoleLog = (type, args) => { console[type](...args); @@ -250,8 +252,13 @@ const runSingleRequest = async function ( let response, responseTime; try { - // run request - const axiosInstance = makeAxiosInstance(); + + let axiosInstance = makeAxiosInstance(); + if (request.ntlmConfig) { + axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance) + delete request.ntlmConfig; + } + if (request.awsv4config) { // todo: make this happen in prepare-request.js diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 7e8e25564..c7a6b369a 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -19,7 +19,9 @@ "test": "node --experimental-vm-modules $(npx which jest)" }, "jest": { - "modulePaths": ["node_modules"] + "modulePaths": [ + "node_modules" + ] }, "dependencies": { "@aws-sdk/credential-providers": "3.658.1", @@ -28,9 +30,11 @@ "@usebruno/lang": "0.12.0", "@usebruno/node-machine-id": "^2.0.0", "@usebruno/schema": "0.7.0", + "@usebruno/vm2": "^3.9.13", "about-window": "^1.15.2", "aws4-axios": "^3.3.0", "axios": "1.7.5", + "axios-ntlm": "^1.4.2", "chai": "^4.3.7", "chokidar": "^3.5.3", "content-disposition": "^0.5.4", @@ -55,7 +59,6 @@ "socks-proxy-agent": "^8.0.2", "tough-cookie": "^4.1.3", "uuid": "^9.0.0", - "@usebruno/vm2": "^3.9.13", "yup": "^0.32.11" }, "optionalDependencies": { diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 782878c59..1865426e0 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -40,6 +40,7 @@ const iconv = require('iconv-lite'); const FormData = require('form-data'); const { createFormData } = require('../../utils/form-data'); const { findItemInCollectionByPathname } = require('../../utils/collection'); +const { NtlmClient } = require('axios-ntlm'); const safeStringifyJSON = (data) => { try { @@ -272,7 +273,15 @@ const configureRequest = async ( ...httpsAgentRequestFields }); } - const axiosInstance = makeAxiosInstance(); + + + let axiosInstance = makeAxiosInstance(); + + if (request.ntlmConfig) { + axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance) + delete request.ntlmConfig; + } + if (request.oauth2) { let requestCopy = cloneDeep(request); diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index d9833f59a..2b46327af 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -231,6 +231,14 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc 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; }; diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 69825bc4e..6c7672e7d 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -5,6 +5,7 @@ const { getTreePathFromCollectionToItem, mergeHeaders, mergeScripts, mergeVars } const { buildFormUrlEncodedPayload, createFormData } = require('../../utils/form-data'); const setAuthHeaders = (axiosRequest, request, collectionRoot) => { + const collectionAuth = get(collectionRoot, 'request.auth'); if (collectionAuth && request.auth.mode === 'inherit') { switch (collectionAuth.mode) { @@ -33,6 +34,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { password: get(collectionAuth, 'digest.password') }; break; + case 'ntlm': + axiosRequest.ntlmConfig = { + username: get(collectionAuth, 'ntlm.username'), + password: get(collectionAuth, 'ntlm.password'), + domain: get(collectionAuth, 'ntlm.domain') + }; + break; case 'wsse': const username = get(request, 'auth.wsse.username', ''); const password = get(request, 'auth.wsse.password', ''); @@ -89,6 +97,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { password: get(request, 'auth.digest.password') }; 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': const grantType = get(request, 'auth.oauth2.grantType'); switch (grantType) { diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 228691c1b..2fe5fb472 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 | 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 bodyforms = bodyformurlencoded | bodymultipart params = paramspath | paramsquery @@ -87,6 +87,7 @@ const grammar = ohm.grammar(`Bru { authbasic = "auth:basic" dictionary authbearer = "auth:bearer" dictionary authdigest = "auth:digest" dictionary + authNTLM = "auth:ntlm" dictionary authOAuth2 = "auth:oauth2" dictionary authwsse = "auth:wsse" dictionary authapikey = "auth:apikey" dictionary @@ -450,6 +451,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) { const auth = mapPairListToKeyValPairs(dictionary.ast, false); const grantTypeKey = _.find(auth, { name: 'grant_type' }); diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index 5180f0193..61d373d91 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -4,7 +4,7 @@ const { outdentString } = require('../../v1/src/utils'); const grammar = ohm.grammar(`Bru { 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" st = " " | "\\t" @@ -42,6 +42,7 @@ const grammar = ohm.grammar(`Bru { authbasic = "auth:basic" dictionary authbearer = "auth:bearer" dictionary authdigest = "auth:digest" dictionary + authNTLM = "auth:ntlm" dictionary authOAuth2 = "auth:oauth2" dictionary authwsse = "auth:wsse" 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) { const auth = mapPairListToKeyValPairs(dictionary.ast, false); const grantTypeKey = _.find(auth, { name: 'grant_type' }); diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index 5c8a573b6..62b31c2f9 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -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) { switch (auth?.oauth2?.grantType) { case 'password': diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js index 8b162b7a6..c2a843dc6 100644 --- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -120,6 +120,17 @@ ${indentString(`username: ${auth.digest.username}`)} ${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}`)} + +} + `; } diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 3d5959f15..b6e044ae4 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -127,6 +127,17 @@ const authDigestSchema = Yup.object({ .noUnknown(true) .strict(); + + + const authNTLMSchema = Yup.object({ + username: Yup.string().nullable(), + password: Yup.string().nullable(), + domain: Yup.string().nullable() + + }) + .noUnknown(true) + .strict(); + const authApiKeySchema = Yup.object({ key: Yup.string().nullable(), value: Yup.string().nullable(), @@ -195,11 +206,12 @@ const oauth2Schema = Yup.object({ const authSchema = Yup.object({ 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'), awsv4: authAwsV4Schema.nullable(), basic: authBasicSchema.nullable(), bearer: authBearerSchema.nullable(), + ntlm: authNTLMSchema.nullable(), digest: authDigestSchema.nullable(), oauth2: oauth2Schema.nullable(), wsse: authWsseSchema.nullable(),