I'm implementing web service client in Java which uses wss4j 1.6.8 for WS-Security (to be more precize I need to sign a SOAP message). Server side requires requests to have the following structure:
<Envelope>
<Header>
<wsse:Security mustUnderstand="1">
**<wsu:Timestamp wsu:Id="Timestamp-913ca68e-05ed-44e1-9d6c-b2f293da5a1d">
<wsu:Created>2012-12-21T11:37:31Z</wsu:Created>
<wsu:Expires>2012-12-21T11:42:31Z</wsu:Expires>
</wsu:Timestamp>**
<wsse:BinarySecurityToken>
MIID2jCCAsKg...
</wsse:BinarySecurityToken>
<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#rsa-sha1"/>
<Reference URI="#Timestamp-913ca68e-05ed-44e1-9d6c-b2f293da5a1d">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>jdVY1HaDLusqO9UcxASE/GQHxyo=</DigestValue>
</Reference>
<Reference URI="#Body-e344eef1-2d8a-42d0-8a30-361ee61a8617">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>L60mQelZERvXgLEgWlW50uJNqEA=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
NmgACUqrYYc/Kp/F...
</SignatureValue>
<KeyInfo>
<wsse:SecurityTokenReference xmlns="">
<wsse:Reference URI="#SecurityToken-3f054298-711c-4090-95c3-105e1093f3ba" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
</wsse:Security>
</S:Header>
<S:Body>
Body content...
</S:Body>
</Envelope>
My solution signs the document (both body and timestamp elements) but for some reason wss4j puts timestamp element to the bottom of the section, after <wsse:BinarySecurityToken>
and <Signature>
elements what is wrong. Please look at the sources that does signing job:
public static SOAPMessage signSoapMessage(SOAPMessage message, PrivateKey signingKey, X509Certificate signingCert, char[] passphrase) throws WSSecurityException {
final String alias = "signingKey";
final int signatureValidityTime = 3600; // 1hour in seconds
WSSConfig config = new WSSConfig();
config.setWsiBSPCompliant(false);
WSSecSignature builder = new WSSecSignature(config);
builder.setX509Certificate(signingCert);
builder.setUserInfo(alias, new String(passphrase));
builder.setUseSingleCertificate(true);
builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
try {
Document document = DanskeUtils.toDocument(message);
WSSecHeader secHeader = new WSSecHeader();
secHeader.setMustUnderstand(true);
secHeader.insertSecurityHeader(document);
WSSecTimestamp timestamp = new WSSecTimestamp();
timestamp.setTimeToLive(signatureValidityTime);
document = timestamp.build(document, secHeader);
List<WSEncryptionPart> parts = new ArrayList<WSEncryptionPart>();
WSEncryptionPart timestampPart = new WSEncryptionPart("Timestamp", WSConstants.WSU_NS, "");
WSEncryptionPart bodyPart = new WSEncryptionPart(WSConstants.ELEM_BODY, WSConstants.URI_SOAP11_ENV, "");
parts.add(timestampPart);
parts.add(bodyPart);
builder.setParts(parts);
Properties properties = new Properties();
properties.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
Crypto crypto = CryptoFactory.getInstance(properties);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null, passphrase);
keystore.setKeyEntry(alias, signingKey, passphrase, new Certificate[]{signingCert});
((Merlin) crypto).setKeyStore(keystore);
crypto.loadCertificate(new ByteArrayInputStream(signingCert.getEncoded()));
document = builder.build(document, crypto, secHeader);
return Utils.updateSoapMessage(document, message);
} catch (Exception e) {
throw new WSSecurityException(WSSecurityException.Reason.SIGNING_ISSUE, e);
}
}
Could you please help me to clarify how to change the order of elements before document will be sign? Thank you!
The WS-SEC specification says "As elements are added to a header block, they SHOULD be prepended to the existing elements."
So if you first add the timestamp it will be above any existing child elements in the ws-header. Since you are signing message after adding the timstamp, the signing info will be again preappended to the header, thus it will appear above the timestamp element.
If you need the timestamp element to appear at the very top, add it to the header as the final process
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With