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.24.0 to 0.25.0

lib/security/NTLMSecurity.js

17

History.md

@@ -0,1 +1,18 @@

0.25.0 / 2018-08-19
===================
* [FIX] Improved deserialization on inline `simpleType` declarations (#1015)
* [ENHANCEMENT] Added option to allow the user to dis-/enable the timestamp in `WSSecurtityCert` (defaults to "enabled" to maintain current behaviour) (#1017)
* [DOC] Updated the "*Async" result description (#1016)
* [ENHANCEMENT] Added ability to resolve Schema-cross-reference namespaces in `client.describe()` (#1014)
* [FIX] Fixed `.npmignore` patterns in order to publish only the necessary files (#1012)
* [DOC] Removed formatting in code (#1011)
* [ENHANCEMENT] Added initial NTLM support (#887)
* [ENHANCEMENT] Added optional async authentication for the server (#1002)
* [MAINTENANCE] End of support for `node < 6.x` in our Travis CI config!
* [MAINTENANCE] Removed unnecessary `selectn` dependency (#975)
* [ENHANCEMNET] Added support for attributes in root elements (#910)
* [ENHANCEMENT] Added/updated TypeScript definitions (#991)
* [ENHANCEMENT] Change signature of `server.authorizeConnection()` to include also the `res`ponse param. (#1006)
* [FIX] WSSE Template - fix behaviour for template compilation in `__dirname` "unsafe" environments (e.g. `webpack` with target `node`) (#1008)
0.24.0 / 2018-04-05

@@ -2,0 +19,0 @@ ===================

0

index.js
"use strict";
module.exports = require('./lib/soap');

2

lib/client.js

@@ -430,3 +430,3 @@ /*

// Added mostly for testability, but possibly useful for debugging
if(req && req.headers) //fixes an issue when req or req.headers is indefined
if(req && req.headers && !options.ntlm) //fixes an issue when req or req.headers is undefined, doesn't apply to ntlm requests
self.lastRequestHeaders = req.headers;

@@ -433,0 +433,0 @@ };

@@ -11,2 +11,3 @@ /*

var debug = require('debug')('node-soap');
var httpNtlm = require('httpntlm');

@@ -113,10 +114,30 @@ var VERSION = require('../package.json').version;

var options = self.buildRequest(rurl, data, exheaders, exoptions);
var req = self._request(options, function(err, res, body) {
if (err) {
return callback(err);
}
body = self.handleResponse(req, res, body);
callback(null, res, body);
});
var req;
if (exoptions !== undefined && exoptions.hasOwnProperty('ntlm')) {
// sadly when using ntlm nothing to return
// Not sure if this can be handled in a cleaner way rather than an if/else,
// will to tidy up if I get chance later, patches welcome - insanityinside
options.url = rurl;
httpNtlm[options.method.toLowerCase()](options, function (err, res) {
if (err) {
return callback(err);
}
// if result is stream
if( typeof res.body !== 'string') {
res.body = res.body.toString();
}
res.body = self.handleResponse(req, res, res.body);
callback(null, res, res.body);
});
} else {
req = self._request(options, function (err, res, body) {
if (err) {
return callback(err);
}
body = self.handleResponse(req, res, body);
callback(null, res, body);
});
}
return req;

@@ -123,0 +144,0 @@ };

@@ -0,0 +0,0 @@ 'use strict';

@@ -0,0 +0,0 @@ "use strict";

@@ -0,0 +0,0 @@ "use strict";

@@ -0,0 +0,0 @@ 'use strict';

@@ -0,0 +0,0 @@ 'use strict';

@@ -5,2 +5,3 @@ "use strict";

BasicAuthSecurity: require('./BasicAuthSecurity')
, NTLMSecurity: require('./NTLMSecurity')
, ClientSSLSecurity: require('./ClientSSLSecurity')

@@ -7,0 +8,0 @@ , ClientSSLSecurityPFX: require('./ClientSSLSecurityPFX')

@@ -0,0 +0,0 @@ "use strict";

@@ -8,4 +8,4 @@ "use strict";

var uuid4 = require('uuid/v4');
var wsseSecurityHeaderTemplate = ejs.compile(fs.readFileSync(path.join(__dirname, 'templates', 'wsse-security-header.ejs')).toString());
var wsseSecurityTokenTemplate = ejs.compile(fs.readFileSync(path.join(__dirname, 'templates', 'wsse-security-token.ejs')).toString());
var wsseSecurityHeaderTemplate;
var wsseSecurityTokenTemplate;

@@ -38,3 +38,4 @@ function addMinutes(date, minutes) {

function WSSecurityCert(privatePEM, publicP12PEM, password) {
function WSSecurityCert(privatePEM, publicP12PEM, password, options) {
options = options || {};
this.publicP12PEM = publicP12PEM.toString().replace('-----BEGIN CERTIFICATE-----', '').replace('-----END CERTIFICATE-----', '').replace(/(\r\n|\n|\r)/gm, '');

@@ -48,2 +49,5 @@

this.x509Id = "x509-" + generateId();
this.hasTimeStamp = typeof options.hasTimeStamp === 'undefined' ? true : !!options.hasTimeStamp;
this.signatureTransformations = Array.isArray(options.signatureTransformations) ? options.signatureTransformations
: ["http://www.w3.org/2000/09/xmldsig#enveloped-signature", "http://www.w3.org/2001/10/xml-exc-c14n#"];

@@ -53,2 +57,6 @@ var _this = this;

this.signer.keyInfoProvider.getKeyInfo = function (key) {
if (!wsseSecurityTokenTemplate) {
wsseSecurityTokenTemplate = ejs.compile(fs.readFileSync(path.join(__dirname, 'templates', 'wsse-security-token.ejs')).toString());
}
return wsseSecurityTokenTemplate({ x509Id: _this.x509Id });

@@ -62,2 +70,6 @@ };

if (!wsseSecurityHeaderTemplate) {
wsseSecurityHeaderTemplate = ejs.compile(fs.readFileSync(path.join(__dirname, 'templates', 'wsse-security-header.ejs')).toString());
}
var secHeader = wsseSecurityHeaderTemplate({

@@ -67,2 +79,3 @@ binaryToken: this.publicP12PEM,

expires: this.expires,
hasTimeStamp: this.hasTimeStamp,
id: this.x509Id

@@ -73,8 +86,10 @@ });

var references = ["http://www.w3.org/2000/09/xmldsig#enveloped-signature",
"http://www.w3.org/2001/10/xml-exc-c14n#"];
var references = this.signatureTransformations;
this.signer.addReference("//*[name(.)='" + envelopeKey + ":Body']", references);
this.signer.addReference("//*[name(.)='wsse:Security']/*[local-name(.)='Timestamp']", references);
if (this.hasTimeStamp) {
this.signer.addReference("//*[name(.)='wsse:Security']/*[local-name(.)='Timestamp']", references);
}
this.signer.computeSignature(xmlWithSec);

@@ -81,0 +96,0 @@

@@ -51,3 +51,3 @@ /*

if (typeof self.authorizeConnection === 'function') {
if (!self.authorizeConnection(req)) {
if (!self.authorizeConnection(req, res)) {
res.end();

@@ -64,3 +64,3 @@ return;

if (typeof self.authorizeConnection === 'function') {
if (!self.authorizeConnection(req)) {
if (!self.authorizeConnection(req, res)) {
res.end();

@@ -242,99 +242,145 @@ return;

serviceName, portName,
includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp;
includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp,
authenticate = self.authenticate || function defaultAuthenticate() { return true; };
if (typeof self.authenticate === 'function') {
if (!obj.Header || !obj.Header.Security) {
throw new Error('No security header');
function process() {
if (typeof self.log === 'function') {
self.log("info", "Attempting to bind to " + pathname);
}
if (!self.authenticate(obj.Header.Security)) {
throw new Error('Invalid username or password');
//Avoid Cannot convert undefined or null to object due to Object.keys(body)
//and throw more meaningful error
if (!body) {
throw new Error('Failed to parse the SOAP Message body');
}
}
if (typeof self.log === 'function') {
self.log("info", "Attempting to bind to " + pathname);
}
// use port.location and current url to find the right binding
binding = (function () {
var services = self.wsdl.definitions.services;
var firstPort;
var name;
for (name in services) {
serviceName = name;
var service = services[serviceName];
var ports = service.ports;
for (name in ports) {
portName = name;
var port = ports[portName];
var portPathname = url.parse(port.location).pathname.replace(/\/$/, '');
//Avoid Cannot convert undefined or null to object due to Object.keys(body)
//and throw more meaningful error
if (!body) {
throw new Error('Failed to parse the SOAP Message body');
}
if (typeof self.log === 'function') {
self.log("info", "Trying " + portName + " from path " + portPathname);
}
// use port.location and current url to find the right binding
binding = (function (self) {
var services = self.wsdl.definitions.services;
var firstPort;
var name;
for (name in services) {
serviceName = name;
var service = services[serviceName];
var ports = service.ports;
for (name in ports) {
portName = name;
var port = ports[portName];
var portPathname = url.parse(port.location).pathname.replace(/\/$/, '');
if (portPathname === pathname)
return port.binding;
if (typeof self.log === 'function') {
self.log("info", "Trying " + portName + " from path " + portPathname);
// The port path is almost always wrong for generated WSDLs
if (!firstPort) {
firstPort = port;
}
}
}
return !firstPort ? void 0 : firstPort.binding;
})();
if (portPathname === pathname)
return port.binding;
if (!binding) {
throw new Error('Failed to bind to WSDL');
}
// The port path is almost always wrong for generated WSDLs
if (!firstPort) {
firstPort = port;
}
try {
if (binding.style === 'rpc') {
methodName = Object.keys(body)[0];
self.emit('request', obj, methodName);
if (headers)
self.emit('headers', headers, methodName);
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: methodName,
outputName: methodName + 'Response',
args: body[methodName],
headers: headers,
style: 'rpc'
}, req, callback);
} else {
var messageElemName = (Object.keys(body)[0] === 'attributes' ? Object.keys(body)[1] : Object.keys(body)[0]);
var pair = binding.topElements[messageElemName];
self.emit('request', obj, pair.methodName);
if (headers)
self.emit('headers', headers, pair.methodName);
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: pair.methodName,
outputName: pair.outputName,
args: body[messageElemName],
headers: headers,
style: 'document'
}, req, callback, includeTimestamp);
}
}
return !firstPort ? void 0 : firstPort.binding;
})(this);
catch (error) {
if (error.Fault !== undefined) {
return self._sendError(error.Fault, callback, includeTimestamp);
}
if (!binding) {
throw new Error('Failed to bind to WSDL');
throw error;
}
}
try {
if (binding.style === 'rpc') {
methodName = Object.keys(body)[0];
// Authentication
self.emit('request', obj, methodName);
if (headers)
self.emit('headers', headers, methodName);
if (typeof authenticate === 'function') {
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: methodName,
outputName: methodName + 'Response',
args: body[methodName],
headers: headers,
style: 'rpc'
}, req, callback);
} else {
var messageElemName = (Object.keys(body)[0] === 'attributes' ? Object.keys(body)[1] : Object.keys(body)[0]);
var pair = binding.topElements[messageElemName];
var authResultProcessed = false,
processAuthResult = function (authResult) {
self.emit('request', obj, pair.methodName);
if (headers)
self.emit('headers', headers, pair.methodName);
if (!authResultProcessed && (authResult || authResult === false)) {
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: pair.methodName,
outputName: pair.outputName,
args: body[messageElemName],
headers: headers,
style: 'document'
}, req, callback, includeTimestamp);
}
}
catch (error) {
if (error.Fault !== undefined) {
return self._sendError(error.Fault, callback, includeTimestamp);
}
authResultProcessed = true;
throw error;
if (authResult) {
try {
process();
} catch (error) {
if (error.Fault !== undefined) {
return self._sendError(error.Fault, callback, includeTimestamp);
}
return self._sendError({
Code: {
Value: 'SOAP-ENV:Server',
Subcode: { value: 'InternalServerError' }
},
Reason: { Text: error.toString() },
statusCode: 500
}, callback, includeTimestamp);
}
} else {
return self._sendError({
Code: {
Value: 'SOAP-ENV:Client',
Subcode: { value: 'AuthenticationFailure' }
},
Reason: { Text: 'Invalid username or password' },
statusCode: 401
}, callback, includeTimestamp);
}
}
};
processAuthResult(authenticate(obj.Header && obj.Header.Security, processAuthResult));
} else {
throw new Error('Invalid authenticate function (not a function)');
}

@@ -417,3 +463,3 @@ };

? "http://www.w3.org/2003/05/soap-envelope"
: "http://schemas.xmlsoap.org/soap/envelope/"
: "http://schemas.xmlsoap.org/soap/envelope/";

@@ -420,0 +466,0 @@ var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +

@@ -103,2 +103,111 @@ /// <reference types="node" />

export interface Definitions {
descriptions: object;
ignoredNamespaces: string[];
messages: WsdlMessages;
portTypes: WsdlPortTypes;
bindings: WsdlBindings;
services: WsdlServices;
schemas: WsdlSchemas;
valueKey: string;
xmlKey: string;
xmlns: WsdlXmlns;
'$targetNamespace': string;
'$name': string;
}
export interface XsdTypeBase {
ignoredNamespaces: string[];
valueKey: string;
xmlKey: string;
xmlns?: WsdlXmlns,
}
export interface WsdlSchemas {
[prop: string]: WsdlSchema;
}
export interface WsdlSchema extends XsdTypeBase {
children: any[];
complexTypes?: WsdlElements;
elements?: WsdlElements;
includes: any[];
name: string;
nsName: string;
prefix: string;
types?: WsdlElements;
xmlns: WsdlXmlns;
}
export interface WsdlElements {
[prop: string]: XsdElement;
}
export type XsdElement = XsdElementType | XsdComplexType;
export interface WsdlXmlns {
wsu?: string;
wsp?: string;
wsam?: string;
soap?: string;
tns?: string;
xsd?: string;
__tns__?: string;
[prop: string]: string | void;
}
export interface XsdComplexType extends XsdTypeBase {
children: XsdElement[] | void;
name: string;
nsName: string;
prefix: string;
'$name': string;
[prop: string]: any;
}
export interface XsdElementType extends XsdTypeBase {
children: XsdElement[] | void;
name: string;
nsName: string;
prefix: string;
targetNSAlias: string;
targetNamespace: string;
'$lookupType': string;
'$lookupTypes': any[];
'$name': string;
'$type': string;
[prop: string]: any;
}
export interface WsdlMessages {
[prop: string]: WsdlMessage;
}
export interface WsdlMessage extends XsdTypeBase {
element: XsdElement;
parts: { [prop: string]: any };
'$name': string;
}
export interface WsdlPortTypes {
[prop: string]: WsdlPortType;
}
export interface WsdlPortType extends XsdTypeBase {
methods: { [prop: string]: XsdElement }
}
export interface WsdlBindings {
[prop: string]: WsdlBinding;
}
export interface WsdlBinding extends XsdTypeBase {
methods: WsdlElements;
style: string;
transport: string;
topElements: {[prop: string]: any};
}
export interface WsdlServices {
[prop: string]: WsdlService;
}
export interface WsdlService extends XsdTypeBase {
ports: {[prop: string]: any};
}
export class WSDL {

@@ -116,3 +225,3 @@ constructor(definition: any, uri: string, options?: IOptions);

xmlToObject(xml: any, callback?: (err:Error, result:any) => void): any;
findSchemaObject(nsURI: string, qname: string): any;
findSchemaObject(nsURI: string, qname: string): XsdElement | null | undefined;
objectToDocumentXML(name: string, params: any, nsPrefix?: string, nsURI?: string, type?: string): any;

@@ -126,2 +235,4 @@ objectToRpcXML(name: string, params: any, nsPrefix?: string, nsURI?: string, isParts?: any): string;

findChildSchemaObject(parameterTypeObj: any, childName: any, backtrace?: any): any;
uri: string;
definitions: Definitions;
}

@@ -199,3 +310,3 @@

export class WSSecurityCert implements ISecurity {
constructor(privatePEM: any, publicP12PEM: any, password: any);
constructor(privatePEM: any, publicP12PEM: any, password: any, options?: any);
addOptions(options: any): void;

@@ -202,0 +313,0 @@ toXML(): string;

@@ -96,2 +96,3 @@ /*

exports.BasicAuthSecurity = security.BasicAuthSecurity;
exports.NTLMSecurity = security.NTLMSecurity;
exports.WSSecurity = security.WSSecurity;

@@ -98,0 +99,0 @@ exports.WSSecurityCert = security.WSSecurityCert;

@@ -0,0 +0,0 @@

{
"name": "soap",
"version": "0.24.0",
"version": "0.25.0",
"description": "A minimal node SOAP client",

@@ -16,5 +16,5 @@ "engines": {

"lodash": "^4.17.5",
"httpntlm": "^1.5.2",
"request": ">=2.9.0",
"sax": ">=0.6",
"selectn": "^0.9.6",
"serve-static": "^1.11.1",

@@ -27,3 +27,3 @@ "strip-bom": "~0.3.1",

"type": "git",
"url": "https://github.com/milewise/node-soap.git"
"url": "https://github.com/vpulim/node-soap.git"
},

@@ -38,5 +38,5 @@ "main": "./index.js",

"pretest": "jshint index.js lib test",
"cover": "nyc --reporter=lcov --reporter=html --reporter=text mocha test/*-test.js test/security/*.js",
"cover": "nyc --reporter=lcov --reporter=html --reporter=text mocha --exit test/*-test.js test/security/*.js",
"coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js -v",
"test": "mocha --timeout 10000 test/*-test.js test/security/*.js"
"test": "mocha --timeout 10000 --exit test/*-test.js test/security/*.js"
},

@@ -48,5 +48,6 @@ "keywords": [

"devDependencies": {
"@types/bluebird": "^3.5.1",
"body-parser": "^1.15.2",
"colors": "^1.1.2",
"coveralls": "^2.11.6",
"coveralls": "^3.0.1",
"diff": "^2.2.1",

@@ -58,3 +59,3 @@ "doctoc": "^1.0.0",

"jshint": "2.3.0",
"mocha": "~1.17.0",
"mocha": "~5.2.0",
"nyc": "^11.4.1",

@@ -61,0 +62,0 @@ "readable-stream": "~2.0.2",

@@ -51,2 +51,3 @@ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url]

- [WSSecurityCert](#wssecuritycert)
- [NTLMSecurity](#ntlmsecurity)
- [Handling XML Attributes, Value and XML (wsdlOptions).](#handling-xml-attributes-value-and-xml-wsdloptions)

@@ -131,3 +132,3 @@ - [Overriding the `value` key](#overriding-the-value-key)

- endpoint: to override the SOAP service's host specified in the `.wsdl` file.
- envelopeKey: to set specific key instead of `<pre><<b>soap</b>:Body></<b>soap</b>:Body></pre>`.
- envelopeKey: to set specific key instead of `<pre><soap:Body></soap:Body></pre>`.
- preserveWhitespace: to preserve leading and trailing whitespace characters in text and cdata.

@@ -310,4 +311,24 @@ - escapeXML: escape special XML characters in SOAP message (e.g. `&`, `>`, `<` etc), default: `true`.

Asynchronous authentication:
``` javascript
server = soap.listen(...)
server.authenticate = function(security, callback) {
var created, nonce, password, user, token;
token = security.UsernameToken, user = token.Username,
password = token.Password, nonce = token.Nonce, created = token.Created;
myDatabase.getUser(user, function (err, dbUser) {
if (err || !dbUser) {
callback(false);
return;
}
callback(password === soap.passwordDigest(nonce, created, dbUser.password));
});
};
```
Synchronous authentication:
``` javascript
server = soap.listen(...)
server.authenticate = function(security) {

@@ -472,6 +493,7 @@ var created, nonce, password, user, token;

client.MyFunctionAsync({name: 'value'}).then((result) => {
// result is a javascript array containing result, raw and soapheader
// result is a javascript array containing result, rawResponse, soapheader, and rawRequest
// result is a javascript object
// raw is the raw response
// rawResponse is the raw xml response string
// soapHeader is the response soap header as a javascript object
// rawRequest is the raw xml request string
})

@@ -741,2 +763,14 @@ ```

### NTLMSecurity
Parameter invocation:
``` javascript
client.setSecurity(new soap.NTLMSecurity('username', 'password', 'domain', 'workstation'));
```
This can also be set up with a JSON object, substituting values as appropriate, for example:
``` javascript
var loginData = {username: 'username', password: 'password', domain: 'domain', workstation: 'workstation'};
client.setSecurity(new soap.NTLMSecurity(loginData));
```
## Handling XML Attributes, Value and XML (wsdlOptions).

@@ -743,0 +777,0 @@ Sometimes it is necessary to override the default behaviour of `node-soap` in order to deal with the special requirements

@@ -0,0 +0,0 @@ var _ = require('lodash');

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

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