Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node-soap example? #19

Open
davidjconnolly opened this issue Oct 27, 2016 · 7 comments
Open

Node-soap example? #19

davidjconnolly opened this issue Oct 27, 2016 · 7 comments

Comments

@davidjconnolly
Copy link

Does anybody happen to have a working example of integrating wcf.js with https://github.com/vpulim/node-soap?

I need to setup an integration from our node server to a .NET API and it would be great to have an example as a starting point.

Thanks!

@yaronn
Copy link
Owner

yaronn commented Oct 28, 2016

I don't have a concrete example but wcf.js input is soap so you can try to ask in node-soap what'ss the best way to just extract the raw soap out of a request without sending it.

@davidjconnolly
Copy link
Author

Ya, that's what I was hoping to avoid but it may be the only way. It looks like I don't need WS password or token auth, just basic WSAuth to enforce HTTPS (or so the vendor says). I've narrowed it down to needing to enable: WSBinding supporting WS-A Addressing Version 200508.

Is this something I can do through wcf.js?

@yaronn
Copy link
Owner

yaronn commented Oct 28, 2016

Please paste here a sample soap. WSBinding is a potentially complex binding, but if you were able to narrow it down to just the WSA headers, then you can manually push them inside the soap envelope or I'm sure node-soap has built in support for them.

@davidjconnolly
Copy link
Author

Ya, that's what I'm hoping, I'm just not familiar enough with XML/Soap in general to know where to put them. node-soap's docs do mention WS-Security, however it looks like they only support creds/token based WS-Security auth. They seem to only be using it to enforce https on transport so I'm wondering if there's a hidden noad-soap setting somewhere I could use to get it talking in the right way to the server.

I'm trying to hit the WSDL: https://uat1api.berkeleypayment.com/CAMS/BPSClientAPI.svc?singleWsdl

Here is a sample working SOAP request for the Login event (generated by node-soap). I've used made up login creds but you can tell if it's working based on the response:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:i0="http://tempuri.org/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:tns="http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI" xmlns:q1="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q2="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q3="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q4="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q5="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q6="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q7="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts.Enums" xmlns:q8="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q9="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q10="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q11="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q12="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q13="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q14="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q15="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q16="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q17="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q18="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q19="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q20="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q21="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:q22="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:q23="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/">
   <soap:Body>
      <bps:Login xmlns:bps="http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI" xmlns:berk="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts">
         <bps:userID>someuser</bps:userID>
         <bps:password>somepassword</bps:password>
      </bps:Login>
   </soap:Body>
</soap:Envelope>

Here's the current response:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body><s:Fault><s:Code><s:Value>s:Sender</s:Value></s:Code><s:Reason><s:Text xml:lang="en-US">General exception in API&#xD;
Message: System.ServiceModel.MessageHeaderException: No Action header was found with namespace 'http://www.w3.org/2005/08/addressing' for the given message.&#xD;
   at System.ServiceModel.Dispatcher.ChannelHandler.ReplyContractFilterDidNotMatch(RequestContext request)&#xD;
   at System.ServiceModel.Dispatcher.ChannelHandler.EnsureChannelAndEndpoint(RequestContext request)&#xD;
   at System.ServiceModel.Dispatcher.ChannelHandler.TryRetrievingInstanceContextCore(RequestContext request)</s:Text></s:Reason></s:Fault></s:Body></s:Envelope>

Here is the expected response (using SoapUI's default interpretation of the WSDL, I didn't make any changes to the configs):

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
   <s:Header>
      <a:Action s:mustUnderstand="1">http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI/IBPSClientAPI/LoginResponse</a:Action>
      <ActivityId CorrelationId="082e328b-139d-4e43-bc8a-8a2e5410608f" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">a39225d4-af95-4ea0-8191-7ff392055ad3</ActivityId>
   </s:Header>
   <s:Body>
      <LoginResponse xmlns="http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI">
         <LoginResult xmlns:b="http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <b:ReponseTime>2016-10-28T18:22:26.9314783Z</b:ReponseTime>
            <b:Result>00000000-0000-0000-0000-000000000000</b:Result>
         </LoginResult>
      </LoginResponse>
   </s:Body>
</s:Envelope>

@davidjconnolly
Copy link
Author

Might also be worth mentioning how I've implemented node-soap:

// node-soap options
var options = {
  connection: 'keep-alive',
  headers: {
    'Connection': 'Keep-Alive',
  },
  overrideRootElement: {
    namespace: 'bps',
    xmlnsAttributes: [{
      name: 'xmlns:bps',
      value: 'http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI'
    }, {
      name: 'xmlns:berk',
      value: 'http://schemas.datacontract.org/2004/07/Berk.CAMS.Contracts'
    }]
  },
  forceSoap12Headers: true
};

Initialization function:

var berkeley = require('soap');
var wsdlurl = 'https://uat1api.berkeleypayment.com/CAMS/BPSClientAPI.svc?singleWsdl';

BerkeleyService.prototype.init = function() {
  if (this.isInitialized()) {
    throw new Error('This service has already been initialized');
  }
  var deferred = Q.defer();
  var _this = this;
  var args = {
    'bps:userID': constants.berkeley.userId,
    'bps:password': constants.berkeley.password
  };

  berkeley.createClient(wsdlurl, options, function(err, client) {
    if (err) {
      deferred.reject(err);
    } else {
      _this.client = client;
      _this.client.BPSClientAPI.WSHttpBinding_IBPSClientAPI.Login(args,
        options,
        function(err, result, raw) {
          if (err) {
            deferred.reject(raw);
          } else {
            _this.sessionId = result.LoginResult.Result;
            deferred.resolve(result);
          }
        });
    }
  });

  return deferred.promise;
};

@yaronn
Copy link
Owner

yaronn commented Oct 28, 2016

Try to use ws.js instead of Wcf.js:

https://github.com/yaronn/ws.js#ws-addressing

take the values of the action and addr ctor param from an outoging request soap ui sends.

@davidjconnolly
Copy link
Author

I figured it out! Thanks so much for the help @yaronn. I ended up getting it to work with node-soap alone.

I ended up getting an example XML request working in SoapUI without WS-A enabled then basically hacked around with node-soap until I was able to get it to generate the request format needed. The key was adding an Action soap header with the 'wsa' prefix and respective wsa xmlns schema

<soap:Header>
 <wsa:Action>http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI/IBPSClientAPI/Login</wsa:Action>
</soap:Header>

I achieved this by re-writing the 'xmlnsInEnvelope' (not sure why this wasn't in the envelope already per the WSDL) and adding the Action to the header like so:

if (client.wsdl.xmlnsInEnvelope.search('xmlns:wsa=\"http://www.w3.org/2005/08/addressing\"') == -1) {
     client.wsdl.xmlnsInEnvelope += ' xmlns:wsa=\"http://www.w3.org/2005/08/addressing\"';
}
client.clearSoapHeaders();
client.addSoapHeader({
     'wsa:Action': 'http://berkeleypayment.com/Berk.CAMS.ClientAPI/BPSClientAPI/IBPSClientAPI/Login'
});

Thanks again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants