0

I have a namespaced XML document what must bu signed using special browser plugin.

Here is the peace code, that sign document:

    var oCertificate = GetCertificateBySubjectName(certificateName);

    var token = oCertificate.Export(CADESCOM_ENCODE_BASE64);

    var element, xmlDoc;

    xmlDoc = $.parseXML(doc.toString());
    element = $(xmlDoc).find("o\\:BinarySecurityToken");
    element.text(token);

    var xmlString = undefined;

    if (window.ActiveXObject) {
        xmlString = xmlDoc[0];
    }

    if (xmlString === undefined) {
        var oSerializer = new XMLSerializer();
        xmlString = (new XMLSerializer()).serializeToString(xmlDoc);
    }

    var doc = SignCreate(oCertificate, xmlString);

where doc is string that contains XML.

Here is the peace of XML what must be signed:

<s:Header>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:actor="http://smev.gosuslugi.ru/actors/smev">
        <o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"/>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411" />
                <Reference URI="#_1">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411" />
                    <DigestValue/>
                </Reference>
            </SignedInfo>
            <SignatureValue/>
            <KeyInfo>
                <o:SecurityTokenReference>
                    <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-ee82d445-758b-42cb-996c-666b74b60022-2" />
                </o:SecurityTokenReference>
            </KeyInfo>
        </Signature>
    </o:Security>
</s:Header>

Signing of the document works like this. Using xmlDoc = $.parseXML(message.toString()); element = $(xmlDoc).find("o\\:BinarySecurityToken"); element.text(token); I put token from sertificate into <o:BinarySecurityToken> then convert it back to string and send to sign.

In this steps I've got:

<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!!TOKEN!!</o:BinarySecurityToken>

and then

<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!!!TOKEN!!!</o:BinarySecurityToken>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
                <Reference URI="#_1">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/>
                    <DigestValue>!!!SIGNATURE DIGEST VALUE!!!</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>!!!SIGNATURE!!!</SignatureValue>

Everything works excellent in FireFox and (!)IE, but doesn't works in Google Chrome. In Chrome code that puts token into leave it empty and all other methods will not work.

So, my question is: What should I do to solve this problem? I try to use https://github.com/rfk/jquery-xmlns to give jQuery some power to work with namespaced XML, but this library didn't run in my code.

Thanks in advance.

P.S. I use jQuery 1.10.2

1 Answer 1

1

jQuery does not supports namespaces, only colons in node names. I could not get the jquery-xmlns plugin to work with the current jQuery versions.

The new Document.querySelector() and Document.querySelectorAll() methods do not support namespaces either.

But Document.evaluate() and Document itself do. They allow to use XPath. All modern browser except IE support Document.evaluate(). For IE a JavaScript library can be used to add the method to the document objects.

var dom = (new DOMParser()).parseFromString(xml, 'application/xml');

var resolver = {
  namespaces : {
   'o' : 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
  },
  lookupNamespaceURI : function(prefix) {
    if (prefix == '') {
      return null;
    }   
    return this.namespaces[prefix] || null;
  }
};

var node = dom.evaluate(
  '//o:BinarySecurityToken',  
  dom,
  resolver,
  XPathResult.FIRST_ORDERED_NODE_TYPE,
  null 
).singleNodeValue;
node.appendChild(dom.createTextNode('TOKEN_TEXT')); 

document.querySelector('#output').textContent = (new XMLSerializer()).serializeToString(dom);

Demo: http://jsfiddle.net/mec2qxLa/2/

To make it work with IE you need to load the xpath.js. It attaches the evaluate method to the document object. For new Document instances you can get it from there. It does not publish the XPathResult object, but it defines a xpath object that provides it.

var dom = (new DOMParser()).parseFromString(xml, 'application/xml');
if (!dom.evaluate && document.evaluate) {
  dom.evaluate = document.evaluate;
  if (typeof XPathResult == 'undefined') {
    XPathResult = xpath.XPathResult;
  }
}
...
Sign up to request clarification or add additional context in comments.

12 Comments

Thanks for response. Your method is perfectly works with FireFox and Chrome, but IE throws an "XPathResult is undefined" exception. I link JS library that you'd give me then my page loads in IE, but problem migrate now from Chrome to IE :-D
For IE you need the xpath.js library that I linked. I added an example on how to integrate it. Spartan is reported to have native support.
I'd added your code, include xpath.js but still no result for IE. xpath.js used node.js library for work, isn't it? If it's right I don't use it in my project. I'd open jsfiddle.net/mec2qxLa/2 in IE and get the same error.
The library works with node.js and browsers. It recognizes if it is loaded in node.js or not.
I cant understand why it wants work. I put <script src="Scripts\xpath.js"></script> into my page, and then 'if (typeof installDOM3XPathSupport != 'undefined') { installDOM3XPathSupport(dom, new XPathParser()); }' executes, IE told me that installDOM3XPathSupport is undefined. Could you show me the corret usage of this library, please?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.