Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

soap

Package Overview
Dependencies
Maintainers
3
Versions
97
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

soap - npm Package Compare versions

Comparing version 0.4.2 to 0.4.4

lib/security/BasicAuthSecurity.js

26

History.md

@@ -0,3 +1,29 @@

0.4.4 / 2014-04-16
=================
* Added namespace prefixes to SOAP headers. #307
* Provided more documentation around security protocols in the README. #321
* Added lodash. #321
* Added a default parameter to ClientSSLSecurity. #321
* Fix to reset the generated namespace number. #308
* Fixed maximum callstack errors on certain responses. #257
0.4.3 / 2014-04-07
=================
* Refactored WS-security. small modifications to pull #275
* Updated readme to add documentation for passing options to a client request
* Added null check for portType and methods[methodname].output
* Fixed issue where requests that included compex types led to invalid request XML.
* Support for attributes array elements and support for complex extensions with array elements.
* Make sure callback is done asynchronously for a cached wsdl
* Added WSDL inheritance support (#133).
0.4.2 / 2014-03-13
=================
* Added the ability to inspect and clear soap headers.
* Reducing test wsdl size.
* No longer prefixing elements with a default namespace prefix i.e. xmlns.
0.4.1 / 2014-03-04
=================
Note: an error occurred publishing this version to npm. This version was tagged, so it can be referrenced via git.
* package; increased minor version to 0.4.1

@@ -4,0 +30,0 @@ * Adding an npmignore on test/

12

lib/client.js

@@ -90,3 +90,3 @@ /*

var self = this;
return function(args, callback, options) {
return function(args, callback, options, extraHeaders) {
if (typeof args === 'function') {

@@ -98,7 +98,7 @@ callback = args;

callback(error, result, raw);
}, options);
}, options, extraHeaders);
};
};
Client.prototype._invoke = function(method, args, location, callback, options) {
Client.prototype._invoke = function(method, args, location, callback, options, extraHeaders) {
var self = this,

@@ -123,2 +123,5 @@ name = method.$name,

//Add extra headers
for (var attr in extraHeaders) { headers[attr] = extraHeaders[attr]; }
// Allow the security object to add headers

@@ -142,2 +145,3 @@ if (self.security && self.security.addHeaders)

"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
encoding +

@@ -154,2 +158,3 @@ this.wsdl.xmlnsInEnvelope + '>' +

self.lastMessage = message;
self.lastRequest = xml;

@@ -162,2 +167,3 @@

self.lastResponseHeaders = response && response.headers;
if (err) {

@@ -164,0 +170,0 @@ callback(err);

@@ -10,7 +10,6 @@ /*

Server = require('./server').Server,
security = require('./security'),
passwordDigest = require('./utils').passwordDigest,
open_wsdl = require('./wsdl').open_wsdl,
crypto = require('crypto'),
WSDL = require('./wsdl').WSDL,
https = require('https'),
fs = require('fs');
WSDL = require('./wsdl').WSDL;

@@ -28,3 +27,5 @@ var WSDL = require('./wsdl').WSDL;

if (wsdl) {
callback(null, wsdl);
process.nextTick(function() {
callback(null, wsdl);
});
}

@@ -69,88 +70,6 @@ else {

function BasicAuthSecurity(username, password) {
this._username = username;
this._password = password;
}
BasicAuthSecurity.prototype.addHeaders = function(headers) {
headers.Authorization = "Basic " + new Buffer((this._username + ':' + this._password) || '').toString('base64');
};
BasicAuthSecurity.prototype.toXML = function() {
return "";
};
function ClientSSLSecurity(keyPath, certPath) {
this.key = fs.readFileSync(keyPath);
this.cert = fs.readFileSync(certPath);
}
ClientSSLSecurity.prototype.toXML = function(headers) {
return "";
};
ClientSSLSecurity.prototype.addOptions = function(options) {
options.key = this.key;
options.cert = this.cert;
options.agent = new https.Agent(options);
};
function WSSecurity(username, password, passwordType) {
this._username = username;
this._password = password;
this._passwordType = passwordType || 'PasswordText';
}
var passwordDigest = function(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 passwordDigest = pwHash.digest('base64');
return passwordDigest;
};
WSSecurity.prototype.toXML = function() {
// avoid dependency on date formatting libraries
function getDate(d) {
function pad(n) {
return n < 10 ? '0' + n : n;
}
return d.getUTCFullYear() + '-'
+ pad(d.getUTCMonth() + 1) + '-'
+ pad(d.getUTCDate()) + 'T'
+ pad(d.getUTCHours()) + ':'
+ pad(d.getUTCMinutes()) + ':'
+ pad(d.getUTCSeconds()) + 'Z';
}
var now = new Date();
var created = getDate(now);
var expires = getDate(new Date(now.getTime() + (1000 * 600)));
// nonce = base64 ( sha1 ( created + random ) )
var nHash = crypto.createHash('sha1');
nHash.update(created + Math.random());
var nonce = nHash.digest('base64');
return "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
"<wsu:Timestamp wsu:Id=\"Timestamp-" + created + "\">" +
"<wsu:Created>" + created + "</wsu:Created>" +
"<wsu:Expires>" + expires + "</wsu:Expires>" +
"</wsu:Timestamp>" +
"<wsse:UsernameToken xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"SecurityToken-" + created + "\">" +
"<wsse:Username>" + this._username + "</wsse:Username>" +
(this._passwordType === 'PasswordText' ?
"<wsse:Password>" + this._password + "</wsse: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>" +
"<wsu:Created>" + created + "</wsu:Created>" +
"</wsse:UsernameToken>" +
"</wsse:Security>";
};
exports.BasicAuthSecurity = BasicAuthSecurity;
exports.WSSecurity = WSSecurity;
exports.ClientSSLSecurity = ClientSSLSecurity;
exports.security = security;
exports.BasicAuthSecurity = security.BasicAuthSecurity;
exports.WSSecurity = security.WSSecurity;
exports.ClientSSLSecurity = security.ClientSSLSecurity;
exports.createClient = createClient;

@@ -157,0 +76,0 @@ exports.passwordDigest = passwordDigest;

@@ -480,24 +480,24 @@ /*

children = this.children;
if (portType){
portType.postProcess(definitions);
this.methods = portType.methods;
// delete portType.methods; both binding and portType should keep the same set of operations
portType.postProcess(definitions);
this.methods = portType.methods;
// delete portType.methods; both binding and portType should keep the same set of operations
for (var i = 0, child; child = children[i]; i++) {
if (child.name !== 'operation')
continue;
child.postProcess(definitions, 'binding');
children.splice(i--, 1);
child.style || (child.style = style);
var method = this.methods[child.$name];
method.style = child.style;
method.soapAction = child.soapAction;
method.inputSoap = child.input || null;
method.outputSoap = child.output || null;
method.inputSoap && method.inputSoap.deleteFixedAttrs();
method.outputSoap && method.outputSoap.deleteFixedAttrs();
// delete method.$name; client will use it to make right request for top element name in body
// method.deleteFixedAttrs(); why ???
for (var i = 0, child; child = children[i]; i++) {
if (child.name !== 'operation')
continue;
child.postProcess(definitions, 'binding');
children.splice(i--, 1);
child.style || (child.style = style);
var method = this.methods[child.$name];
method.style = child.style;
method.soapAction = child.soapAction;
method.inputSoap = child.input || null;
method.outputSoap = child.output || null;
method.inputSoap && method.inputSoap.deleteFixedAttrs();
method.outputSoap && method.outputSoap.deleteFixedAttrs();
// delete method.$name; client will use it to make right request for top element name in body
// method.deleteFixedAttrs(); why ???
}
}
delete this.$name;

@@ -583,3 +583,13 @@ delete this.$type;

if (typeElement && !(typeName in Primitives)) {
element[name] = typeElement.description(definitions);
if (!(typeName in definitions.descriptions.types)) {
var t = {};
definitions.descriptions.types[typeName] = t;
element[name] = t = typeElement.description(definitions);
definitions.descriptions.types[typeName] = element[name];
}
else {
element[name] = definitions.descriptions.types[typeName];
}
}

@@ -710,3 +720,5 @@ else

var inputName = methods[methodName].input.$name;
var outputName = methods[methodName].output.$name;
var outputName="";
if(methods[methodName].output )
outputName = methods[methodName].output.$name;
topEls[inputName] = {"methodName": methodName, "outputName": outputName};

@@ -990,2 +1002,5 @@ }

var parameterTypeObj = type ? this.findParameterObject(xmlns, type) : null;
if (this.namespaceNumber) {
this.namespaceNumber = 0;
}
return this.objectToXML(args, null, ns, xmlns, true, null, parameterTypeObj);

@@ -1009,3 +1024,3 @@ };

parts.push(['<', key, '>'].join(''));
parts.push((typeof value === 'object') ? this.objectToXML(value) : xmlEscape(value));
parts.push((typeof value === 'object') ? this.objectToXML(value, key, namespace, xmlns) : xmlEscape(value));
parts.push(['</', key, '>'].join(''));

@@ -1033,12 +1048,11 @@ }

}
var ns = namespace && namespace !== 'xmlns' ? namespace + ':' : '';
var ns = namespace && namespace !== 'xmlns' ? (namespace.indexOf(":") === -1 ? namespace + ':' : namespace) : '';
if (Array.isArray(obj)) {
for (var i = 0, item; item = obj[i]; i++) {
if (i > 0) {
parts.push(['</', ns, name, '>'].join(''));
parts.push(['<', ns, name, xmlnsAttrib, '>'].join(''));
}
parts.push(self.objectToXML(item, name, namespace, xmlns));
var arrayAttr = self.processAttributes(item);
parts.push(['<', ns, name, arrayAttr, xmlnsAttrib, '>'].join(''));
parts.push(self.objectToXML(item, name, namespace, xmlns, false, null, null, ancXmlns));
parts.push(['</', ns, name, '>'].join(''));
}

@@ -1053,9 +1067,23 @@ } else if (typeof obj === 'object') {

var child = obj[name];
if (child.attributes && child.attributes.xsi_type) {
var xsiType = child.attributes.xsi_type;
// Generate a new namespace for complex extension if one not provided
if (!xsiType.namespace) {
if (self.namespaceNumber) {
self.namespaceNumber++;
} else {
self.namespaceNumber = 1;
}
xsiType.namespace = 'ns' + self.namespaceNumber;
}
}
var attr = self.processAttributes(child);
parts.push(['<', ns, name, attr, xmlnsAttrib, '>'].join(''));
var value = '';
if (first) {
parts.push(self.objectToXML(child, name, namespace, xmlns, false, null, parameterTypeObject, ancXmlns));
value = self.objectToXML(child, name, namespace, xmlns, false, null, parameterTypeObject, ancXmlns);
} else {
if (self.definitions.schemas) {

@@ -1066,8 +1094,11 @@ var schema = this.definitions.schemas[xmlns];

var childParameterTypeObject = self.findChildParameterObject(parameterTypeObject, name);
if (childParameterTypeObject) {
//find sub namespace if not a primitive
if (childParameterTypeObject && childParameterTypeObject.$type && (childParameterTypeObject.$type.indexOf('xsd') === -1)) {
var childParameterType = childParameterTypeObject.$type;
var childNamespace = '';
var childName = '';
if (childParameterType.indexOf(':') !== -1) {
childNamespace = childParameterType.substring(0, childParameterType.indexOf(':'));
childName = childParameterType.substring(childParameterType.indexOf(':') + 1);
}

@@ -1082,11 +1113,27 @@ var childXmlns = schema.xmlns[childNamespace];

parts.push(self.objectToXML(child, name, childNamespace, childXmlns, false, childXmlnsAttrib, childParameterTypeObject));
var completeChildParameterTypeObject = self.findChildParameterObjectFromSchema(childName, childXmlns) || childParameterTypeObject;
value = self.objectToXML(child, name, childNamespace, childXmlns, false, childXmlnsAttrib, completeChildParameterTypeObject, ancXmlns);
} else if (obj.attributes && obj.attributes.xsi_type) { //if parent object has complex type defined and child not found in parent
var completeChildParamTypeObject = self.findChildParameterObjectFromSchema(obj.attributes.xsi_type.type, obj.attributes.xsi_type.xmlns);
ns = obj.attributes.xsi_type.namespace + ':';
ancXmlns.push(obj.attributes.xsi_type.xmlns);
value = self.objectToXML(child, name, obj.attributes.xsi_type.namespace, obj.attributes.xsi_type.xmlns, false, null, null, ancXmlns);
} else {
parts.push(self.objectToXML(child, name, namespace, xmlns));
value = self.objectToXML(child, name, namespace, xmlns, false, null, null, ancXmlns);
}
} else {
value = self.objectToXML(child, name, namespace, xmlns, false, null, null, ancXmlns);
}
}
}
if (!Array.isArray(child)) {
parts.push(['<', ns, name, attr, xmlnsAttrib, '>'].join(''));
}
parts.push(['</', ns, name, '>'].join(''));
parts.push(value);
if (!Array.isArray(child)) {
parts.push(['</', ns, name, '>'].join(''));
}
}

@@ -1103,3 +1150,12 @@ } else if (obj !== undefined) {

for (var attrKey in child.attributes) {
attr += ' ' + attrKey + '="' + xmlEscape(child.attributes[attrKey]) + '"';
//handle complex extension separately
if (attrKey === 'xsi_type') {
var attrValue = child.attributes[attrKey];
attr += ' xsi:type="' + attrValue.namespace + ':' + attrValue.type + '"';
attr += ' xmlns:' + attrValue.namespace + '="' + attrValue.xmlns + '"';
continue;
} else {
attr += ' ' + attrKey + '="' + xmlEscape(child.attributes[attrKey]) + '"';
}
}

@@ -1111,2 +1167,15 @@ }

WSDL.prototype.findChildParameterObjectFromSchema = function(name, xmlns) {
if (!this.definitions.schemas || !name || !xmlns) {
return null;
}
var schema = this.definitions.schemas[xmlns];
if (!schema || !schema.complexTypes) {
return null;
}
return schema.complexTypes[name];
};
WSDL.prototype.findChildParameterObject = function(parameterTypeObj, childName) {

@@ -1183,2 +1252,5 @@ if (!parameterTypeObj || !childName) {

this.definitions = this._parse(xml);
this.definitions.descriptions = {
types:{}
};
this.xml = xml;

@@ -1262,2 +1334,1 @@ };

{
"name": "soap",
"version": "0.4.2",
"version": "0.4.4",
"description": "A minimal node SOAP client",

@@ -11,3 +11,4 @@ "engines": {

"sax": ">=0.6",
"request": ">=2.9.0"
"request": ">=2.9.0",
"lodash": "~2.4.1"
},

@@ -23,3 +24,3 @@ "repository": {

"scripts": {
"mocha": "mocha -R spec -u exports test/*-test.js",
"mocha": "mocha test/*-test.js test/security/*.js",
"jshint": "jshint index.js lib test",

@@ -40,4 +41,5 @@ "test": "npm run-script jshint && npm run-script mocha"

"jshint": "~2.4.2",
"glob": "~3.2.8"
"glob": "~3.2.8",
"should": "~3.3.0"
}
}

@@ -48,3 +48,3 @@ This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services.

// This is how to define an asynchronous function.
// This is how to define an asynchronous function.
MyAsyncFunction: function(args, callback) {

@@ -130,5 +130,34 @@ // do some work

### Client.setSecurity(security) - use the specified security protocol (see WSSecurity below)
### Client.setSecurity(security) - use the specified security protocol
`node-soap` has several default security protocols. You can easily add your own
as well. The interface is quite simple. Each protocol defines 2 methods:
* addOptions - a method that accepts an options arg that is eventually passed directly to `request`
* toXML - a method that reurns a string of XML.
By default there are 3 protocols:
####BasicAuthSecurity
``` javascript
client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));
```
####ClientSSLSecurity
_Note_: If you run into issues using this protocol, consider passing these options
as default request options to the constructor:
* rejectUnauthorized: false
* strictSSL: false
* secureOptions: constants.SSL_OP_NO_TLSv1_2//this is likely needed for node >= 10.0
``` javascript
client.setSecurity(new soap.ClientSSLSecurity(
'/path/to/key'
, '/path/to/cert'
, {/*default request options*/}
));
```
####WSSecurity
``` javascript
client.setSecurity(new WSSecurity('username', 'password'))

@@ -144,3 +173,3 @@ ```

```
### Client.*service*.*port*.*method*(args, callback) - call a *method* using a specific *service* and *port*
### Client.*service*.*port*.*method*(args, callback[, options]) - call a *method* using a specific *service* and *port*

@@ -152,2 +181,11 @@ ``` javascript

```
+#### Options (optional)
- Accepts any option that the request module accepts, see [here.](https://github.com/mikeal/request)
- For example, you could set a timeout of 5 seconds on the request like this:
``` javascript
client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
// result is a javascript object
}, {timeout: 5000})
```
### Client.*addSoapHeader*(soapHeader[, name, namespace, xmlns]) - add soapHeader to soap:Header node

@@ -154,0 +192,0 @@ #### Options

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc