I'm having a great deal of trouble trying to implement a SOAP call to CyberSource, and I'd appreciate any help that anyone can provide.
The environment: ColdFusion 11 on Windows 2012 Server, 64-bit.
The SOAP packet (personal info redacted) is as follows; it's basically the CyberSource sample provided in their documentation:
<?xml version="1.0" encoding="utf-8"?>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<phoneNumber>000 000 0000</phoneNumber>
The transmission is as follows:
<cfhttp url="https://ics2wstesta.ic3.com/commerce/1.x/transactionProcessor" method="post" port="443" resolveurl="false" result="httpResponse">
<cfhttpparam type="header" name="content-type" value="text/xml; charset=utf-8"/>
<cfhttpparam type="header" name="accept-encoding" value="no-compression"/>
<cfhttpparam type="header" name="content-length" value="#Len(Trim(variables.soap_packet))#"/>
<cfhttpparam type="xml" value="#Trim(variables.soap_packet)#"/>
The response from CyberSource is:
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext" xmlns:c="urn:schemas-cybersource-com:transaction-data-1.0"> <faultcode>soap:Client</faultcode> <faultstring> XML parse error. </faultstring> </soap:Fault> </soap:Body> </soap:Envelope>
There are two interesting things going on.
1. Initially, I built the SOAP packet by enclosing the above item like this:
When I tested the resulting string via #IsXML(Trim(XMLFormat(variables.soap_packet)))#, I got "NO".
Then I built the packet by enclosing the above item like this:
which produces a SOAP document object. I then converted that document object to a string via
<cfset soap_packet = #ToString(variables.soap_xml)#>
Testing the result via #IsXML(Trim(variables.soap_packet))#, I got "YES", and that's what I'm passing in the transmission.
So there's the first issue: Why is ColdFusion apparently producing different results for the two approaches?
2. Assuming I'm passing well-formed and valid XML with the second approach, why is the interaction with CyberSource failing?
As I've said, this is becoming very frustrating. Can anyone tell me what I'm doing wrong?
"XML parse error" is usually a pretty straight forward issue to fix. I ran your sample above through a parser and it appears valid. I'm guessing that the username and/or password that you masked in the sample contains one or more characters that require encoding and this is not being done - or being encoded incorrectly.
Off-topic, your sample included card information. Cybersource should have either a tokenization solution or a hosted payment page so your site does not touch the actual card information. If at all possible you want to avoid having your site touch card data as it will be very costly to maintain PCI compliance and makes you a target for hackers. A single breach can easily cost you thousands of dollars.
Thanks, but I don't believe that's the issue. The password, which I show here because (a) it's to a test environment and (b) it's useless without the username, is this:
As you can see, no XML-averse characters. But just to be certain, I'm now doing this: #Trim(EncodeForXML(the above string))# before passing it in my XML packet. No difference in the return result. And the username is pure alphanumerics. So I'm back to Square One. I suppose the username/password could have been created incorrectly by CyberSource, and I will look into that. I guess that it's also possible that CyberSource's documentation is incorrect.
In any case, I wonder if anyone else has seen the apparent CF inconsistency that I described:
<cfsavecontent var="soap_packet"><cfoutput>my text</cfoutput></cfsavecontent> produces a string. Then, IsXML(Trim(XMLFormat(that string))) returns FALSE.
But <cfxml><cfoutput>my text</cfoutput></cfxml> produces an XML document object, and ToString(the XML document object) also produces a string. Then, IsXML(Trim(that string)) returns TRUE. What's going on?? The two processes should produce identical results, no?
Regarding the card info, that's above my pay grade. I've just been told to get this process to work. Any further suggestions? I'll also be consulting CyberSource, of course....
Maybe try visually comparing the two strings. I still think there is some encoding going on that you're not seeing. I never use cfxml so I can't help much further on that. When creating XML output, if it's a real simple XML doc I'll use cfsavecontent similar to what you show above. Anything more complex than the simplest of XML documents I'll create the xml manually and then use toString:
local.xml = xmlNew();
local.xml.xmlRoot = xmlElemNew(variables.xml,"i4goauth");
local.outstr = toString(local.xml);