Skip to content

Commit

Permalink
Fixed PasswordDigest Generation (#1039)
Browse files Browse the repository at this point in the history
* 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()
  • Loading branch information
martinholden-skillsoft authored and jsdevel committed Feb 13, 2019
1 parent 570f5b3 commit f4fd1e7
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 62 deletions.
2 changes: 2 additions & 0 deletions lib/security/WSSecurity.js
Expand Up @@ -71,6 +71,8 @@ WSSecurity.prototype.toXML = function() {
password += "<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + nonce + "</wsse:Nonce>";
}
} else {
/* Specific Testcase for passwordDigest calculation cover this code
/* istanbul ignore next */
password = "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + passwordDigest(nonce, created, this._password) + "</wsse:Password>" +
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + nonce + "</wsse:Nonce>";
}
Expand Down
9 changes: 7 additions & 2 deletions lib/utils.js
Expand Up @@ -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');
};

Expand Down
22 changes: 22 additions & 0 deletions 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);
});
});
141 changes: 81 additions & 60 deletions test/server-compress-test.js
Expand Up @@ -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);
});
});

0 comments on commit f4fd1e7

Please sign in to comment.