XML 架构验证 'Security' 问题
XML schema validation 'Security' issue
我有以下 xsd:
<xsd:schema
targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
elementFormDefault="qualified" attributeFormDefault="unqualified"
blockDefault="#all" version="0.2">
<xsd:import namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" schemaLocation="../MSG/IRS-WSTimeStampElementMessage.xsd" />
<xsd:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="../MSG/IRS-WSSignatureElementMessage.xsd"/>
<xsd:complexType name="SecurityHeaderType">
<xsd:annotation>
<xsd:documentation>This complexType defines header block to use for
security-relevant data directed at a specific SOAP actor.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="ds:Signature" minOccurs="0"/>
<xsd:element ref="wsu:Timestamp" minOccurs="0"/>
</xsd:sequence>
<xsd:anyAttribute namespace="##other" processContents="lax" />
</xsd:complexType>
<xsd:element name="Security" type="wsse:SecurityHeaderType">
<xsd:annotation>
<xsd:documentation>This element defines the wsse:Security SOAP header
element per Section 4.</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>
这是 XML 我正在尝试根据上面的架构进行验证:
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="TS-E68EBBF1696C5DD4AA143353323390073">
<u:Created>2016-03-22T12:42:44.170Z</u:Created>
<u:Expires>2016-03-22T12:52:44.170Z</u:Expires>
</u:Timestamp>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#id-1">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>2gAU0kJV40nvR+Og=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-2">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>pISNeszVQ59HKCRbQ=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#TS-E68EBBF1696C5DD4AA143353323390073">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>mh7+cJJPRtrrn/s4N15AE=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>fhpY2IlKEdwBFWqNxbVEw7p+ojhw54+op+g==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>fshPnGE6H36KNqWMZqTf+X0oBls3dLz7TY=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
我无法理解的是为什么在验证期间出现以下错误:
ERROR: The element 'Security' in namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' has invalid child element 'Signature' in namespace 'http://www.w3.org/2000/09/xmldsig#'.
它看起来像是在命名空间中定义的元素,但验证器似乎没有注意到它,或者出于某种原因只是忽略了这一事实。
它们以错误的顺序出现。一个序列应该按照它声明的顺序出现。你为签名设置了 0 的最小出现次数,这就是为什么它没有给你一个问题,因为时间戳是第一个.
如果您不想强制执行子元素的出现顺序,那么您可以选择 xsd::all,但它有自己的 issue/rules Difference between <xsd:all> and <xsd:sequence> in schema definition?
扩展@Rob 所说的内容。
当我创建我的 Signature
元素时,在使用 SignedXml
对象的 ComputeSignature()
方法后,我使用 signedXml.GetXml()
方法输出 XML 到 XmlElement
对象。用它来保存数字签名。我创建了一个 XmlNode
对象来保存 Security
元素的引用,然后使用 InsertBefore
方法在 [=17= 的 FirstChild
之前添加数字签名]元素。
这样做会将 Security
元素的子元素按适当的顺序排列。
// Compute the signature.
xSigned.ComputeSignature();
// Get the Xml representation of the signature and save it to an XmlElement object.
XmlElement xmlDigitalSignature = xSigned.GetXml();
// Replace the KeyInfo element of the DigitalSignature with the appropriate KeyInfo information.
xmlDigitalSignature = ReplaceKeyInfo(xmlDigitalSignature);
// Create a reference to the Security Element under the SOAP Header.
XmlNode securityNode = xdoc.DocumentElement.SelectSingleNode("//soapenv:Header/wsse:Security", XmlManager(xdoc));
// Add the element to the XmlDocument by moving the Signature Element to be the first child under the Security Element.
securityNode.InsertBefore(xdoc.ImportNode(xmlDigitalSignature, true), securityNode.FirstChild);
我有以下 xsd:
<xsd:schema
targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
elementFormDefault="qualified" attributeFormDefault="unqualified"
blockDefault="#all" version="0.2">
<xsd:import namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" schemaLocation="../MSG/IRS-WSTimeStampElementMessage.xsd" />
<xsd:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="../MSG/IRS-WSSignatureElementMessage.xsd"/>
<xsd:complexType name="SecurityHeaderType">
<xsd:annotation>
<xsd:documentation>This complexType defines header block to use for
security-relevant data directed at a specific SOAP actor.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="ds:Signature" minOccurs="0"/>
<xsd:element ref="wsu:Timestamp" minOccurs="0"/>
</xsd:sequence>
<xsd:anyAttribute namespace="##other" processContents="lax" />
</xsd:complexType>
<xsd:element name="Security" type="wsse:SecurityHeaderType">
<xsd:annotation>
<xsd:documentation>This element defines the wsse:Security SOAP header
element per Section 4.</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>
这是 XML 我正在尝试根据上面的架构进行验证:
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="TS-E68EBBF1696C5DD4AA143353323390073">
<u:Created>2016-03-22T12:42:44.170Z</u:Created>
<u:Expires>2016-03-22T12:52:44.170Z</u:Expires>
</u:Timestamp>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#id-1">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>2gAU0kJV40nvR+Og=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-2">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>pISNeszVQ59HKCRbQ=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#TS-E68EBBF1696C5DD4AA143353323390073">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>mh7+cJJPRtrrn/s4N15AE=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>fhpY2IlKEdwBFWqNxbVEw7p+ojhw54+op+g==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>fshPnGE6H36KNqWMZqTf+X0oBls3dLz7TY=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
我无法理解的是为什么在验证期间出现以下错误:
ERROR: The element 'Security' in namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' has invalid child element 'Signature' in namespace 'http://www.w3.org/2000/09/xmldsig#'.
它看起来像是在命名空间中定义的元素,但验证器似乎没有注意到它,或者出于某种原因只是忽略了这一事实。
它们以错误的顺序出现。一个序列应该按照它声明的顺序出现。你为签名设置了 0 的最小出现次数,这就是为什么它没有给你一个问题,因为时间戳是第一个.
如果您不想强制执行子元素的出现顺序,那么您可以选择 xsd::all,但它有自己的 issue/rules Difference between <xsd:all> and <xsd:sequence> in schema definition?
扩展@Rob 所说的内容。
当我创建我的 Signature
元素时,在使用 SignedXml
对象的 ComputeSignature()
方法后,我使用 signedXml.GetXml()
方法输出 XML 到 XmlElement
对象。用它来保存数字签名。我创建了一个 XmlNode
对象来保存 Security
元素的引用,然后使用 InsertBefore
方法在 [=17= 的 FirstChild
之前添加数字签名]元素。
这样做会将 Security
元素的子元素按适当的顺序排列。
// Compute the signature.
xSigned.ComputeSignature();
// Get the Xml representation of the signature and save it to an XmlElement object.
XmlElement xmlDigitalSignature = xSigned.GetXml();
// Replace the KeyInfo element of the DigitalSignature with the appropriate KeyInfo information.
xmlDigitalSignature = ReplaceKeyInfo(xmlDigitalSignature);
// Create a reference to the Security Element under the SOAP Header.
XmlNode securityNode = xdoc.DocumentElement.SelectSingleNode("//soapenv:Header/wsse:Security", XmlManager(xdoc));
// Add the element to the XmlDocument by moving the Signature Element to be the first child under the Security Element.
securityNode.InsertBefore(xdoc.ImportNode(xmlDigitalSignature, true), securityNode.FirstChild);