diff --git a/lib/client.js b/lib/client.js index 80597692c..72786953b 100755 --- a/lib/client.js +++ b/lib/client.js @@ -110,7 +110,13 @@ Client.prototype._invoke = function(method, arguments, location, callback, optio self.security.addHeaders(headers); if (self.security && self.security.addOptions) self.security.addOptions(options); - + + //NTLM Security has extra requirements + var ntlm = false; + if (self.security && self.security.NTLM){ + ntlm = self.security; + } + if (input.parts) { assert.ok(!style || style == 'rpc', 'invalid message definition for document style binding'); message = self.wsdl.objectToRpcXML(name, arguments, alias, ns); @@ -121,7 +127,7 @@ Client.prototype._invoke = function(method, arguments, location, callback, optio } else { assert.ok(!style || style == 'document', 'invalid message definition for rpc style binding'); - message = self.wsdl.objectToDocumentXML(input.$name, arguments, input.targetNSAlias, input.targetNamespace); + message = self.wsdl.objectToDocumentXML(input.$name, arguments, input.targetNSAlias, input.targetNamespace); } xml = "" + ""; - self.lastRequest = xml; - + self.lastRequest = xml; + http.request(location, xml, function(err, response, body) { self.lastResponse = body; if (err) { @@ -160,7 +166,7 @@ Client.prototype._invoke = function(method, arguments, location, callback, optio } callback(null, result, body); } - }, headers, options); + }, headers, options, ntlm); } exports.Client = Client; diff --git a/lib/http.js b/lib/http.js index 631263f44..90e18add4 100755 --- a/lib/http.js +++ b/lib/http.js @@ -4,11 +4,12 @@ */ var url = require('url'), - req = require('request'); + req = require('request'), + httpntlm = require('httpntlm'); var VERSION = "0.2.0"; -exports.request = function(rurl, data, callback, exheaders, exoptions) { +exports.request = function(rurl, data, callback, exheaders, exoptions, ntlmSecurity) { var curl = url.parse(rurl); var secure = curl.protocol == 'https:'; var host = curl.hostname; @@ -41,13 +42,28 @@ exports.request = function(rurl, data, callback, exheaders, exoptions) { exoptions = exoptions || {}; for (var attr in exoptions) { options[attr] = exoptions[attr]; } - var request = req(options, function (error, res, body) { - if (error) { - callback(error); - } else { - callback(null, res, body); - } - }); - request.on('error', callback); - request.end(data); + console.log(JSON.stringify(headers)); + + if(!ntlmSecurity){ + + var request = req(options, function (error, res, body) { + if (error) { + callback(error); + } else { + callback(null, res, body); + } + }); + request.on('error', callback); + request.end(data); + + }else{ + console.log('Entering NTLM request'); + options.headers['Authorization'] = ntlm.challengeHeader(ntlmSecurity._hostname, ntlmSecurity._domain); + options.workstation = 'virco.webserver'; + options.body = data; + options.domain = ntlmSecurity._domain; + options.username = ntlmSecurity._username; + options.password = ntlmSecurity._password; + httpntlm.post(options, callback); + } } diff --git a/lib/soap.js b/lib/soap.js index e99411543..3fabb79ea 100755 --- a/lib/soap.js +++ b/lib/soap.js @@ -62,6 +62,22 @@ function listen(server, pathOrOptions, services, xml) { return new Server(server, path, services, wsdl); } +function NTLMAuthSecurity(url, domain, username, password) { + this._url = url; + this._hostname = require('url').parse(url).hostname; + this._domain = domain; + this._username = username; + this._password = password; +} + +NTLMAuthSecurity.prototype.toXML = function() { + return ""; +} + +NTLMAuthSecurity.prototype.NTLM = function() { + return true; +} + function BasicAuthSecurity(username, password) { this._username = username; this._password = password; @@ -144,6 +160,7 @@ WSSecurity.prototype.toXML = function() { } exports.BasicAuthSecurity = BasicAuthSecurity; +exports.NTLMAuthSecurity = NTLMAuthSecurity; exports.WSSecurity = WSSecurity; exports.ClientSSLSecurity = ClientSSLSecurity; exports.createClient = createClient; diff --git a/package.json b/package.json index 708ebd500..23a5f705d 100755 --- a/package.json +++ b/package.json @@ -1,21 +1,48 @@ { - "name": "soap", - "version": "0.3.0", - "description": "A minimal node SOAP client", - "engines": { "node": ">=0.8.0" }, - "author": "Vinay Pulim ", - "dependencies": { - "node-expat": ">=1.6.1", - "request": ">=2.9.0" - }, - "repository" : { - "type":"git", - "url":"https://github.com/milewise/node-soap.git" }, - "main": "./index.js", - "directories": { "lib": "./lib" }, - "scripts": {"test": "mocha -R spec -u exports test/*-test.js"}, - "keywords": ["soap"], - "licenses": [{ - "type" : "MIT License", - "url" : "http://www.opensource.org/licenses/mit-license.php" }] + "name": "soap", + "version": "0.3.0", + "description": "A minimal node SOAP client", + "engines": { + "node": ">=0.8.0" + }, + "author": { + "name": "Vinay Pulim", + "email": "v@pulim.com" + }, + "dependencies": { + "node-expat": ">=1.6.1", + "request": ">=2.9.0", + "httpntlm": "https://github.com/btallman/node-http-ntlm.git" + }, + "repository": { + "type": "git", + "url": "https://github.com/milewise/node-soap.git" + }, + "main": "./index.js", + "directories": { + "lib": "./lib" + }, + "scripts": { + "test": "mocha -R spec -u exports test/*-test.js" + }, + "keywords": [ + "soap" + ], + "licenses": [ + { + "type": "MIT License", + "url": "http://www.opensource.org/licenses/mit-license.php" + } + ], + "readme": "This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services.\n\nFeatures:\n\n* Very simple API\n* Handles both RPC and Document schema types\n* Supports multiRef SOAP messages (thanks to [@kaven276](https://github.com/kaven276))\n* Support for both synchronous and asynchronous method handlers\n* WS-Security (currently only UsernameToken and PasswordText encoding is supported)\n* Slightly improved ability to handle SAP SOAP WSDLS\n 1. Sequences nest a collection of objects beneath the parent object, instead of a collection of parent objects\n\n## Install\n\nInstall with [npm](http://github.com/isaacs/npm):\n\n```\n npm install soap\n```\n## Module\n\n### soap.createClient(url, callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.\n\n``` javascript\n var soap = require('soap');\n var url = 'http://example.com/wsdl?wsdl';\n var args = {name: 'value'};\n soap.createClient(url, function(err, client) {\n client.MyFunction(args, function(err, result) {\n console.log(result);\n });\n });\n```\n\n### soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.\n*wsdl* is an xml string that defines the service.\n\n``` javascript\n var myService = {\n MyService: {\n MyPort: {\n MyFunction: function(args) {\n return {\n name: args.name\n };\n }\n\n // This is how to define an asynchronous function. \n MyAsyncFunction: function(args, callback) {\n // do some work\n callback({\n name: args.name\n })\n }\n }\n }\n }\n\n var xml = require('fs').readFileSync('myservice.wsdl', 'utf8'),\n server = http.createServer(function(request,response) {\n response.end(\"404: Not Found: \"+request.url)\n });\n\n server.listen(8000);\n soap.listen(server, '/wsdl', myService, xml);\n```\n\n### server logging\n\nIf the log method is defined it will be called with 'received' and 'replied'\nalong with data.\n\n``` javascript\n server = soap.listen(...)\n server.log = function(type, data) {\n // type is 'received' or 'replied'\n };\n```\n\n### server security example using PasswordDigest\n\nIf server.authenticate is not defined no authentation will take place.\n\n``` javascript\n server = soap.listen(...)\n server.authenticate = function(security) {\n var created, nonce, password, user, token;\n token = security.UsernameToken, user = token.Username,\n password = token.Password, nonce = token.Nonce, created = token.Created;\n return user === 'user' && password === soap.passwordDigest(nonce, created, 'password');\n };\n```\n\n### server connection authorization\n\nThis is called prior to soap service method\nIf the method is defined and returns false the incoming connection is\nterminated.\n\n``` javascript\n server = soap.listen(...)\n server.authorizeConnection = function(req) {\n return true; // or false\n };\n```\n\n\n## Client\n\nAn instance of Client is passed to the soap.createClient callback. It is used to execute methods on the soap service.\n\n### Client.describe() - description of services, ports and methods as a JavaScript object\n\n``` javascript\n client.describe() // returns\n {\n MyService: {\n MyPort: {\n MyFunction: {\n input: {\n name: 'string'\n }\n }\n }\n }\n }\n```\n\n### Client.setSecurity(security) - use the specified security protocol (see WSSecurity below)\n\n``` javascript\n client.setSecurity(new WSSecurity('username', 'password'))\n```\n\n### Client.*method*(args, callback) - call *method* on the SOAP service.\n\n``` javascript\n client.MyFunction({name: 'value'}, function(err, result) {\n // result is a javascript object\n })\n```\n### Client.*service*.*port*.*method*(args, callback) - call a *method* using a specific *service* and *port*\n\n``` javascript\n client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {\n // result is a javascript object\n })\n```\n### Client.*addSoapHeader*(soapHeader[, name, namespace, xmlns]) - add soapHeader to soap:Header node\n#### Options\n\n - `soapHeader` Object({rootName: {name: \"value\"}}) or strict xml-string\n\n##### Optional parameters when first arg is object :\n - `name` Unknown parameter (it could just a empty string)\n - `namespace` prefix of xml namespace\n - `xmlns` URI\n\n### Client.*lastRequest* - the property that contains last full soap request for client logging\n\n## WSSecurity\n\nWSSecurity implements WS-Security. UsernameToken and PasswordText/PasswordDigest is supported. An instance of WSSecurity is passed to Client.setSecurity.\n\n``` javascript\n new WSSecurity(username, password, passwordType)\n //'PasswordDigest' or 'PasswordText' default is PasswordText\n```\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/milewise/node-soap/issues" + }, + "_id": "soap@0.3.0", + "dist": { + "shasum": "1cb44bad31fe51e218e54c78aaa4446c3a311e21" + }, + "_resolved": "git://github.com/btallman/node-soap#ac6240218470ef142ffed64c6e1b70ed30835c26", + "_from": "soap@git://github.com/btallman/node-soap#alpha-1" }