【发布时间】:2016-07-29 08:48:30
【问题描述】:
我有一个 Java(基于 JAX-WS)SOAP 客户端,我正试图与基于 WCF 的(第三方)服务器通信。我发现sentiment expressed here 非常准确。但目标仍然存在。
长话短说,我可以从服务器中哄出一个有效的“安全上下文令牌”,但我却被消息签名问题挂断了(我相信)。
服务器似乎希望使用客户端/服务器密钥(PSHA1 算法)使用hmac-sha1 身份验证代码对消息进行签名。很公平。然而 JAX-WS 似乎想要使用 rsa-sha1 和 X509 证书来签署出站消息(服务器不喜欢),并且似乎只在提供 UsernameToken 时才使用 hmac-sha1(服务器也不喜欢)。
所以我尝试从SOAPHandler 实现中手动签署出站SOAP 消息。客户端为获取安全上下文令牌而发送的请求如下所示:
<t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:Entropy>
<t:BinarySecret Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce">NzM1MDZjYWVkMTEzNDlkNGEyODY0ZDBlMjlkODEyMTM=</t:BinarySecret>
</t:Entropy>
<t:KeySize>256</t:KeySize>
</t:RequestSecurityToken>
服务器发回的令牌如下所示:
<t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
<t:RequestedSecurityToken>
<c:SecurityContextToken xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" u:Id="uuid-106bdbae-76e5-4195-b5d0-cc1c1a7a813e-13">
<c:Identifier>urn:uuid:c0be4929-da8d-4955-8e13-b25aa7a37217</c:Identifier>
</c:SecurityContextToken>
</t:RequestedSecurityToken>
<t:RequestedAttachedReference>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-106bdbae-76e5-4195-b5d0-cc1c1a7a813e-13" />
</o:SecurityTokenReference>
</t:RequestedAttachedReference>
<t:RequestedUnattachedReference>
<o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="urn:uuid:c0be4929-da8d-4955-8e13-b25aa7a37217" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
</o:SecurityTokenReference>
</t:RequestedUnattachedReference>
<t:RequestedProofToken>
<t:ComputedKey>http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1</t:ComputedKey>
</t:RequestedProofToken>
<t:Entropy>
<t:BinarySecret u:Id="uuid-106bdbae-76e5-4195-b5d0-cc1c1a7a813e-14" Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce">dssunihZGy2dnnDHV9PMe3vU3lg/kKKZQkFohvGvCAk=</t:BinarySecret>
</t:Entropy>
<t:Lifetime>
<u:Created>2016-04-08T04:11:54.392Z</u:Created>
<u:Expires>2016-04-08T19:11:54.392Z</u:Expires>
</t:Lifetime>
<t:KeySize>256</t:KeySize>
</t:RequestSecurityTokenResponse>
我正在使用PSHA1 组合客户端和服务器BinarySecret 密钥,如下所示:
private byte[] getSharedKey() {
try {
//FIXME: client key first, or server key first?
P_SHA1 algo = new P_SHA1();
return algo.createKey(getBinaryClientEntropy(), getBinaryServerEntropy(), 0, getSharedKeySize() / 8);
}
catch (Throwable e) {
LOG.error("Unable to compute shared key!", e);
}
return null;
}
然后我使用该密钥来计算消息的 MAC,例如:
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec key = new SecretKeySpec(getSharedKey(), "HmacSHA1");
mac.init(key);
byte[] signatureBytes = mac.doFinal(content);
String signature = Base64.encodeBytes(signatureBytes);
然后进入出站请求(以及大量其他样板文件),如SignatureValue。最终我得到了类似的东西:
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Header xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:scon="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:sec="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<sec:Security xmlns:env="http://www.w3.org/2003/05/soap-envelope" env:mustUnderstand="true">
<scon:SecurityContextToken xmlns:util="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" util:Id="uuid-106bdbae-76e5-4195-b5d0-cc1c1a7a813e-55">
<scon:Identifier>urn:uuid:3ab0f3fb-edd4-4880-af77-d700dda371bb</scon:Identifier>
</scon:SecurityContextToken>
<sig:Signature xmlns:sig="http://www.w3.org/2000/09/xmldsig#">
<sig:SignedInfo>
<sig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<sig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" />
</sig:SignedInfo>
<sig:SignatureValue>ohqViTbUYBG2E3hLldUA1AsPBJM=</sig:SignatureValue>
<sig:KeyInfo>
<sec:SecurityTokenReference>
<sec:Reference URI="#uuid-106bdbae-76e5-4195-b5d0-cc1c1a7a813e-55" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
</sec:SecurityTokenReference>
</sig:KeyInfo>
</sig:Signature>
</sec:Security>
</S:Header>
<S:Body>
<ns2:HelloWorld xmlns:ns2="http://tempuri.org/" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/">
<ns2:name>Test</ns2:name>
</ns2:HelloWorld>
</S:Body>
</S:Envelope>
这会导致服务器返回“验证消息安全性时出错”响应。
使用 wcf-storm 触发请求并使用 Fiddler2 检查传出数据包,我知道我应该关闭。以下请求正常工作:
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
<S:Header xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:scon="http://schemas.xmlsoap.org/ws/2005/02/sc" xmlns:sec="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="_0">
<u:Created>2016-04-05T23:48:06.110Z</u:Created>
<u:Expires>2016-04-05T23:53:06.110Z</u:Expires>
</u:Timestamp>
<c:SecurityContextToken xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc" u:Id="uuid-8085da33-b25c-4f09-b5a9-110635a3ae39-2005">
<c:Identifier>urn:uuid:91349027-cb32-4c46-9f16-74a6bcb11126</c:Identifier>
</c:SecurityContextToken>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" />
<Reference URI="#_0">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>AvRXi7pyjulsfdg9afInSFMM+5k=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>TQup7BBN43b8CefrdSRd+X8MBgg=</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-8085da33-b25c-4f09-b5a9-110635a3ae39-2005" />
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</S:Header>
<S:Body>
<ns2:HelloWorld xmlns:ns2="http://tempuri.org/" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/">
<ns2:name>Test</ns2:name>
</ns2:HelloWorld>
</S:Body>
</S:Envelope>
主要区别在于:
- 我已经省略了
Timestamp元素(尽管我尝试过包含它,但似乎没有任何区别)。 - 我省略了
SignedInfo/Reference元素,因为我不确定它的DigestValue是如何计算的。
因此,我想主要问题是:
签署出站消息的实际算法是什么?如果我有:
<Envelope>
<Header>
HHH...
</Header>
<Body>
BBB...
</Body>
</Envelope>
...我的意思是计算<Envelope>...</Envelope> 的签名值(所以整个事情),或者只是<Body>...</Body>,甚至只是BBB... 部分?如果我打算使用整个东西,我该如何协调这与将签名信息添加到标头会改变计算签名时用作输入的内容这一事实?
有没有更直接的方法让 JAX-WS 使用我忽略的所需签名约定生成请求?
还有一些小问题:
在使用
PSHA1组合它们时,是否有关于我传递客户端和服务器BinarySecret值的顺序的既定标准?Timestamp和SignedInfo/Reference条目是否重要,如果是,计算DigestValue的正确方法是什么?
【问题讨论】:
标签: java wcf soap soap-client