我正在使用xmlseclibs尝试签署 SOAP 文档,但它似乎并没有以相同的方式规范化事物,具体取决于我是在签名还是验证。
我给你举个例子。这是我要签名的 XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" IssueInstant="2010-02-04T15:27:43Z" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester"/>
</samlp:Status>
</samlp:Response>
</soapenv:Body>
</soapenv:Envelope>
我得到了一些在 PHP 中工作的代码,以使用公钥和私钥证书的组合对其进行签名,它似乎可以工作。它为<ds:Signature>
元素添加了所有适当的东西,看起来很棒。但后来我在签名后立即尝试验证它,再次使用 xmlseclibs(和公钥证书)对其进行了测试,但验证失败。因此,完全相同的代码库正在执行签名和验证,但是由于某种原因这两个进程不同意。
我向 xmlseclibs 添加了一些调试代码以了解它在做什么,并且我意识到它提供的签名密钥和提供的验证密钥不同的原因是因为它在两种情况下对事物进行了不同的规范化。当我告诉它签署<samlp:Response>
元素时,这是它签署的规范形式(为了便于阅读,我在此处添加了换行符):
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester">
</samlp:StatusCode>
</samlp:Status>
</samlp:Response>
但是,当它验证签名时,这是它计算验证的规范形式(再次,我在这里添加了换行符):
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a">
<samlp:Status>
<samlp:StatusCode Value="samlp:Requester">
</samlp:StatusCode>
</samlp:Status>
</samlp:Response>
如您所见,这个版本省略了元素中的xmlns:saml
属性<samlp:Response>
,而第一个版本没有。(请注意,这与xmlns:samlp
属性不同,后者包含在两者中。)这看起来很明显就像 xmlseclibs 中的一个错误,但尽管如此,如果我知道哪种规范形式是正确的,我很乐意自己修复它. 是否应该通过排他规范化省略该属性?还是应该包括在内?哪一种是正确的排他规范形式?