Thanks for the reply. However, the line in my demo

    input.setNeedsToBeExpanded(true);

causes the following code in CanonicalizerBase to be called

    if (input.isNeedsToBeExpanded()) {
        XMLUtils.circumventBug2650(doc);
    } 

which does call XMLUtils.circumventBug2650 (I traced it) on the nodeset.
Still the namespaces in PrefixList are not output in the root element.

I have investigated some more and have managed to get the result I want but
it has made me more convinced there is a bug in xml-security's Excl C14N
processing (or that I really don't understand it ;) ).

There are 3 test cases which each produce different output but which I
suspect should produce the same output. 

1) 

INPUT: 
  XMLSignatureInput with nodeSet and set "needsToBeExpanded" to true. 

DESCRIPTION: 
  In this case XMLUtils.circumventBug2650() is called in CanonicalizerBase
  because "needsToBeExpanded" is set in the input.

CODE:
  input = new XMLSignatureInput(nodeSet);
  input.setNeedsToBeExpanded(true);
  bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

OUTPUT (formatted):
  <env:Body wsu:Id="body">
    <ns0:Ping xsi:type="ns0:ping">
      <ns0:text xsi:type="xsd:string">hello</ns0:text>
    </ns0:Ping>
  </env:Body>

COMMENT: 
  missing namespace declarations on Body. The call to circumventBug2650
  is done by the canonicalizer after the nodeset is created. Doing another
  test, where the nodeset is created and then circumventBug2650 is called
  explicitely before C14N, produces the same result.

2)

INPUT: 
  XMLSignatureInput with nodeSet on which circumventBug2650 was called
before 
  the nodeSet was created from the document.

DESCRIPTION: 
  the Document is created, circumventBug2650 called and then the nodeSet
  is created. The input is again an XMLSignatureInput with a nodeSet but
  this time "needsToBeExpanded" is not set to true because the circumvent
  was already called.

CODE:
  XMLUtils.circumventBug2650(doc);
  XMLUtils.getSet(doc.getDocumentElement().getFirstChild(), nodeSet, null,
false);
  input = new XMLSignatureInput(nodeSet);
  bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

OUTPUT:
  <env:Body 
      xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"; 
 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurit
y-utility-1.0.xsd" 
      wsu:Id="body">
    <ns0:Ping xmlns:ns0="http://xmlsoap.org/Ping"; 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
        xsi:type="ns0:ping">
      <ns0:text xsi:type="xsd:string">hello</ns0:text>
    </ns0:Ping>
  </env:Body>

COMMENT: 
  This is the output that would be expected if InclusiveNamespaces="".
  However, the value "env ns0 xsi wsu" is passed as the prefix list.
  Tracing the code in the Canonicalizer shows that the prefix list is
  lost.

3)

INPUT: 
  NodeSet with circumventBug2650 called on the document before the 
  nodeset is created. 

DESCRIPTION: 
  The method "engineCanonicalizeXPathNodeSet() is called directly
  here instead of indirectly as in the previous cases so the 
  InclusiveNamespaces value is assured to be passed correctly to 
  the method.

CODE:
  XMLUtils.circumventBug2650(doc);
  XMLUtils.getSet(doc.getDocumentElement().getFirstChild(), nodeSet, null,
false);
  bytes = c14n.engineCanonicalizeXPathNodeSet(nodeSet, "env ns0 xsi wsu");

OUTPUT:
  <env:Body 
      xmlns:env="http://schemas.xmlsoap.org/soap/envelope/";
      xmlns:ns0="http://xmlsoap.org/Ping";
 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurit
y-utility-1.0.xsd" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
      wsu:Id="body">
    <ns0:Ping xsi:type="ns0:ping">
      <ns0:text xsi:type="xsd:string">hello</ns0:text>
    </ns0:Ping>
  </env:Body>

COMMENT: 
  this is the output I was expecting from all of the above cases. 
  The InclusiveNamespaces value means those namespace prefix 
  declarations should appear on the root node as they do here.

4)

INPUT: 
  root node

DESCRIPTION:
  circumventBug2650 may or may not be called and "needsToBeExpanded" 
  can be true or false. The same result is obtained in each case.

CODE:
  input = new XMLSignatureInput(doc.getDocumentElement().getFirstChild());
  byte[] bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

OUTPUT:
  Same as case 3)

COMMENT: 
  the result using a root node is consistent no matter the settings. 
  Should this also be the case for using nodesets?

Cases 3 and 4 produce the same (correct I think) output. Cases 1 and 2
produce different output from each other and from 3 and 4. Is this the
expected behaviour is cases 1 and 2 and, if so, why?

Or if someone could tell me where my logic/expectations are in error that
would also be great.

I have attached an updated class that demonstrates each of the above cases.

Pete

>>-----Original Message-----
>>From: [EMAIL PROTECTED] 
>>[mailto:[EMAIL PROTECTED] On Behalf Of Raul Benito
>>Sent: Wednesday, 30 November 2005 3:23 a.m.
>>To: [email protected]
>>Subject: Re: Different behaviour with NodeSet and RootNode 
>>with InclusiveNamespaces
>>
>>You need to XMLUtils.circumventBug* before calling the c14n 
>>with nodesets...
>>
>>Regards,
>>
>>On 11/29/05, Pete Hendry <[EMAIL PROTECTED]> wrote:
>>> I have a WS-Security implementation based on xml-security 
>>and am testing
>>> interop. When testing against WSS4J (which also uses 
>>xml-security) - both
>>> using version 1.3.0 - I am having problems because of what 
>>appears to be
>>> different results of Excl C14N depending on whether the 
>>input is a NodeSet
>>> or a root node. The problem occurs when using InclusiveNamespaces.
>>>
>>> The issue appears to be that when the input is a NodeSet, the
>>> InclusiveNamespaces value is ignored. What happens is the 
>>following sequence
>>> of calls:
>>>
>>> TransformC14NExclusive.enginePerformTransform(inputWithNodeSet)
>>>  -> 
>>Canonicalizer20010315Excl.engineCanonicalize(inputWithNodeSet,
>> "env ns0
>>> xsi wsu")
>>>    -> _inclusiveNSSet = "env ns0 xsi wsu"
>>>    -> CanonicalizerBase.engineCanonicalize(inputWithNodeSet)
>>>      ->
>>> 
>>Canonicalizer20010315Excl.engineCanonicalizeXPathNodeSet(xpathNodeSet)
>>>        ->
>>> 
>>Canonicalizer20010315Excl.engineCanonicalizeXPathNodeSet(xpath
>>NodeSet, "")
>>>        -> _inclusiveNSSet = ""
>>>
>>> So the inclusive namespaces passed in originally are forgotten to be
>>> replaced by an empty list.
>>>
>>> When passing a root node instead of a node set, the 
>>inclusive namespace list
>>> is used and so the result is different. In the XML below, 
>>the document
>>> element is env:Envelope and env:Body is that target node 
>>for C14N. For the
>>> nodeset the result on the SOAP body is (formatting added)
>>>
>>> <env:Body
>>>     xmlns:env="http://schemas.xmlsoap.org/soap/envelope/";
>>>
>>> 
>>xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401
>>-wss-wssecurit
>>> y-utility-1.0.xsd"
>>>     wsu:Id="body">
>>>   <ns0:Ping
>>>       xmlns:ns0="http://xmlsoap.org/Ping";
>>>       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>>>       xsi:type="ns0:ping">
>>>     <ns0:text xsi:type="xsd:string">hello</ns0:text>
>>>   </ns0:Ping>
>>> </env:Body>
>>>
>>> and for a root node (being the body element in this case)
>>>
>>> <env:Body
>>>     xmlns:env="http://schemas.xmlsoap.org/soap/envelope/";
>>>     xmlns:ns0="http://xmlsoap.org/Ping";
>>>
>>> 
>>xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401
>>-wss-wssecurit
>>> y-utility-1.0.xsd"
>>>     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>>>     wsu:Id="body">
>>>   <ns0:Ping xsi:type="ns0:ping">
>>>     <ns0:text xsi:type="xsd:string">hello</ns0:text>
>>>   </ns0:Ping>
>>> </env:Body>
>>>
>>> I attach a test program that compares the 2 ways of doing 
>>this on the same
>>> document and shows the results (the nodeset result differs 
>>from the one
>>> above as it does not include any namespace declarations).
>>>
>>> Is this a bug or am I not understanding the difference 
>>between processing
>>> based on a nodeset and processing based on a root node?
>>>
>>> Pete
>>>
>>>
>>>
>>
>>
>>--
>>http://r-bg.com
package client.wss4j;

import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.xml.security.c14n.implementations.Canonicalizer20010315Excl;
import org.apache.xml.security.c14n.implementations.Canonicalizer20010315ExclOmitComments;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;


public class DemoINProblem {

    private static final String XML =
        "<env:Envelope"
        + " xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\"";
        + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"";
        + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
        + " xmlns:ns0=\"http://xmlsoap.org/Ping\"";
        + " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>"
        + "<env:Body wsu:Id=\"body\">"
        + "<ns0:Ping xsi:type=\"ns0:ping\">"
        + "<ns0:text xsi:type=\"xsd:string\">hello</ns0:text>"
        + "</ns0:Ping>"
        + "</env:Body>"
        + "</env:Envelope>";


    public static void main( String[] args )
        throws Exception {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        factory.setValidating(false);

        DocumentBuilder builder = factory.newDocumentBuilder();

        Canonicalizer20010315Excl c14n;
        Document doc;
        XMLSignatureInput input;
        byte[] bytes;
        Set nodeSet;

        // CASE 1: nodeSet, set needsToBeExpanded=true
        doc = builder.parse(new InputSource(new StringReader(XML)));
        c14n = new Canonicalizer20010315ExclOmitComments();
        nodeSet = new HashSet();
        XMLUtils.getSet(doc.getDocumentElement().getFirstChild(), nodeSet, null, false);
        input = new XMLSignatureInput(nodeSet);
        input.setNeedsToBeExpanded(true);
        bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");
        System.out.println("CASE 1: NodeSet, needsToBeExpanded=true, circumventBug2650=false\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");


        // CASE 2: nodeSet, circumventBug2650 called before C14N
        doc = builder.parse(new InputSource(new StringReader(XML)));
        c14n = new Canonicalizer20010315ExclOmitComments();
        XMLUtils.circumventBug2650(doc);
        nodeSet = new HashSet();
        XMLUtils.getSet(doc.getDocumentElement().getFirstChild(), nodeSet, null, false);
        input = new XMLSignatureInput(nodeSet);
        input.setNeedsToBeExpanded(false);

        bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");
        System.out.println("CASE 2: NodeSet, needsToBeExpanded=false, circumventBug2650=true\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");


        // CASE 3: nodeSet, circumventBug2650 called first,
        //         engineCanonicalizeXPathNodeSet called directly
        doc = builder.parse(new InputSource(new StringReader(XML)));
        c14n = new Canonicalizer20010315ExclOmitComments();
        XMLUtils.circumventBug2650(doc);
        nodeSet = new HashSet();
        XMLUtils.getSet(doc.getDocumentElement().getFirstChild(), nodeSet, null, false);
        bytes = c14n.engineCanonicalizeXPathNodeSet(nodeSet, "env ns0 xsi wsu");
        System.out.println("CASE 3: NodeSet, needsToBeExpanded=false, circumventBug2650=true, calls engineCanonicalizeXPathNodeSet\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");


        //CASE 4: Root Node
        doc = builder.parse(new InputSource(new StringReader(XML)));
        c14n = new Canonicalizer20010315ExclOmitComments();
        input = new XMLSignatureInput(doc.getDocumentElement().getFirstChild());
        input.setNeedsToBeExpanded(false);
        bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

        System.out.println("CASE 4.1 needsToBeExpanded=false, circumventBug2650=false:\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");

        doc = builder.parse(new InputSource(new StringReader(XML)));
        XMLUtils.circumventBug2650(doc);
        c14n = new Canonicalizer20010315ExclOmitComments();
        input = new XMLSignatureInput(doc.getDocumentElement().getFirstChild());
        input.setNeedsToBeExpanded(false);
        bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

        System.out.println("CASE 4.2 needsToBeExpanded=false, circumventBug2650=true:\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");

        doc = builder.parse(new InputSource(new StringReader(XML)));
        c14n = new Canonicalizer20010315ExclOmitComments();
        input = new XMLSignatureInput(doc.getDocumentElement().getFirstChild());
        input.setNeedsToBeExpanded(true);
        bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

        System.out.println("CASE 4.3 needsToBeExpanded=true, circumventBug2650=false:\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");

        doc = builder.parse(new InputSource(new StringReader(XML)));
        XMLUtils.circumventBug2650(doc);
        c14n = new Canonicalizer20010315ExclOmitComments();
        input = new XMLSignatureInput(doc.getDocumentElement().getFirstChild());
        input.setNeedsToBeExpanded(true);
        bytes = c14n.engineCanonicalize(input, "env ns0 xsi wsu");

        System.out.println("CASE 4.4 needsToBeExpanded=true, circumventBug2650=true:\n"
                           + new String(bytes, "utf-8")
                           + "\n=======\n");
    }
}

Reply via email to