Putting together a SOAP Request in JMeter
. My request is valid, as it succeeds in SOAPUI
. My issue is getting the request's Security header populated. I'm attempting to generate the security header with the code below, but I keep encountering the following exception:
2016/07/07 09:24:44 ERROR - jmeter.modifiers.JSR223PreProcessor: Problem in JSR223 script JSR223 PreProcessor.2 javax.script.ScriptException: Sourced file: inline evaluation of:
import com.sun.org.apache.xml.internal.security.Init; import com.sun.org.apache. . . .
: JMert : at Line: 78 : in file: inline evaluation of:
import com.sun.org.apache.xml.internal.security.Init; import com.sun.org.apache. . . .
: ( privateKey ) in inline evaluation of: ``import com.sun.org.apache.xml.internal.security.Init; import com.sun.org.apache. . . . '' at line number 78
As far as I can tell, the privateKey is properly declared in the code I'm using. As expected, when I run the testplan in JMeter the SOAP response is that the request is missing the security headers.
import com.sun.org.apache.xml.internal.security.Init;
import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
import com.sun.org.apache.xml.internal.security.transforms.Transforms;
import com.sun.org.apache.xml.internal.security.utils.Constants;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.apache.jmeter.protocol.http.sampler.SoapSampler;
import org.apache.commons.io.FileUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
//write sampler body into "signature.xml" file
String body = sampler.getXmlData();
FileUtils.writeStringToFile(new File("signature.xml"),body);
File signatureFile = new File("signature.xml");
//X509 properties
String keystoreType = "JKS";
String keystoreFile = "C:/jMeterTest/resources/abbazabba.jks";
String keystorePass = "XYZ";
String privateKeyAlias = "abba";
String privateKeyPass = "XYZ";
String certificateAlias = "abbazabba";
Element element = null;
String BaseURI = signatureFile.toURI().toURL().toString();
//SOAP envelope to be signed
//get the private key used to sign, from the keystore
KeyStore ks = KeyStore.getInstance(keystoreType);
FileInputStream fis = new FileInputStream(keystoreFile);
ks.load(fis, keystorePass.toCharArray());
PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias, privateKeyPass.toCharArray());
//create basic structure of signature
javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
String request = sampler.getXmlData();
ByteArrayInputStream in = new ByteArrayInputStream(request.getBytes());
Document doc = dBuilder.parse(in);
in.close();
Init.init();
XMLSignature sig = new XMLSignature(doc, BaseURI, XMLSignature.ALGO_ID_SIGNATURE_RSA);
element = doc.getDocumentElement();
element.normalize();
element.getElementsByTagName("soapenv:Header").item(0).appendChild(sig.getElement());
{
Transforms transforms = new Transforms(doc);
transforms.addTransform(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
//Sign the content of SOAP Envelope
sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
}
//Signing procedure
{
X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias);
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
sig.sign(privateKey);
}
//write signature to file
FileOutputStream f = new FileOutputStream(signatureFile);
XMLUtils.outputDOMc14nWithComments(doc, f);
f.close();
//set sampler's XML data from file
String request = FileUtils.readFileToString(signatureFile);
sampler.setXmlData(request);
Further, if I comment out sig.sign(privateKey);
the security information is populated in the security header, however the formatting and data insertion is incorrect and the request fails with Invalid Security message.