strong-soap
Version:
A minimal node SOAP client
88 lines (86 loc) • 4.15 kB
JavaScript
// Copyright IBM Corp. 2016,2018. All Rights Reserved.
// Node module: strong-soap
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var NodeRsa = require('node-rsa');
var SignedXml = require('xml-crypto').SignedXml;
var uuid = require('uuid');
var Security = require('./security');
var xmlHandler = require('../parser/xmlHandler');
var crypto = require('crypto');
function addMinutes(date, minutes) {
return new Date(date.getTime() + minutes * 60000);
}
function dateStringForSOAP(date) {
return date.getUTCFullYear() + '-' + ('0' + (date.getUTCMonth() + 1)).slice(-2) + '-' + ('0' + date.getUTCDate()).slice(-2) + 'T' + ('0' + date.getUTCHours()).slice(-2) + ":" + ('0' + date.getUTCMinutes()).slice(-2) + ":" + ('0' + date.getUTCSeconds()).slice(-2) + "Z";
}
function generateCreated() {
return dateStringForSOAP(new Date());
}
function generateExpires() {
return dateStringForSOAP(addMinutes(new Date(), 10));
}
function generateId() {
return uuid.v4().replace(/-/gm, '');
}
class WSSecurityCert extends Security {
constructor(privatePEM, publicP12PEM, password) {
super();
this.publicP12PEM = publicP12PEM.toString().replace('-----BEGIN CERTIFICATE-----', '').replace('-----END CERTIFICATE-----', '').replace(/(\r\n|\n|\r)/gm, '');
this.signer = new SignedXml();
this.signer.signingKey = this.getSigningKey(privatePEM, password);
this.x509Id = 'x509-' + generateId();
var references = ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'];
this.signer.addReference('//*[local-name(.)=\'Body\']', references);
this.signer.addReference('//*[local-name(.)=\'Timestamp\']', references);
var _this = this;
this.signer.keyInfoProvider = {};
this.signer.keyInfoProvider.getKeyInfo = function (key) {
var x509Id = _this.x509Id;
var xml = `<wsse:SecurityTokenReference>
<wsse:Reference URI="${x509Id}" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>`;
return xml;
};
}
getSigningKey(privatePEM, password) {
if (typeof crypto.createPrivateKey === 'function') {
// Node 11 or above
this.privateKey = crypto.createPrivateKey({
key: privatePEM,
passphrase: password
});
return this.privateKey.export({
type: 'pkcs1',
format: 'pem'
});
} else {
// Node 10 or below, fall back to https://github.com/rzcoder/node-rsa
if (password) throw new Error('Passphrase is not supported by node-rsa.');
this.privateKey = new NodeRsa(privatePEM);
return this.privateKey.exportKey('private');
}
}
postProcess(headerElement, bodyElement) {
this.created = generateCreated();
this.expires = generateExpires();
var binaryToken = this.publicP12PEM,
created = this.created,
expires = this.expires,
id = this.x509Id;
var secElement = headerElement.element('wsse:Security').attribute('xmlns:wsse', 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-wssecurity-secext-1.0.xsd').attribute('xmlns:wsu', 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-wssecurity-utility-1.0.xsd').attribute('soap:mustUnderstand', '1');
secElement.element('wsse:BinarySecurityToken').attribute('EncodingType', 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-soap-message-security-1.0#Base64Binary').attribute('ValueType', 'http://docs.oasis-open.org/wss/2004/01/' + 'oasis-200401-wss-x509-token-profile-1.0#X509v3').attribute('wsu:Id', id).text(binaryToken);
var tsElement = secElement.element('wsu:Timestamp').attribute('wsu:Id', '_1');
tsElement.element('wsu:Created', created);
tsElement.element('wsu:Expires', expires);
var xmlWithSec = headerElement.doc().end({
pretty: true
});
this.signer.computeSignature(xmlWithSec);
var sig = this.signer.getSignatureXml();
xmlHandler.parseXml(secElement, sig);
}
}
module.exports = WSSecurityCert;
//# sourceMappingURL=WSSecurityCert.js.map