我想在肥皂消息中添加 wsse:security 。这是我的代码:
public Document signSoapMessage(SOAPMessage message) {
try {
Document doc = message.getSOAPBody().getOwnerDocument();
Crypto crypto = CryptoFactory.getInstance(properties); //File
WSSecHeader secHeader = new WSSecHeader(doc);
secHeader.insertSecurityHeader();
InputStream inStream = new FileInputStream(properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.file"));
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(inStream, properties.getProperty("privatekeypassword").toCharArray());
String alias = ks.aliases().nextElement();
X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
WSSecSignature sign = new WSSecSignature(secHeader);
sign.setX509Certificate(cert);
sign.setUserInfo(properties.getProperty("org.apache.ws.security.crypto.merlin.keystore.alias"), properties.getProperty("privatekeypassword"));
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE); // Binary Security Token - SecurityTokenReference
sign.setUseSingleCertificate(true);
sign.setDigestAlgo(DigestMethod.SHA1);
//sign.build(crypto);
Document signedDoc = sign.build(crypto);
return signedDoc;
} catch (SOAPException e) {
e.printStackTrace();
return null;
} catch (WSSecurityException e) {
e.printStackTrace();
throw new RuntimeException("Error: " + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (CertificateException e) {
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
} catch (KeyStoreException e) {
e.printStackTrace();
return null;
}
}
它适用于 soapenv:Body (确实会添加 wsu:Id 和 xmlns:wsu 参数)
但是 soapenv:Header 中有一个额外的元素,它不会对该元素签名。没有 wsu:Id 和 xmlns:wsu 参数,并且缺少一个ds:Reference。
未签名的肥皂味精的示例:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<!-- this element should be signed but is not - NOT WORKING -->
<something>
</something>
</soapenv:Header>
<!-- this element should be signed and It does. -->
<soapenv:Body>
</soapenv:Body>
</soapenv:Envelope>
我将程序中的肥皂味精与SoapUI项目中的工作肥皂味精进行了比较。
当我向Web服务发布消息时,出现错误:wsse:InvalidSecurity - Soap Header must be signed
。在SoupUI中,它确实有效。
所以我的问题是如何强制 WSS4j 在 soapenv:Header 内签名多余的元素?
答案 0 :(得分:3)
好,我已经解决了问题。
通常,此代码应适合我的情况。
//strange static method from apache o.O
org.apache.xml.security.Init.init();
List<WSEncryptionPart> wsEncryptionParts = new ArrayList<>();
WSEncryptionPart somethingPart = new WSEncryptionPart("something","somethingNamespace","");
wsEncryptionParts.add(somethingPart);
sign.addReferencesToSign(wsEncryptionParts);
但是,它不起作用。它总是抛出异常:
org.apache.wss4j.common.ext.WSSecurityException:没有标识为ID的消息 在资源包中找到“ noXMLSig” “ org / apache / xml / security / resource / xmlsecurity”。原“例外”为 org.apache.wss4j.common.ext.WSSecurityException和消息否 资源束中找到标识为“ noEncElement”的消息 “ org / apache / xml / security / resource / xmlsecurity”
我找不到我的肥皂消息或代码有问题的答案。
但是,在调试 org.apache.wss4j.dom.message.WSSecSignature 一段时间之后。我觉得这堂课有些问题。我决定修改方法 build(Crypto cr)。
public Document build(Crypto cr) throws WSSecurityException {
LOG.debug("Beginning signing...");
this.prepare(cr);
if (this.getParts().isEmpty()) {
this.getParts().add(WSSecurityUtil.getDefaultEncryptionPart(this.getDocument()));
// --- Here is my edit - And it works!
WSEncryptionPart aaa = new WSEncryptionPart("something","somethingNamespace","");
this.getParts().add(aaa);
// ----------------------------------
} else {
Iterator var2 = this.getParts().iterator();
label33:
while(true) {
while(true) {
if (!var2.hasNext()) {
break label33;
}
WSEncryptionPart part = (WSEncryptionPart)var2.next();
if (part.getId() == null && "STRTransform".equals(part.getName())) {
part.setId(this.strUri);
} else if ("KeyInfo".equals(part.getName()) && "http://www.w3.org/2000/09/xmldsig#".equals(part.getNamespace()) && part.getElement() == null) {
Element keyInfoElement = this.getKeyInfoElement();
part.setElement(keyInfoElement);
}
}
}
}
List<javax.xml.crypto.dsig.Reference> referenceList = this.addReferencesToSign(this.getParts());
this.computeSignature(referenceList);
if (this.bstToken != null) {
this.prependBSTElementToHeader();
}
return this.getDocument();
}
当然,解决方案很弱。但是,至少现在可以使用。
该问题存在于最新版本中:
wss4j-ws-security-dom 2.2.2
wss4j-ws-security-common 2.2.2
答案 1 :(得分:0)
我猜它应该可以这样工作:
WSSecSignature sign = new WSSecSignature(secHeader);
sign.getParts().addAll(getEncryptionParts());
使用getEncryptionParts()作为要添加的WSEncryptionPart列表。 如果以这种方式添加,则build方法能够找到它们,而无需修补框架。