我正在尝试为我的PHP SOAP客户端实现WS-Security。第一步是能够从传出请求生成有效的XML摘要,但我无法做到这一点。我一直在寻找几天的答案,但大多数答案最终都是“不要自己解决,只使用现有的Java库”。在我目前的情况下,这是不可行的。
我一直在寻找网上的几个例子,试图重现他们所拥有的相同摘要,例如微软的this one。该页面列出了以下示例:
<ds:Object Id="ts-text">
Wed Jun 4 12:11:06 EDT
</ds:Object>
然后他们显示预期的摘要值:
<ds:Reference URI="#ts-text">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>pN3j2OeC0+/kCatpvy1dYfG1g68=</ds:DigestValue>
</ds:Reference>
这是我用来计算摘要值的代码:
<?php
$digest = base64_encode(hash('SHA1', $contents, true));
我尝试了许多不同的组合来删除空格或仅使用时间戳而没有XML标记但没有成功。我还尝试了更复杂的例子,其中需要进行规范化。这是我的单元测试之一:
public function testCreateDigest(DOMDocument $request, $expectedDigest) {
$ns = $request->documentElement->namespaceURI;
$body = $request
->getElementsByTagNameNS($ns, 'Body')
->item(0);
$firstElement = '';
foreach($body->childNodes as $node){
if ($node->nodeType === XML_ELEMENT_NODE) {
$firstElement = $node;
break;
}
}
$content = $firstElement->C14N(false, true);
$actualDigest = base64_encode(hash('SHA1', $content, true));
$this->assertEquals($expectedDigest, $actualDigest);
}
我究竟要干什么?我错过了任何步骤吗?
答案 0 :(得分:2)
我找到了解决方案。对于我尝试过的大多数示例,所需的转换是带有注释的独占规范化:http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/#WithComments
所以我的问题是我做错了转换。 PHP的C14N函数中的第一个参数定义是否使用独占转换。这就是代码应该是的(注意我删除了对第一个元素的不必要的遍历):
public function testCreateDigest(DOMDocument $request, $expectedDigest) {
$ns = $request->documentElement->namespaceURI;
$body = $request
->getElementsByTagNameNS($ns, 'Body')
->item(0);
$content = $body->C14N(true, true); // <-- exclusive, with comments
$actualDigest = base64_encode(hash('SHA1', $content, true));
$this->assertEquals($expectedDigest, $actualDigest);
}
所以你有它。这提醒我在漫无目的地编码之前仔细检查我的XML并理解标准。