1

I am working with Jmeter and Blazemeter in a login script for a web made with Genexus. The problem that I am having is in the POST.

Whenever I try to make a POST http petition, Jmeter throws the next thing: enter image description here

As you can see, in the response body, I am having a 440 http error code. This is a login Time-out which means the client's session has expired and must log in again. I used to have a 403 error code but now, after doing some arrangements, I have 440. Do you have any suggestions on how to resolve this?

Mauricio Estevez
  • 419
  • 1
  • 6
  • 21

2 Answers2

1

Any HTTP Status 4xx is a client error, to wit you're sending an incorrect request.

If custom 440 http status code means "session has expired" my expectation is that you have a recorded hard-coded session ID somewhere in your request parameters or headers

You should carefully inspect previous response(s) and look for something which appears to be a session id, once you find it - extract it using a suitable JMeter's Post-Processor and replace hard-coded session ID with the appropriate JMeter Variable. The process is known as correlation

Dmitri T
  • 159,985
  • 5
  • 83
  • 133
1

First, I'm not an expert on Genexus. All my findings are from a black-box point of view.

Genexus Security

I found that Genexus requires at least two things to authenticate on Web Application (I tested only Java and .Net generated apps).

  1. The GXState parameter. This param is sent in post request, and from my understanding works as "Synchronizer token pattern", see more info on Cross-site request forgery. We need to send this param on every post request.

  2. The gxajaxEvt parameter. This is very specific to Genexus Apps. In the documentation mentions this parameter is send encrypted in the URL, and this behavior is managed by the "Javascript debug mode property":

# Javascript Debug Mode: Yes
http://{server}:{port}/{webappname}/servlet/com.{kbname}.{objectname}?gxfullajaxEvt,gx-no-cache=1442811265833
# Javascript Debug Mode: No (default value)
http://{server}:{port}/{webappname}/servlet/com.{kbname}.{objectname}?64df96a2d9b8480aed416e470dae529e,gx-no-cache=1442811265833

JMeter Script

  1. So, to get the GXState, we can use the Regular Expression Extractor: Regular Expression Extractor

    Name of created variable: GXState

    Regular expression: name="GXState" value='(.*?)'

    Template: $1$

    Match No.: 1

    Default Value: NOT_FOUND

  2. The GXState is a JSON, object, from it we can extract the GX_AJAX_KEY to encrypt gxajaxEvt string. Note that, I found the GX_AJAX_KEY is the key used to encrypt in this case, but some others could apply. We can debug this using Browser Web Console, with this:

gx.sec.encrypt("gxajaxEvt")

We'll see something like this: "8722e2ea52fd44f599d35d1534485d8e206d507a46070a816ca7fcdbe812b0ad"

As we can found, all the client encryption code is in the gxgral.js file. Genexus uses the Rijndael algortihm (Sub set of AES) with block size of 128 bits.

Browser Web Console

To emulate this client behavior in the JMeter Script we can use the "JSR 233 sampler". A way to get the Rijndael results is use the Bouncy Castle library. We need to add this jar (bouncycastle:bcprov-jdk15to18:1.68) to the JMeter's lib folder to use it.

Our code script will be something like this (Language Groovy 3.0.5/Groovy Scripting Engine 2.0):

import com.jayway.jsonpath.JsonPath
import java.nio.charset.StandardCharsets
import java.util.Arrays
import org.bouncycastle.crypto.BufferedBlockCipher
import org.bouncycastle.crypto.InvalidCipherTextException
import org.bouncycastle.crypto.engines.RijndaelEngine
import org.bouncycastle.crypto.params.KeyParameter
import org.bouncycastle.util.encoders.Hex
import org.apache.jmeter.threads.JMeterContextService
import org.apache.jmeter.threads.JMeterContext
import org.apache.jmeter.threads.JMeterVariables

String gxState = vars.get('GXState')
String gxAjaxKey = JsonPath.read(gxState,'$.GX_AJAX_KEY')
byte[] input = Arrays.copyOf('gxajaxEvt'.getBytes(StandardCharsets.UTF_8), 16)
RijndaelEngine engine = new RijndaelEngine(128)
KeyParameter key = new KeyParameter(Hex.decode(gxAjaxKey))
BufferedBlockCipher cipher = new BufferedBlockCipher(engine)
cipher.init(true, key)
byte[] out = new byte[16]
int length = cipher.processBytes(input, 0, 16, out, 0)
cipher.doFinal(out, length)
String encryptedOutput= Hex.toHexString(out)
log.info 'gx.sec.encrypt("gxajaxEvt")='+encryptedOutput
String gxNoCache = String.valueOf(System.currentTimeMillis())
log.info 'gx-no-cache='+gxNoCache
vars.put('gxajaxEvt', encryptedOutput)
vars.put('gxNoCache', gxNoCache)

The script work like this:

  • First, We get the previos GXState variable extracted.
  • Second, Using JSON Path (Already available in JMeter 5.4.1) extract the GX_AJAX_KEY property.
  • Third, We apply the Rijndael algorithm over the gxajaxEvt using the GX_AJAX_KEY as a key.
  • We also create the gx-no-cache to handle the cache.

JSR233 Sampler

  1. With these variables we can send the next request successfully: Next HTTP Request

We can found this sample JMeter script available here.

For complex scripts, please refer to this guide (Requires GXTest)

In case we get this exception in JMeter ( java.util.zip.ZipException: Not in GZIP format) please refer this answer too.

JuanMoreno
  • 2,498
  • 1
  • 25
  • 34