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);
+ });
});