droyo / go-xml

utility and code-generation libraries for XML
MIT License
305 stars 115 forks source link

Referenced node has no explicit xmlns namespace when marshalling #83

Open makon opened 5 years ago

makon commented 5 years ago

Hi, I am trying to include the external xmldsig schema into my schema and to generate the structs. This steps works and this is great! In the next step I use xmlsec1 to sign the marshalled XML but then it complains that it can't find the Signature node.

Error: failed to find default node with name="Signature"

It seems that xmlsec1 expects that the marshalled XML contains a Signaute node with its explicit xmlns namespace/

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">

When I am marshalling the XML I get a Signature node without its namespace but all its child nodes contain it. Is it somehow possible to achieve that the Signature node also has its namespace explicitly when marshalled?

Result:

<MetaDataType>
  <Signature>
    <SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
      <CanonicalizationMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      <SignatureMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
      <Reference xmlns="http://www.w3.org/2000/09/xmldsig#">
        <DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <DigestValue xmlns="http://www.w3.org/2000/09/xmldsig#"/>
      </Reference>
    </SignedInfo>
    <SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#"/>
  </Signature>
</MetaDataType>

Schema:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
           elementFormDefault="qualified">
    <xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
               schemaLocation="xmldsig-core-schema.xsd" />

    <xs:element name="MetaData" type="MetaDataType" />
    <xs:complexType name="MetaDataType">
        <xs:sequence>
            <xs:element ref="ds:Signature"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

Generated code:

type MetaDataType struct {
    Signature *SignatureType `xml:" Signature"`
}

type SignatureType struct {
    SignedInfo     *SignedInfoType     `xml:"http://www.w3.org/2000/09/xmldsig# SignedInfo"`
    SignatureValue *SignatureValueType `xml:"http://www.w3.org/2000/09/xmldsig# SignatureValue"`
    KeyInfo        *KeyInfoType        `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo,omitempty"`
    Object         []ObjectType        `xml:"http://www.w3.org/2000/09/xmldsig# Object,omitempty"`
    Id             string              `xml:"Id,attr,omitempty"`
}
droyo commented 5 years ago

Thanks for the report.

The problem appears to be that the root element, regardless of what it is, doesn't get a namespace. This could be fixed in the code generation by adding an XMLName field. In your example, we'd generate something like

type SignatureType struct {
    XMLName        xml.Name            `xml:"http://www.w3.org/2000/09/xmldsig# Signature"`
    SignedInfo     *SignedInfoType     `xml:"http://www.w3.org/2000/09/xmldsig# SignedInfo"`
    SignatureValue *SignatureValueType `xml:"http://www.w3.org/2000/09/xmldsig# SignatureValue"`
    KeyInfo        *KeyInfoType        `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo,omitempty"`
    Object         []ObjectType        `xml:"http://www.w3.org/2000/09/xmldsig# Object,omitempty"`
    Id             string              `xml:"Id,attr,omitempty"`
}
droyo commented 5 years ago

Actually, looking at this closer, the fact that the Signature field in MetaDataType does not have a namespace seems like a bug.

I recall a previous issue where the code failed to preserve namespaces when importing types across namespace boundaries (as your schema does), but I thought I fixed that. The fact that this schema does not declare a targetNamespace may be relevant -- can you try adding a targetNamespace declaration (the value doesn't matter) to the schema element and try codegen again?

makon commented 5 years ago

Thanks for the fast respone. So I changed the schema to

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
           xmlns:ex="urn:example"
           targetNamespace="urn:example"
           elementFormDefault="qualified">
    <xs:import namespace="http://www.w3.org/2000/09/xmldsig#"
               schemaLocation="xmldsig-core-schema.xsd" />

    <xs:element name="MetaData" type="ex:MetaDataType" />
    <xs:complexType name="MetaDataType">
        <xs:sequence>
            <xs:element ref="ds:Signature"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

and adjusted the namespace flag to

xsdgen -pkg=main -o=xsd/test.go -ns "urn:example" xsd/test.xsd xsd/xmldsig-core-schema.xsd

and in this case it seems to use the target namespace but in my case I would expect that Signautre would have the namespace of xmldsig?

type MetaDataType struct {
    Signature *SignatureType `xml:"urn:example Signature"`
}

type SignatureType struct {
    SignedInfo     *SignedInfoType     `xml:"http://www.w3.org/2000/09/xmldsig# SignedInfo"`
    SignatureValue *SignatureValueType `xml:"http://www.w3.org/2000/09/xmldsig# SignatureValue"`
    KeyInfo        *KeyInfoType        `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo,omitempty"`
    Object         []ObjectType        `xml:"http://www.w3.org/2000/09/xmldsig# Object,omitempty"`
    Id             string              `xml:"Id,attr,omitempty"`
}

the xml output is now

<Signature xmlns="urn:example">

Did I do something wrong? I am not sure if this was what you thought about. I am not really an expert in XSD schemas... sorry.

What I forgot to mention is that I am using the omitempty-structs branch but I merged the latest master into it. I also tried it with the master with the same result.

droyo commented 5 years ago

It looks like setting the targetNamespace did not fix the issue and this is a variation of #65 ; elements in another namespace mistakenly get labelled with the targetNamespace of the schema containing the reference.