wildview
8 years agoSenior Member
WS-Security SOAP signing error - Help!
Hi, I'm completely new to using the WS-Security methods to sign an xml payload and need some help to understand why my SOAP signing code is throwing an exception error when trying to addReferencesToSign. I need to sign an xml document using a BinarySecurityToken type. There is something that I’m just not configuring correctly w/ the WSSecSignature method, the raw xml template or something else. Can someone please help me by looking at the code below to see what is missing or out of sequence?
Exception error on the addReferencesToSign method:
The sign.addReferencesToSign(signParts,secHeader) is throwing Error::signSoapMessage - No message with ID "noXMLSig" found in resource bundle "org/apache/xml/security/resource/xmlsecurity". Original Exception was a org.apache.wss4j.common.ext.WSSecurityException and message No message with ID "noEncElement" found in resource bundle "org/apache/xml/security/resource/xmlsecurity"
The Raw xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">> </wsse:Security> </Header> <soapenv:Body> <OrganizationIdentification>Id</OrganizationIdentification> </soapenv:Body> </soapenv:Envelope>
Signing code:
import java.io.*; // SOAP keystore imports import java.security.Key; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.security.cert.Certificate // SOAP xml document imports import javax.xml.parsers.DocumentBuilder; import org.apache.commons.io.IOUtils; import org.apache.xml.security.Init; import org.apache.xml.security.c14n.Canonicalizer; import org.apache.xml.security.signature.XMLSignature; import org.apache.xml.security.transforms.Transforms; import org.apache.xml.security.utils.Constants; import org.apache.xml.security.utils.ElementProxy; import org.xml.sax.InputSource import org.w3c.dom.Document; import javax.xml.parsers.DocumentBuilderFactory; // SOAP signing imports import org.apache.wss4j.common.ext.WSSecurityException; import org.apache.wss4j.common.crypto.Merlin; import org.apache.wss4j.common.WSEncryptionPart import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.dom.engine.WSSConfig import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.dom.message.WSSecHeader; import org.apache.wss4j.dom.message.WSSecSignature; import org.apache.wss4j.dom.message.WSSecTimestamp; import org.apache.wss4j.common.crypto.CryptoFactory; import org.apache.wss4j.dom.message.WSSecUsernameToken; public ByteArrayOutputStream signSoapMessage(String xmlFile, File privateKeyFile) throws WSSecurityException { final int signatureValidityTime = 3600; // 1hour in seconds try { //WSSConfig config = new WSSConfig(); //config.setWsiBSPCompliant(false); // Open keystore and create signingCert KeyStore keyStore = loadKeyStore(privateKeyFile); Key privateKey = keyStore.getKey(PRIVATE_KEY_ALIAS, PRIVATE_KEY_PASS.toCharArray()); final X509Certificate signingCert = (X509Certificate)keyStore.getCertificate(PRIVATE_KEY_ALIAS); Certificate[] lChain = new Certificate[1]; lChain[0]= signingCert; keyStore.setKeyEntry(PRIVATE_KEY_ALIAS, privateKey, KEY_STORE_PASS.toCharArray(), lChain); // Load XML message into document and build header Document document= xmlToDoc(xmlFile); WSSecHeader secHeader = new WSSecHeader(document); secHeader.setMustUnderstand(true); secHeader.insertSecurityHeader(); // Setup timeStamp token to add WSSecTimestamp secTimeStamp = new WSSecTimestamp(); secTimeStamp.setTimeToLive(signatureValidityTime); secTimeStamp.prepare(document); //secTimeStamp.prependToHeader(secHeader); // Setup userName token to add WSSecUsernameToken secUsernameToken = new WSSecUsernameToken(); secUsernameToken.setPasswordType(WSConstants.PASSWORD_TEXT); secUsernameToken.setUserInfo(USER_INFO_NAME, USER_INFO_PWD); secUsernameToken.addNonce(); secUsernameToken.addCreated(); secUsernameToken.prepare(document); // Setup signature to sign document WSSecSignature sign = new WSSecSignature(); String bstId = sign.getBSTTokenId(); sign.appendBSTElementToHeader(secHeader); sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE); sign.setX509Certificate(signingCert); sign.setUserInfo(PRIVATE_KEY_ALIAS, new String(KEY_STORE_PASS.toCharArray())); sign.setUseSingleCertificate(true); sign.setSignatureAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1); sign.setDigestAlgo("http://www.w3.org/2000/09/xmldsig#sha1"); sign.setSigCanonicalization(WSConstants.C14N_EXCL_OMIT_COMMENTS); // Add crypto properties to document Properties cxfProps = new Properties(); cxfProps.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin"); Crypto crypto = CryptoFactory.getInstance(cxfProps); ((Merlin) crypto).setKeyStore(keyStore); crypto.loadCertificate(new ByteArrayInputStream(signingCert.getEncoded())); sign.prepare(document, crypto, secHeader); // Add signing references to header List<WSEncryptionPart> signParts = new ArrayList<WSEncryptionPart>(); signParts.add(new WSEncryptionPart(WSConstants.ELEM_BODY,WSConstants.URI_SOAP12_ENV, "")); signParts.add(new WSEncryptionPart(bstId)); signParts.add(new WSEncryptionPart(secTimeStamp.getId(), WSConstants.WSU_NS, "")); // *** Throws exception on addReferencesToSign method below sign.addReferencesToSign(signParts,secHeader); List<Reference> referenceList = sign.addReferencesToSign(signParts, secHeader); sign.computeSignature(referenceList, false, null); document= sign.build(document, crypto, secHeader); // Write signed document to output stream final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); outputStream.write(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(document)); //String result=DOM2Writer.nodeToString(signedDoc); // return signed payload return outputStream; } catch (Exception e) { dPrintln("Error::signSoapMessage - " + e.message); throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE,e); } }
Thanks in advance,
Rob