Forum Discussion

Magua's avatar
Magua
New Contributor
5 years ago

How to view canonicalized SignedInfo node for generating SignatureValue?

So I can successfully make a callout to a webservice using an X509 certificate as authentication via SoapUI as a test to validate my XML body and everything.  Works great.

 

However, when I try to perform the exact same callout from Salesforce (with the exact same XML payload) I get a different SignatureValue.

 

Now my DigestValue is a perfect match, (which I thought would be the hard part), which tells me that the string I'm using to generate the SignatureValue is the issue.  (Salesforce does not have a method to canonicalize internally so I must do so manually.)

 

According to SC14N (https://www.cryptosys.net/sc14n/) the string I'm using is correct but I'd *love* to see exactly the string of the SignedInfo node that SoapUI is using itself.

 

So, how can I see that?

 

I found this thread:  https://community.smartbear.com/t5/SoapUI-Open-Source/SoapUI-WS-Security-header/m-p/166755#M27209

 

... and this one:  https://community.smartbear.com/t5/SoapUI-Open-Source/How-is-SOAPUI-calculating-the-signature-value-withn-C14E-and/m-p/106742#M18437

 

And they are both unanswered, but I'm crossing my fingers that someone can help me out.

 

Thanks...

 

3 Replies

    • Magua's avatar
      Magua
      New Contributor

      I appreciate the response, JHunt , but I was hoping for a log or some way within SoapUI to actually view the canonicalized string used in generating the hashed value.

       

      Perhaps that could be logged as a feature request for future versions?  I'm sure many would appreciate it, not just myself...

       

      • JHunt's avatar
        JHunt
        Community Hero

        SoapUI only uses WSS4J to do create the Signature. As part of generating the signature, WSS4J does the canonicalization. SoapUI never sees the canonicalized version inside it's own code base.

         

        I put this script together by looking at how SoapUI prepares the request, and what WSS4J was doing internally.

        import javax.xml.parsers.DocumentBuilderFactory
        import org.apache.xml.security.c14n.Canonicalizer
        import org.w3c.dom.Document
        import org.xml.sax.InputSource
        
        def request = context.testCase.testSteps["Test Request - login"].testRequest
        
        Document doc = {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance()
            dbf.setValidating(false)
            dbf.setNamespaceAware(true)
            return dbf.newDocumentBuilder()
                .parse(new InputSource(new StringReader(context.expand(request.requestContent))))
        }()
        
        Byte[] canonicalBytes = {
            org.apache.xml.security.Init.init()
            Canonicalizer.getInstance("http://www.w3.org/2001/10/xml-exc-c14n#")
                .canonicalizeSubtree(doc.documentElement)
        }()
        
        String canonicalBase64 = canonicalBytes.encodeBase64()
        String canonicalXml = new String(canonicalBytes)

        Create a new Groovy Script test step, put in the script and adjust line 7 with the name of your request. Hopefully I've not omitted any important steps in the preparation.