How do I sign parameters in JMeter?

This installment continues Groovy’s use of parameter signing in JMeter by using the Groovy utility class for parameter signing.

This situation is common in interface testing, where one parameter of the interface is determined by another parameter (including the checktoken), and in my experience is common in PHP backend services. Here’s how to handle this situation with Groovy utility classes. The code comes from development and you can just copy it, which is one of the reasons I chose Groovy: its near-perfect compatibility with Java. The Groovy script content in the code is the same as the previous one, with key information omitted.

  • Start by creating a simple thread group and a simple request:

  • Add the JSR223 preprocessor

Script content:

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

vars.put("MY1"."flow")
props.put("MY"."ewewewerr")
log.info(props.get("MY"))
sampler.addArgument("name"."funteddster")
sampler.addArgument("pwd"."funtddester")

def args = sampler.getArguments()
def ss = [:]
log.info(sampler.getArguments().toString())
args.getArgumentCount().times{
	def a = args.getArgument(it)
	ss.put(a.ARG_NAME,a.VALUE)
}

def my_var = RSAUtilLJT.sign(ss,RSAUtilLJT.getPrivateKey(RSAUtilLJT.RSA_PRIVATE_KEY)) as String;

log.warn "Output parameters -------- ${vars} console"
log.info("222222" + my_var);

sampler.addArgument("sign", my_var)



public class RSAUtilLJT {

    /** * The maximum encrypted plaintext size of RSA */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /** * Maximum size of RSA ciphertext */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * RSA私钥
     */
    public static final String RSA_PRIVATE_KEY= "Confidential Content";
    /** * RSA public key */
    public static final String RSA_PUBLIC_KEY= "Confidential Content";

    /** * does not participate in the signature parameter */
    private static final String excludeKey = "sign";


    /** * get the private key **@paramPrivateKey privateKey character string *@return* /
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }

    /** * Get public key **@paramPublicKey publicKey character string *@return* /
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }

    /** * RSA encryption **@paramData Indicates the data to be encrypted@paramPublicKey public key *@return* /
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // Encrypt data in segments
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // Get the encrypted content encoded using Base64 and converted to a string using UTF-8 standards
        // An encrypted string
        return new String(Base64.encodeBase64String(encryptedData));
    }

    /** * RSA decryption **@paramData Data to be decrypted *@paramPrivateKey private key *@return* /
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] dataBytes = Base64.decodeBase64(data);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // decrypt data in segments
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // The decrypted content
        return new String(decryptedData, "UTF-8");
    }

    /** ** signature **@paramData Data to be signed *@paramPrivateKey private key *@returnSignature * /
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        return new String(Base64.encodeBase64(signature.sign()));
    }

    /** * check the signature **@paramSrcData The original string *@paramPublicKey public key *@paramSign the signature *@returnCheck whether the visa is approved */
    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64.decodeBase64(sign.getBytes()));
    }

    /** * Sign the map *@param mapData
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String sign(Map<String, String> mapData, PrivateKey privateKey) throws Exception {
        return sign(getStr(mapData), privateKey);
    }

    /** * Signature verification *@paramMapData parameter map *@paramPublicKey public key *@return
     * @throws Exception
     */
    public static boolean verify(Map<String, String> mapData, PublicKey publicKey) throws Exception {
        String sign = mapData.remove(excludeKey);
        if (sign == null || sign.length() < 1) {
            throw new RuntimeException("Parameter missing signature");
        }
        return verify(getStr(mapData), publicKey, sign);
    }

    /** * Interface request parameter to string *@param parms
     * @return* /
    public static String getStr(Map<String, String> parms) {
        parms.remove(excludeKey);
        TreeMap<String, String> sortParms = new TreeMap<>();
        sortParms.putAll(parms);
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, String> entry : parms.entrySet()) {
            builder.append(entry.getKey());
            builder.append("=");
            builder.append(String.valueOf(entry.getValue()));
            builder.append("&");
        }
        if (builder.length() > 1) {
            builder.setLength(builder.length() - 1);
        }
        returnbuilder.toString(); }}Copy the code
  • Console output:
2020-04-17 17:13:30.989 INFO o.a.j.e.StandardJMeterEngine: Running the test!
2020-04-17 17:13:30.991 INFO o.a.j.s.SampleEvent: List of sample_variables: []
2020-04-17 17:13:31.008 INFO o.a.j.g.u.JMeterMenuBar: setRunning(true, *local*)
2020-04-17 17:13:31.208 INFO o.a.j.e.StandardJMeterEngine: Starting ThreadGroup: 1: the thread group2020-04-17 17:13:31.208 INFO o.a.j.e.StandardJMeterEngine: Starting 1 threads forGroup Thread group.2020-04-17 17:13:31.208 INFO o.a.j.e.StandardJMeterEngine: Thread will continue on error
2020-04-17 17:13:31.209 INFO o.a.j.t.ThreadGroup: Starting thread group... number=1 threads=1 ramp-up=0 perThread=0.0 delayedStart=false
2020-04-17 17:13:31.210 INFO o.a.j.t.ThreadGroup: Started thread group number 1
2020-04-17 17:13:31.213 INFO o.a.j.e.StandardJMeterEngine: All thread groups have been started
2020-04-17 17:13:31.216INFO O.A.J.T. JMeterThread: Thread started: Indicates the Thread group1-1
2020-04-17 17:13:31.337INFO O.A.J.M.J.Jsr223 Parameter signature Groovy class: ewewewerr2020-04-17 17:13:31.341INFO O.a.j.m.j.jsr223 Parameter signature Groovy class: t=flow()& S =ewewewerr()&name=funteddster()& PWD =funtddester()2020-04-17 17:13:31.360WARN O.A.J.M.J.J SR223 parameter Groovy classes: the output parameters -- -- -- -- -- -- -- --. Org. Apache jmeter. Threads. JMeterVariables @7bdab282 console
2020-04-17 17:13:31.361INFO o.A.j.M.j.jsr223 Parameter signature Groovy class:222222DV1UC0RF7y7FWArtYJP8LaUYwWZm7Mc5P8vmx5e4cGqQstaW3LlfR+o5mSiBTTxLY3NSvsr5EHLkLzPcfJ3YCmjJnneZj+lCb7fR7XA5snwGHJNbeDejn6x3 oNVEZF8i4MR/vPO9I1lawA6pEuO5t7kW21IizQdEyxAc2pxLcj8=2020-04-17 17:13:31.495INFO O.A.J.T. JMeterThread: Thread is done: indicates the Thread group1-1
2020-04-17 17:13:31.495INFO O.A.J.T. JMeterThread: Thread Finished: Indicates the Thread group1-1
2020-04-17 17:13:31.495 INFO o.a.j.e.StandardJMeterEngine: Notifying test listeners of end of test
2020-04-17 17:13:31.495 INFO o.a.j.g.u.JMeterMenuBar: setRunning(false, *local*)


Copy the code
  • View the result tree

  • You can clearly see the signature fieldsignIt’s already written into the parameters.

  • Solemnly declare: “FunTester” first, welcome to pay attention to the exchange, prohibit third party reprint.

The JMeter series has written a number of articles, so I would like to post a full set of enhanced versions of the Demo as well.

  • Handle JMeter assertions and logging with Groovy
  • Handle JMeter variables with Groovy
  • Execute command lines in JMeter using Groovy
  • Handle request parameters in JMeter with Groovy
  • Use Groovy to extract assignments using regex in JMeter
  • JMeter throughput error analysis
  • Groovy handles cookies in JMeter
  • Groovy handles headers in JMeter