I am implementing a Java web service client that uses wss4j 1.6.8 for WS-Security (to be more certain, I need to sign a SOAP message). The server side requires that the requests 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 elements and timestamps), but for some reason wss4j places the timestamp element at the bottom of the section, after <wsse:BinarySecurityToken> and <Signature> elements, which is not the case. Please check the sources that signed the contract:
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 help me clarify how to reorder the elements before the document is familiar? Thanks!
source share