From f4fd1e755b06d57a4e261e21214770043c9d0ed9 Mon Sep 17 00:00:00 2001 From: martinholden-skillsoft <12408585+martinholden-skillsoft@users.noreply.github.com> Date: Wed, 13 Feb 2019 17:23:58 +0000 Subject: [PATCH] Fixed PasswordDigest Generation (#1039) * Fixed PasswordDigest Generation The WSSE password digest is best calculated from a byte array of the concat of NONCE, CREATED TIMESTAMP and PASSWORD * Added testing for PasswordDigest * Update server-compress-test.js Refactored to ensure the server is running before the test runs * Update utils.js Porting to the Buffer.from() --- lib/security/WSSecurity.js | 2 + lib/utils.js | 9 +- test/security/PasswordDigest.js | 22 +++++ test/server-compress-test.js | 141 ++++++++++++++++++-------------- 4 files changed, 112 insertions(+), 62 deletions(-) create mode 100644 test/security/PasswordDigest.js diff --git a/lib/security/WSSecurity.js b/lib/security/WSSecurity.js index 4ae1348f3..317c8b883 100644 --- a/lib/security/WSSecurity.js +++ b/lib/security/WSSecurity.js @@ -71,6 +71,8 @@ WSSecurity.prototype.toXML = function() { password += "" + nonce + ""; } } else { + /* Specific Testcase for passwordDigest calculation cover this code + /* istanbul ignore next */ password = "" + passwordDigest(nonce, created, this._password) + "" + "" + nonce + ""; } diff --git a/lib/utils.js b/lib/utils.js index 19fa8f0f5..ea2057ad0 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -4,8 +4,13 @@ var crypto = require('crypto'); exports.passwordDigest = function passwordDigest(nonce, created, password) { // digest = base64 ( sha1 ( nonce + created + password ) ) var pwHash = crypto.createHash('sha1'); - var rawNonce = new Buffer(nonce || '', 'base64').toString('binary'); - pwHash.update(rawNonce + created + password); + + var NonceBytes = Buffer.from(nonce || '', 'base64'); + var CreatedBytes = Buffer.from(created || '','utf8'); + var PasswordBytes = Buffer.from(password || '', 'utf8'); + var FullBytes = Buffer.concat([NonceBytes, CreatedBytes, PasswordBytes ]); + + pwHash.update(FullBytes); return pwHash.digest('base64'); }; diff --git a/test/security/PasswordDigest.js b/test/security/PasswordDigest.js new file mode 100644 index 000000000..43ae4c20b --- /dev/null +++ b/test/security/PasswordDigest.js @@ -0,0 +1,22 @@ +'use strict'; + +var Utils = require('../../lib/utils'), + assert = require('assert'); + +describe('PasswordDigest', function () { + + var nonce = "2FW1CIo2ZUOJmSjVRcJZlQ=="; + var created = "2019-02-12T12:34:12.110Z"; + var password = "vM3s1hKVMy6zBOn"; + var expected = "wM9xjA92wCw+QcQI1urjZ6B8+LQ="; + + it('is a function', function () { + Utils.passwordDigest.should.be.type('function'); + }); + + it('should calculate a valid passworddigest ', function () { + + var result = Utils.passwordDigest(nonce, created, password); + assert.equal(result, expected); + }); +}); diff --git a/test/server-compress-test.js b/test/server-compress-test.js index 1b1bb6d88..54c7cded3 100644 --- a/test/server-compress-test.js +++ b/test/server-compress-test.js @@ -17,73 +17,94 @@ var request = fs.readFileSync(path + '/request.xml', 'utf8'); var response = fs.readFileSync(path + '/response.xml', 'utf8'); var service = { - MyService: { - MyServicePort: { - DefaultNamespace: function (args) { - return JSON.parse(json); - } - } - } + MyService: { + MyServicePort: { + DefaultNamespace: function (args) { + return JSON.parse(json); + } + } + } }; describe('SOAP Server', function () { - // This test sends two requests and checks the responses for equality. The - // first request is sent through a soap client. The second request sends the - // same request in gzipped format. - it('should properly handle compression', function (done) { - var server = http.createServer(function (req, res) {}); - var clientResponse, gzipResponse; + // This test sends two requests and checks the responses for equality. The + // first request is sent through a soap client. The second request sends the + // same request in gzipped format. + var server = http.createServer(function (req, res) {}); - // If both arguments are defined, check if they are equal and exit the test. - var check = function (a, b) { - if (a && b) { - assert(a === b); - done(); - } - }; + before(function () { + server.listen(8000); + soap.listen(server, '/wsdl', service, xml); + }); + + after(function () { + server.close(); + }); - server.listen(8000); - soap.listen(server, '/wsdl', service, xml); - soap.createClient(wsdl, { - endpoint: 'http://localhost:8000/wsdl' - }, function (error, client) { - assert(!error); - client.DefaultNamespace(json, function (error, response) { - assert(!error); - clientResponse = client.lastResponse; - check(clientResponse, gzipResponse); - }); - }); + it('should properly handle compression', function (done) { + + var clientResponse, + gzipResponse; - var gzip = zlib.createGzip(); + // If both arguments are defined, check if they are equal and exit the test. + var check = function (a, b) { + if (a && b) { + try { + assert(a === b); + done(); + } catch (e) { + done(e); + } + } + }; - // Construct a request with the appropriate headers. - gzip.pipe(http.request({ - host: 'localhost', - path: '/wsdl', - port: 8000, - method: 'POST', - headers: { - 'content-type': 'text/xml; charset=utf-8', - 'content-encoding': 'gzip', - 'soapaction': '"DefaultNamespace"' - } - }, function (res) { - var body = ''; - res.on('data', function (data) { - // Parse the response body. - body += data; - }); - res.on('end', function () { - gzipResponse = body; - check(clientResponse, gzipResponse); - // Don't forget to close the server. - server.close(); - }); - })); + soap.createClient(wsdl, { + endpoint: 'http://localhost:8000/wsdl' + }, function (error, client) { + try { + assert(!error); + } catch (e) { + done(e); + } + client.DefaultNamespace(json, function (error, response) { + try { + assert(!error); + } catch (e) { + done(e); + } + clientResponse = client.lastResponse; + check(clientResponse, gzipResponse); + }); + }); - // Send the request body through the gzip stream to the server. - gzip.end(request); - }); + var gzip = zlib.createGzip(); + + // Construct a request with the appropriate headers. + gzip.pipe(http.request({ + host: 'localhost', + path: '/wsdl', + port: 8000, + method: 'POST', + headers: { + 'content-type': 'text/xml; charset=utf-8', + 'content-encoding': 'gzip', + 'soapaction': '"DefaultNamespace"' + } + }, function (res) { + var body = ''; + res.on('data', function (data) { + // Parse the response body. + body += data; + }); + res.on('end', function () { + gzipResponse = body; + check(clientResponse, gzipResponse); + // Don't forget to close the server. + }); + })); + + // Send the request body through the gzip stream to the server. + gzip.end(request); + }); });