diff --git a/codegens/curl/lib/index.js b/codegens/curl/lib/index.js index ff6a58eb3..8abc73df6 100644 --- a/codegens/curl/lib/index.js +++ b/codegens/curl/lib/index.js @@ -1,11 +1,15 @@ -var sanitize = require('./util').sanitize, - sanitizeOptions = require('./util').sanitizeOptions, - getUrlStringfromUrlObject = require('./util').getUrlStringfromUrlObject, - addFormParam = require('./util').addFormParam, - form = require('./util').form, - shouldAddHttpMethod = require('./util').shouldAddHttpMethod, - _ = require('./lodash'), - self; +const { + sanitize, + sanitizeOptions, + getUrlStringfromUrlObject, + getNtlmAuthInfo, + addFormParam, + form, + shouldAddHttpMethod + } = require('./util'), + _ = require('./lodash'); + +var self; self = module.exports = { convert: function (request, options, callback) { @@ -16,7 +20,7 @@ self = module.exports = { options = sanitizeOptions(options, self.getOptions()); var indent, trim, headersData, body, redirect, timeout, multiLine, - format, snippet, silent, url, quoteType; + format, snippet, silent, url, quoteType, ntlmAuth; redirect = options.followRedirect; timeout = options.requestTimeoutInSeconds; @@ -26,9 +30,16 @@ self = module.exports = { silent = options.silent; quoteType = options.quoteType === 'single' ? '\'' : '"'; url = getUrlStringfromUrlObject(request.url, quoteType); + ntlmAuth = getNtlmAuthInfo(request.auth, quoteType, format); - snippet = silent ? `curl ${form('-s', format)}` : 'curl'; + snippet = 'curl'; + if (ntlmAuth) { + snippet += ntlmAuth; + } + if (silent) { + snippet += ` ${form('-s', format)}`; + } if (redirect) { snippet += ` ${form('-L', format)}`; } diff --git a/codegens/curl/lib/util.js b/codegens/curl/lib/util.js index c10640085..a3a5d4020 100644 --- a/codegens/curl/lib/util.js +++ b/codegens/curl/lib/util.js @@ -144,14 +144,49 @@ var self = module.exports = { }, /** - * - * @param {*} urlObject The request sdk request.url object - * @param {boolean} quoteType The user given quoteType - * @returns {String} The final string after parsing all the parameters of the url including - * protocol, auth, host, port, path, query, hash - * This will be used because the url.toString() method returned the URL with non encoded query string - * and hence a manual call is made to getQueryString() method with encode option set as true. - */ + * Generates args required for NTLM authentication to happen + * + * @param {*} auth - The request sdk request.auth object + * @param {string} quoteType - user provided option to decide whether to use single or double quotes + * @param {string} format - user provided option to decide whether to use long format or not + * @returns {string} - The string to be added if NTLM auth is required + */ + getNtlmAuthInfo: function (auth, quoteType, format) { + const ntlmAuth = auth && auth.ntlm; + + if (!auth || auth.type !== 'ntlm' || !ntlmAuth || !ntlmAuth.count || !ntlmAuth.count()) { + return ''; + } + + const username = ntlmAuth.has('username') && ntlmAuth.get('username'), + password = ntlmAuth.has('password') && ntlmAuth.get('password'), + domain = ntlmAuth.has('domain') && ntlmAuth.get('domain'); + + if (!username && !password) { + return ''; + } + + var userArg = format ? '--user ' : '-u ', + ntlmString = ' --ntlm ' + userArg + quoteType; + + if (domain) { + ntlmString += self.sanitize(domain, true, quoteType) + '\\'; + } + ntlmString += self.sanitize(username, true, quoteType) + ':' + self.sanitize(password, true, quoteType); + ntlmString += quoteType; + + return ntlmString; + }, + + /** + * + * @param {*} urlObject The request sdk request.url object + * @param {boolean} quoteType The user given quoteType + * @returns {String} The final string after parsing all the parameters of the url including + * protocol, auth, host, port, path, query, hash + * This will be used because the url.toString() method returned the URL with non encoded query string + * and hence a manual call is made to getQueryString() method with encode option set as true. + */ getUrlStringfromUrlObject: function (urlObject, quoteType) { var url = ''; if (!urlObject) { diff --git a/codegens/curl/test/unit/convert.test.js b/codegens/curl/test/unit/convert.test.js index ffe46396e..849395a5e 100644 --- a/codegens/curl/test/unit/convert.test.js +++ b/codegens/curl/test/unit/convert.test.js @@ -1,4 +1,5 @@ -var expect = require('chai').expect, +var _ = require('lodash'), + expect = require('chai').expect, { Request } = require('postman-collection/lib/collection/request'), { Url } = require('postman-collection/lib/collection/url'), convert = require('../../index').convert, @@ -1026,5 +1027,122 @@ describe('curl convert function', function () { }); }); }); + + describe('should correctly handle NTLM auth', function () { + const sampleRequest = { + 'method': 'POST', + 'header': [], + 'auth': { + 'type': 'ntlm', + 'ntlm': [] + }, + 'url': { + 'raw': 'https://postman-echo.com/post', + 'protocol': 'https', + 'host': [ + 'postman-echo', + 'com' + ], + 'path': [ + 'post' + ] + } + }; + + it('when no username or password is present', function () { + const request = new Request(sampleRequest); + + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('--ntlm'); + }); + }); + + it('when empty username and password is present', function () { + const request = new Request(Object.assign({ auth: { + 'type': 'ntlm', + 'ntlm': [ + {key: 'username', value: ''}, + {key: 'password', value: ''} + ] + }}, sampleRequest)); + + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.not.include('--ntlm'); + }); + }); + + it('when correct username and password is present with single quotes as option', function () { + const request = new Request(_.set(sampleRequest, 'auth.ntlm', [ + {key: 'username', value: 'joh\'n'}, + {key: 'password', value: 'tennesse"e'} + ])); + + convert(request, { quoteType: 'single' }, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.equal('curl --ntlm --user \'joh\'\\\'\'n:tennesse"e\' --location' + + ' --request POST \'https://postman-echo.com/post\''); + }); + }); + + it('when correct username and password is present with double as option', function () { + const request = new Request(_.set(sampleRequest, 'auth.ntlm', [ + {key: 'username', value: 'joh\'n'}, + {key: 'password', value: 'tennesse"e'} + ])); + + convert(request, { quoteType: 'double' }, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.equal('curl --ntlm --user "joh\'n:tennesse\\"e" --location' + + ' --request POST "https://postman-echo.com/post"'); + }); + }); + + it('when correct username and password is present with long format option disabled', function () { + const request = new Request(_.set(sampleRequest, 'auth.ntlm', [ + {key: 'username', value: 'joh\'n'}, + {key: 'password', value: 'tennesse"e'} + ])); + + convert(request, { longFormat: false }, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.equal('curl --ntlm -u \'joh\'\\\'\'n:tennesse"e\' -L' + + ' -X POST \'https://postman-echo.com/post\''); + }); + }); + + it('when username and password is present with domain as well', function () { + const request = new Request(_.set(sampleRequest, 'auth.ntlm', [ + {key: 'username', value: 'joh\'n'}, + {key: 'password', value: 'tennesse"e'}, + {key: 'domain', value: 'radio'} + ])); + + convert(request, {}, function (error, snippet) { + if (error) { + expect.fail(null, null, error); + } + expect(snippet).to.be.a('string'); + expect(snippet).to.equal('curl --ntlm --user \'radio\\joh\'\\\'\'n:tennesse"e\' --location' + + ' --request POST \'https://postman-echo.com/post\''); + }); + }); + }); }); });