1

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.

1

Fixed by making the following changes:

Changed

PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias, privateKeyPass.toCharArray());

TO:

java.security.Key privateKey = (java.security.Key) ks.getKey(privateKeyAlias, privateKeyPass.toCharArray());

also moved

KeyStore ks = KeyStore.getInstance(keystoreType);
FileInputStream fis = new FileInputStream(keystoreFile);
ks.load(fis, keystorePass.toCharArray());
PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias, privateKeyPass.toCharArray());

and

 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);

in with the signing procedure.

In order to get the security information placed within <Security:wsse> I modified

element.getElementsByTagName("soapenv:Header").item(0).appendChild(sig.getElement());

to

element.getElementsByTagName("soapenv:Header").item(0).getElementsByTagName("wsse:Security").item(0).appendChild(sig.getElement());
0

If your web service expects only client-side request SSL encryption and no other security mechanisms are in place you don't even need any scripting.

  1. Change your HTTP Request implementation to Java
  2. Add the following lines to system.properties file (lives in JMeter's "bin" folder)

    javax.net.ssl.keyStore=C:/jMeterTest/resources/abbazabba.jks
    javax.net.ssl.keyStorePassword=XYZ
    
  3. If needed specify which key to use via Keystore Configuration

That's it. See How to Set Your JMeter Load Test to Use Client Side Certificates for detailed information on configuring JMeter-side requests encryption.

  • That was my first line of thinking, and that was unsuccessful. I've now found a fix for the problem detailed above, but am still working to put together the final pieces of the security header puzzle. – Jon Foley Jul 8 '16 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.