Scenario 1:
url: path1
Method : POST
Headers
Accept
Content-Type
Form fields:
Username
Password
url: path2
Method:get
Headers
Accept
Content-Type
Output of path2 is CSRF TOKEN and cookies having JESSION ID
Scenario2:
For calling any path in scenario 2 we need to pass the path2 outputs which is CXRF TOKEN and JSESSIONID
Problem:
For our test cases we need to always pass the jsession id(this jession id should be taken from the path2 only) and csrf token from path2 to all the subsequent calls. Which is not happening now
1>Csrf token is not getting passed to scenario2
2>JESSION ID created here is different from the jesession id from path2
Wants to know if there is way to pass this csrf token and jesession id headers to different scenario please?
First read the doc and then look at these particular examples: call-updates-config.feature and common.feature
Here's what I would do:
try to get everything working as a SINGLE scenario first before proceeding further. normally you never need to set cookies manually
write a re-usable feature that makes the calls to path1 and path2 and keep that in common.feature.
at the end of common.feature set the values of the CSRF token and JSESSIONID to variables
now you can write a second feature or scenario that calls common.feature. again, please read the docs, there are so many examples on how to call one feature from another and pass variables
as I said, you normally don't need to do anything to cookies, but you should be able to set the cookie like this (refer syntax for cookie): * cookie JSESSIONID = yourVariableName
similarly use the header keyword or whichever is appropriate for setting the CSRF token correctly
Related
I want to use a Servant client to first call a login endpoint to obtain a session cookie and then make a request against an endpoint that requires cookie authentication.
The API is (simlified)
import qualified Servant as SV
import qualified Servant.Auth.Server as AS
import qualified Servant.Client as SC
-- Authentication and X-CSRF cookies
type CookieHeader = ( SV.Headers '[SV.Header "Set-Cookie" AS.SetCookie
, SV.Header "Set-Cookie" AS.SetCookie]
SV.NoContent )
type LoginEndpoint = "login" :> SV.ReqBody '[SV.JSON] Login :> SV.Verb 'SV.POST 204 '[SV.JSON] CookieHeader
type ProtectedEndpoint = "protected" :> SV.Get '[SV.JSON]
-- The overall API
type Api = LoginEndpoint :<|> (AS.Auth '[AS.Cookie, AS.JWT] User :> ProtectedEndpoint)
apiProxy :: Proxy Api
apiProxy = Proxy
I define the client as follows:
loginClient :: Api.Login -> SC.ClientM Api.CookieHeader
protectedClient :: AC.Token -> SC.ClientM Text :<|> SC.ClientM SV.NoContent
loginClient :<|> protectedClient = SC.client Api.apiProxy
How does the client handle the authentication cookie? I can think of two ways. When executing a request in the ClientM monad, like
do
result <- SC.runClientM (loginClient (Login "user" "password")) clientEnv
[..]
where Login is the login request body and clientEnv of type Servant.Client.ClientEnv, the cookie could part of the result, it could be updated in the cookieJar TVar inside clientEnv, or both. I would assume the TVar to be updated, so that a subsequent request with the same clientEnv would send the received cookies along. However, my attempt to read the TVar and inspect its contents using Network.HTTP.Client.destroyCookieJar revealed an empty array. Is this intended? I couldn't find anything in the documentation.
Thus, to make an authenticated call, I would need to extract the cookie from the header in the result (how?), update the TVar, create a new clientEnv that references this TVar, and make the authenticated call using this new environment. Is this indeed the suggested procedure? I'm asking because I suppose the use case is so standard that there should be a more streamlined solution. Is there? Am I missing something?
After some experimentation, I figured out that the Servant client indeed does maintain cookies in the cookieJar that is part of the clientEnv. To be more precise, clientEnv contains the field cookieJar, which is of type Maybe (TVar CookieJar). It is the TVar the client updates according to the Set-Cookie instructions of subsequent requests. It is up to the developer to create and initialize that TVar before making the first request; otherwise, the Servant client will discard cookies between requests.
In addition, it is possible to retrieve cookies in the same way as the request body. To this end, the cookies to be retrieved must be defined as part of the API type, like in the example of my original question:
type LoginEndpoint = "login" :> SV.ReqBody '[SV.JSON] Login :> SV.Verb 'SV.POST 204 '[SV.JSON] CookieHeader
Disassembling the returned was a little tricky at first, because I needed to figure out the final type that results from Servant's type-level machinery. Ultimately, I did the following:
SV.Headers resp h <- tryRequest clientEnv (loginClient (Api.Login "user" "pwd"))
let headers = SV.getHeaders h
where tryRequest is a helper to execute runClientM and extract the Right part. The pattern match resp contains the return value (here NoContent), while h is is an HList of the different headers. It can be converted into a regular list of Network.HTTP.Types.Header using Servant's getHeaders function.
It would then be possible to change or generate new headers and submit them with a new request by adding a new header to the cookieJar TVar (see the cookie-manipulating functions in Network.HTTP.Client).
Scenario 1:
url: path1
Method : POST
Headers
Accept
Content-Type
Form fields:
Username
Password
url: path2
Method:get
Headers
Accept
Content-Type
Output of path2 is CSRF TOKEN and cookies having JESSION ID
Scenario2:
For calling any path in scenario 2 we need to pass the path2 outputs which is CXRF TOKEN and JSESSIONID
Problem:
For our test cases we need to always pass the jsession id(this jession id should be taken from the path2 only) and csrf token from path2 to all the subsequent calls. Which is not happening now
1>Csrf token is not getting passed to scenario2
2>JESSION ID created here is different from the jesession id from path2
Wants to know if there is way to pass this csrf token and jesession id headers to different scenario please?
First read the doc and then look at these particular examples: call-updates-config.feature and common.feature
Here's what I would do:
try to get everything working as a SINGLE scenario first before proceeding further. normally you never need to set cookies manually
write a re-usable feature that makes the calls to path1 and path2 and keep that in common.feature.
at the end of common.feature set the values of the CSRF token and JSESSIONID to variables
now you can write a second feature or scenario that calls common.feature. again, please read the docs, there are so many examples on how to call one feature from another and pass variables
as I said, you normally don't need to do anything to cookies, but you should be able to set the cookie like this (refer syntax for cookie): * cookie JSESSIONID = yourVariableName
similarly use the header keyword or whichever is appropriate for setting the CSRF token correctly
I have some troubles with getting Access token with grant type authorization code using Robot framework with Oauth2.
We use also a username/password authentication and after give the following parameters we get back our access token:
Grant Type, Callback URL, Auth URL, Access Token URL, Client ID, Client Secret, Scope, State.
I tried with RequestsLibrary and ExtendedRequestsLibrary as well, but no success so far.
Actually I do not know how to add parameters: callback url, auth url, access token url and state.
First try - using RequestsLibrary
Get admin token
&{HEADER_TOKEN}= Create Dictionary Content-Type=${CONTENT_TYPE}
&{DATA_TOKEN}= Create Dictionary token_name=backend_token grant_type=${GRANT_TYPE} redirect_uri =${CALLBACK_URL} auth_url=${AUTH_URL} access_token_url=${ACCESS_TOKEN_URL} client_id=${CLIENT_ID} client_secret=${CLIENT_SECRET} scope=${SCOPE} state=${STATE} username=${USERNAME} ${PASSWORD}
${BACKEND_RESPONSE}= RequestsLibrary.Post Request ${BACKEND_SESSION} /oauth/token data=${DATA_TOKEN} headers=${HEADER_TOKEN}
Log to console ${BACKEND_RESPONSE}
Should Be Equal As Strings ${BACKEND_RESPONSE.status_code} 200
Second try - using ExtendedRequestsLibrary
Get brand new admin token
${SESSION_RESPONSE}= Create Password Oauth2 Session client ${TOKEN_URL} ${CLIENT_ID} ${CLIENT_SECRET} ${USERNAME} ${PASSWORD} base_url=${BASE_URL}
&{HEADER_TOKEN}= Create Dictionary Content-Type=${CONTENT_TYPE}
&{DATA_TOKEN}= Create Dictionary token_name=client grant_type=${GRANT_TYPE} callback_url=${CALLBACK_URL} auth_url=${AUTH_URL} access_token_url=${ACCESS_TOKEN_URL} client_id=${CLIENT_ID} client_secret=${CLIENT_SECRET} scope=${SCOPE} state=${STATE}
${BACKEND_RESPONSE}= ExtendedRequestsLibrary.Post Request client /oauth/token data=${DATA_TOKEN} headers=${HEADER_TOKEN}
Log to console ${BACKEND_RESPONSE}
Should Be Equal As Strings ${BACKEND_RESPONSE.status_code} 200
Log to console ${BACKEND_RESPONSE.status_code}
If you have any idea just let me know.
thx!
using RequestsLibrary try with this approach it should work:-
Create Session baseUri https://xxxxxx.xx.xxx/xxx/xx verify=True
&{params}= Create Dictionary client_id=${client_id} client_secret=${client_secret} grant_type=${grant_type}
&{headers}= Create Dictionary Content-Type=application/json
${resp}= Post Request baseUri /oauth/token none none ${params} ${headers}
Log to Console ${resp.json()['access_token']}
Status Should Be 200 ${resp}
you are passing data=${DATA_TOKEN} as a body in your post request. You need to send it as query params. First parameter will be alias 2nd is uri 3rd is data 4th is Json and 5th is query params so in
Post Request baseUri /oauth/token none none ${params} ${headers}
you will find 3rd and 4th parameter as none. Hope this works
I'm trying test a few endpoints using Postman.
All endpoint, require a token which can be obtain by log-in.
So I did this :
Request #1
After login success, I have access to the token from the response, then I store that token in my global variable.
let token = pm.response.json().location
console.log('Token : ', token.split("?token=")[1]);
pm.globals.set("token", token)
I need to use that token as Authorization type Bearer Token for my request #2.
I can copy & paste that in the token box, but I tried to avoid doing that manually, is there a way to do it automatically so I can run these 2 requests in sequence?
At first, create an environment ( top right corner of postman - image below ) This
is not a mandatory step by I suggest you to do for better handling of variables
I have modified the script to suit your need
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("ID", jsonData.Location.split("?token=")[1]);
Now this will export the value of the token ( screenshot below )
All you have to do next is to call the variable in request #2
By this you don't have to manually copy, paste into request #2 every single time
NO there isn't any till now. It has to be done manually if you want to have complete value or else you can store it in a variable and use that variable directly for the token.
Scenario 1:
url: path1
Method : POST
Headers
Accept
Content-Type
Form fields:
Username
Password
url: path2
Method:get
Headers
Accept
Content-Type
Output of path2 is CSRF TOKEN and cookies having JESSION ID
Scenario2:
For calling any path in scenario 2 we need to pass the path2 outputs which is CXRF TOKEN and JSESSIONID
Problem:
For our test cases we need to always pass the jsession id(this jession id should be taken from the path2 only) and csrf token from path2 to all the subsequent calls. Which is not happening now
1>Csrf token is not getting passed to scenario2
2>JESSION ID created here is different from the jesession id from path2
Wants to know if there is way to pass this csrf token and jesession id headers to different scenario please?
First read the doc and then look at these particular examples: call-updates-config.feature and common.feature
Here's what I would do:
try to get everything working as a SINGLE scenario first before proceeding further. normally you never need to set cookies manually
write a re-usable feature that makes the calls to path1 and path2 and keep that in common.feature.
at the end of common.feature set the values of the CSRF token and JSESSIONID to variables
now you can write a second feature or scenario that calls common.feature. again, please read the docs, there are so many examples on how to call one feature from another and pass variables
as I said, you normally don't need to do anything to cookies, but you should be able to set the cookie like this (refer syntax for cookie): * cookie JSESSIONID = yourVariableName
similarly use the header keyword or whichever is appropriate for setting the CSRF token correctly