>事实证明,我已经通过 soapUI 测试了一个 Web 服务,使用我获得的 pem 证书配置密钥库。
当我应用传出的 WSSE 签名时,我得到一个 wsse:Security 元素,如下所示:
<wsse:Security
xmlns:wsse="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">
<ds:Signature Id="SIG-1C747258C55C77E5C5154835835043446"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="hal ns ns1 ns2 soapenv"
xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-1C747258C55C77E5C515483521292064">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="hal ns ns1 ns2"
xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>AfQsslNyqfZcR2GwBV+0vtAuO/c=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
[THE SIGNATURE]
</ds:SignatureValue>
<ds:KeyInfo Id="KI-1C747258C55C77E5C5154835835043344">
<wsse:SecurityTokenReference wsu:Id="STR-1C747258C55C77E5C5154835835043345">
<wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">VwDFSfuw3Zk0GeAG4PhV8YWZ2P4=</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
我对使用 nodejs 生成这个确切的块感兴趣。我尝试使用 soap 包,但它总是返回错误"无法解析请求",如果我用这个替换签名块,它会起作用。
所以基本上我想知道手动签署正文和替换哈希的步骤,然后在这个块中替换它们并做一个简单的帖子:)
我希望你不要觉得这个问题很幼稚(我对 SOAP 网络服务很陌生)。
谢谢!
我放弃了用nodeJS做这件事,而是用java来做这件事。这是我是如何做到的:
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.message.WSSecHeader;
import org.apache.ws.security.message.WSSecSignature;
import org.apache.xml.security.algorithms.MessageDigestAlgorithm;
import org.apache.xml.security.signature.XMLSignature;
import org.w3c.dom.Document;
import java.io.StringWriter;
import java.util.Properties;
import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;
public class WSSecuritySign {
public static void signXml() throws Exception {
final String req = new String(readAllBytes(get("target/classes/test.xml"))); //the soap envelope to be signed without the security header
final Document soapDocument = XmlUtils.parseXml(req);
final WSSecHeader secHeader = new WSSecHeader();
final WSSecSignature wssSign = new WSSecSignature();
final Crypto wssCrypto = getCrypto();
secHeader.insertSecurityHeader(soapDocument);
wssSign.setSignatureAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
wssSign.setSigCanonicalization(WSConstants.C14N_EXCL_OMIT_COMMENTS);
wssSign.setUseSingleCertificate(false);
wssSign.setDigestAlgo(MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1);
wssSign.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
wssSign.setUserInfo("keystore_alias", "a_password");
wssSign.setKeyIdentifierType(4); //Or Subject Key Identifier
wssSign.build(soapDocument, wssCrypto, secHeader);
final StringWriter writer = new StringWriter();
XmlUtils.serialize(soapDocument.getDocumentElement(), writer);
System.out.println(writer.toString());
}
public static void main(String... unused) throws Exception {
signXml();
}
public static Crypto getCrypto() throws Exception {
Properties props = new Properties();
props.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
props.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", "a_password");
props.setProperty("org.apache.ws.security.crypto.merlin.keystore.alias", "keystore_alias");
props.setProperty("org.apache.ws.security.crypto.merlin.keystore.file", "keystore.jks");
return CryptoFactory.getInstance(props, ClassLoader.getSystemClassLoader());
}
}
不要忘记替换您的密钥库别名、密钥库位置和密码短语(如果有),我认为如果您的密钥库没有默认密码,则有一个默认密码短语,不记得它是如何命名的。