JMeter - Using cookie field as variable - jmeter

have been looking into JMeter recently. I need to get an authentication string from a cookie and use it when posting a request to a different path. The Auth string changes each time the login page is hit.
Is there a way in JMeter to use one cookie for all paths in a test when the paths are different?
IE-
Path to Get Cookie:
Webserver: someURL.net
Path: /some/login/path
Use the cookie value:
Webserver: someURL.net
Path: /somewhere/different
I have set the below JMeter properties to be able to use Cookies as needed.
CookieManager.check.cookies=false
CookieManager.save.cookies=true
CookieManager.allow_variable_cookies=true
When I run the samplers the result for the request to /somewhere/different
Returns [no cookies]
I can see the cookie data present in the Request when the path is /some/login/path
I have tried defining a User-Defined cookie but I need to get the auth string first to use it in the different path.
When I do this I can see the cookie data added to the request to /somewhere/different but the var is not being set. I don't think this is the right way to solve the challenge.
To get the auth string first I tried to use the Controller "User defined Variables" to store the cookie value and pass it back to the Cookie Manager- this did not work.
And I looked at using the RegEx extractor to get the value so I could use it but I'm not sure that this can be used to get cookie values?
My understanding is that you cannot use more than one cookie manager per Thread group. As I type this I realize that the solution might be that I must use separate threads and pass the cookie value from one thread to another.
Apologies if the question is framed poorly first time here, signed up to ask after searches didn't turn up a solution. If you need more info/screens of my JMeter set up for any of the scenarios I tried above I'll add them. And thank you.

I'm afraid you won't be able to manipulate cookies using built-in JMeter features, you'll need to go deeper and invoke JMeter API methods from scripting test elements.
For instance:
Add a Beanshell PostProcessor as a child of the first request
Put the following code into the PostProcessor(s) "Script" area:
import org.apache.jmeter.protocol.http.control.Cookie;
import org.apache.jmeter.protocol.http.control.CookieManager;
CookieManager manager = ctx.getCurrentSampler().getCookieManager();
for (int i = 0; i < manager.getCookieCount(); i++) {
Cookie cookie = manager.get(i);
if (cookie.getName().equals("your_cookie_name")) {
Cookie newCookie = cookie;
newCookie.setPath("/your/new/path");
manager.remove(i);
manager.add(newCookie);
ctx.getCurrentSampler().setCookieManager(manager);
break;
}
}
Change your_cookie_name and /your/new/path as per your requirements
It will create a new one with the different path. JMeter's HTTP Cookie Manager doesn't allow 2 cookies with the same name so the old one has to be removed.
References:
CookieManager class JavaDoc
JMeterContext class JavaDoc
How to Use BeanShell: JMeter's Favorite Built-in Component guide - overview of scripting, extra information on pre-defined variables, "cookbook" with some examples.

Related

Jmeter 440 error code. How can I resolve this error?

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:
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?
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).
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.
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
So, to get the GXState, we can use the Regular Expression Extractor:
Name of created variable: GXState
Regular expression: name="GXState" value='(.*?)'
Template: $1$
Match No.: 1
Default Value: NOT_FOUND
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.
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.
With these variables we can send the next request successfully:
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.
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

JMeter RegUx User Parameters not adding parameter

New to JMeter, and I'm probably missing some simple thing but I can't find it anywhere.
I'm trying to log into a web application so I send a GET request to the home page to retrieve the csrf token and then I use the regular expression extractor to retrieve it:
I then try to place the extracted token into the POST request:
But the extracted token doesn't show up in the request sent via the View Results Tree. Only the UserId and Password are passed which I manually defined:
My regular expression is finding a match as you can see here:
but even if it wasn't finding a match, it should still pass "NotFound" correct?
Any help is greatly appreciated!
Edit: Added a Debug Sampler and it is correctly showing the variable Token with it's correct value. So Token just isn't being added to the request via the RegEx User Parameter Pre Processor.
It's difficult to see what you're doing without seeing the LoginPage step, but you need to make sure you are adding the csrf token you've extracted in the right place.
Typically it could be as a query param, part of a post body or an http header.
As you can see the token has been extracted from your initial response in the Debug sampler, there must be something wrong in how or where the token is being applied to the LoginPage request. (As you say the RegEx User Parameter Pre Processor isn't adding it)
I've never used the PreProcessor and the Jmeter documentation explanation is a bit vague on what it does, but you can add the variables into your request without it using the variable saved for the capture groups - for input name this will be ${Token_g1} and for value it will be ${Token_g2} - which you will be able to see from the Debug Sampler. You'll need to add a Header or Cookie Manager to the Login Page element if this is where the token is.
By setting the template in the Extractor to $1$$2$ you create a variable with the name and value concatenated together. I'm not sure why you would need this, and I would guess that the name doesn't change - in which case you can just use capture group 2, or if you want to use the Variable name Token then update your template to be $2$

Get the path of an HTTP Request from another component

I am trying to let JMeter crowl my website to ensure a realistic stress test. I was able to extract the URLs from the home page and iterate on them. So I have a regular expression feeding a ForEach loop.
Now I am not able to let an HTTP Request take the output of the loop (Defined as a variable with a name) as its path.
Is there a general approach to setting the path of such a request. JMeter is taking something like:
${MyVar}
set in the path of the request as a string and is not replacing it with the actual value.
Given your Regular Expression Extractor and ForEach Controller configurations are correct everything should work fine. If you need any assistance with this provide the following screenshots:
Regular Expression Extractor configuration
Debug PostProcessor or Debug Sampler output in the View Results Tree listener showing several generated JMeter Variables
ForEach Controller configuration
HTTP Request sampler configuration (i.e. where do you put the variable)
Be aware that you can mimic crawling the site more easily using HTML Link Parser the relevant configuration would be as simple as
See How to Spider a Site with JMeter - A Tutorial to learn more about simulating websites crawling.

JMeter treating "${COOKIE_[cookiename]}" as a string

I have looked at numerous examples of setting properties from cookies, and they all seem to be indicate that using a BeanShell PostProcessor, I should be able to do the following, given a cookie named 'FOO'.
props.put( "fooCookie", "${COOKIE_FOO}" );
However, when I try to write that value to the console, as you see here...
print( props.get( "fooCookie" ) );
... the value is always the string ${COOKIE_FOO} as if the dollar/curly bracket notation is not being parsed.
I feel like I must be missing something painfully obvious here, but after several hours of fighting this, I am bringing it to the experts. Any advice would be appreciated.
EDIT: Adding a bit more detail. This is the layout of my test plan
Test Plan
User Defined Variables
HTTP Cookie Manager
HTTP Request Defaults
Login Thread (setup)
[page request - login POST]
HTTP Header Manager
BeanShell PostProcessor
[more page requests]
And I do indeed have CookieManager.save.cookies=true set in the jmeter.bat file that I am launching it with.
Do you have HTTP Cookie Manager in your test plan? If not, you need to have that.
You also need to set the CookieManager.save.cookies=true in the jmeter.properties file which you can find in JMETER_HOME/bin folder.
${COOKIE_FOO} will return the actual cookie value.
Check that your ${COOKIE_FOO} variable is really set using Debug Sampler and View Results Tree listener combination. Your code is OK so my expectation is that the variable is not set.
Those who suggest using Beanshell where it is possible to handle the situation using JMeter built-in test elements should probably consider quitting IT. There are:
__setProperty() function to put something to JMeter Properties
__P() and/or __property() function to read something from them
See How to Use Variables in Different Thread Groups guide for real-life example.

How to use JMeter to create a resource with POST, extract Location, and then subsequently update it with PUT

I would like to profile a REST API using JMeter. I would like to write the test plan such that each user thread performs the following actions:
creates a new resource using HTTP POST
If HTTP 201 Created is received, then extract the new resource URL from the Location header of the HTTP response.
Subsequently update the resource using HTTP PUT
Loop in 3 and measure the response time
It's unclear to me how to use JMeter's conditional logic to break up the tests into these discrete parts. I would appreciate any insight anyone can provide on how to implement this.
You need to use If Controller to express this logic.
You can use Regular Expression Extractor to extract Response code (In field to check, check it and extract response code in a Variable)
Use the previously extracted variable in the If Controller condition

Resources