Advice for implementing custom authentication scheme [duplicate] - karate

First of all, thanks for build karate it's a very useful for test API's and UI's. We are using it to test a lot of our endpoints but we would like to know if there is a way or which is the best approach to handle requests with signature as part of the request in the header.
In our case we have two headers:
ApiKey: this value is always the same
Signature: this value depends on the request body content
Is there any way to inject the signature value just before the request is executed based on the request body content?
Here you can see two samples of the requests
Sample 1:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'YYY'
And request { }
When method POST
Then status 200
Sample 2:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'ZZZ'
And request { name: 'John' }
When method POST
Then status 200
Thanks

Karate has a "hook" for generating headers, but as of now it is not "aware" of the currently built request body + headers: https://github.com/intuit/karate#configure-headers
We got a similar request here, and are thinking of adding this capability: How to retrieve raw request contents before making a REST call in Karate DSL?
Maybe the OAuth examples will give you the way forward for your case for now: https://stackoverflow.com/a/55055111/143475
Feel free to raise an enhancement request, and we can get this in to the next version (with your help to test it). I'm thinking - what if you are able to call karate.get('request') from within the header JS function.
But for now all you need to do is do something like this:
* def body = { some: 'json' }
* karate.set('requestBody', body)
* url someUrl
* request body
* method post
And in the header.js function
function fn() {
var body = karate.get('requestBody');
var sign = Utils.sign(body);
return { Signature: sign };
}
EDIT: this will be implemented in Karate 1.0 onwards: https://github.com/intuit/karate/issues/1385

Related

Can you define headers in Karate tests? [duplicate]

So I've managed to write a bunch of tests and in every feature file I set the same request headers.
For example:
Given url appUrl
And path '/path'
* header Accept = 'application/json'
I'd like to know if there's a way to set a header once so that it is set before each scenario is run. I've read the documentation and tried the callSingle method as follows in karate-config.js:
karate.callSingle('classpath:api/Utilities/Feature/header.feature');
header.feature looks like:
Feature: common routing that sets the headers for all features
Background:
* configure headers = { Accept : 'application/json' }
And example feature where I expect the headers to be preset:
Feature: Header Preset
Scenario: I expect the header to be set
Given url appUrl
And path '/path'
When method get
Then status 200
* print response
#I expect the response to be returned in JSON format
However I'm unable to get this working. I don't think I've understood how the callSingle method works. Some pointers would be helpful. Thanks.
Ignore callSingle for now and focus on configure headers.
I think you are missing one step - which is to ensure that configure headers has been "applied" before each Scenario. If you are 100% sure that this applies "globally", just do this in karate-config.js:
karate.configure('headers', { Accept: 'application/json' });
Else you use the Background (in each feature):
* configure headers = { Accept: 'application/json' }
Typically you have more steps that are common, so you have them in a "common" feature file and call that for every test. Refer: https://github.com/intuit/karate#shared-scope

callSingle() usage in karate-config.js [duplicate]

I have a .feature file that will receive argument from another feature file as __arg to generate token for oAuth
Given url urlRefreshToken
Given def json = __arg
And header Content-Type = 'application/json; charset=utf-8'
And request json
* header Authorization = 'Bearer' + __arg.refresh_token
When method POST
Then status 200
* def bearer = 'Bearer ' + response.access_token
I am trying to centralise the token generation for only one time on karate-config.js. However I cannot seem to be able to use karate.callSingle() with passed parameters.
I use the feature file to generate token on other feature files as:
* def getToken = call read('classpath:features/Utils/GetToken.feature') refreshTokenRaymond
* header Authorization = getToken.bearer
I am trying to invoke the feature file for generating token on karate-config.js to no avail. I tried to pass in the additional parameter like this on karate-config.js:
var config = {
baseUrl: 'url',
urlRefreshToken: 'url',
refreshToken: '{refreshToken: refreshToken}'
};
var token = karate.callSingle('classpath:features/Utils/GetToken.feature', [config, config.refreshToken])
I wonder if it is possible to pass multiple parameter to karate.callSingle() called from karate-config.js?
Any help will be greatly appreciated. Thanks!
call and karate.callSingle() take only one argument, but you can easily create a new JSON out of other JSONs. Actually since you seem to be passing config as the argument - you can easily access config.refreshToken as __arg.refreshToken.
Your code is very confusing - but hope that this hint is what gets you on your way:
Given def json = __arg.refreshToken
If you need to create a JSON out of other data - I think you already know how to do that:
var temp = { config: config, refreshToken: refreshToken };
var token = karate.callSingle('classpath:features/Utils/GetToken.feature', temp);

How to handle requests with signatures on karate tests?

First of all, thanks for build karate it's a very useful for test API's and UI's. We are using it to test a lot of our endpoints but we would like to know if there is a way or which is the best approach to handle requests with signature as part of the request in the header.
In our case we have two headers:
ApiKey: this value is always the same
Signature: this value depends on the request body content
Is there any way to inject the signature value just before the request is executed based on the request body content?
Here you can see two samples of the requests
Sample 1:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'YYY'
And request { }
When method POST
Then status 200
Sample 2:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'ZZZ'
And request { name: 'John' }
When method POST
Then status 200
Thanks
Karate has a "hook" for generating headers, but as of now it is not "aware" of the currently built request body + headers: https://github.com/intuit/karate#configure-headers
We got a similar request here, and are thinking of adding this capability: How to retrieve raw request contents before making a REST call in Karate DSL?
Maybe the OAuth examples will give you the way forward for your case for now: https://stackoverflow.com/a/55055111/143475
Feel free to raise an enhancement request, and we can get this in to the next version (with your help to test it). I'm thinking - what if you are able to call karate.get('request') from within the header JS function.
But for now all you need to do is do something like this:
* def body = { some: 'json' }
* karate.set('requestBody', body)
* url someUrl
* request body
* method post
And in the header.js function
function fn() {
var body = karate.get('requestBody');
var sign = Utils.sign(body);
return { Signature: sign };
}
EDIT: this will be implemented in Karate 1.0 onwards: https://github.com/intuit/karate/issues/1385

How to pass multiple parameters to callSingle karate on karate-config.js

I have a .feature file that will receive argument from another feature file as __arg to generate token for oAuth
Given url urlRefreshToken
Given def json = __arg
And header Content-Type = 'application/json; charset=utf-8'
And request json
* header Authorization = 'Bearer' + __arg.refresh_token
When method POST
Then status 200
* def bearer = 'Bearer ' + response.access_token
I am trying to centralise the token generation for only one time on karate-config.js. However I cannot seem to be able to use karate.callSingle() with passed parameters.
I use the feature file to generate token on other feature files as:
* def getToken = call read('classpath:features/Utils/GetToken.feature') refreshTokenRaymond
* header Authorization = getToken.bearer
I am trying to invoke the feature file for generating token on karate-config.js to no avail. I tried to pass in the additional parameter like this on karate-config.js:
var config = {
baseUrl: 'url',
urlRefreshToken: 'url',
refreshToken: '{refreshToken: refreshToken}'
};
var token = karate.callSingle('classpath:features/Utils/GetToken.feature', [config, config.refreshToken])
I wonder if it is possible to pass multiple parameter to karate.callSingle() called from karate-config.js?
Any help will be greatly appreciated. Thanks!
call and karate.callSingle() take only one argument, but you can easily create a new JSON out of other JSONs. Actually since you seem to be passing config as the argument - you can easily access config.refreshToken as __arg.refreshToken.
Your code is very confusing - but hope that this hint is what gets you on your way:
Given def json = __arg.refreshToken
If you need to create a JSON out of other data - I think you already know how to do that:
var temp = { config: config, refreshToken: refreshToken };
var token = karate.callSingle('classpath:features/Utils/GetToken.feature', temp);

Karate - Setting global request headers

So I've managed to write a bunch of tests and in every feature file I set the same request headers.
For example:
Given url appUrl
And path '/path'
* header Accept = 'application/json'
I'd like to know if there's a way to set a header once so that it is set before each scenario is run. I've read the documentation and tried the callSingle method as follows in karate-config.js:
karate.callSingle('classpath:api/Utilities/Feature/header.feature');
header.feature looks like:
Feature: common routing that sets the headers for all features
Background:
* configure headers = { Accept : 'application/json' }
And example feature where I expect the headers to be preset:
Feature: Header Preset
Scenario: I expect the header to be set
Given url appUrl
And path '/path'
When method get
Then status 200
* print response
#I expect the response to be returned in JSON format
However I'm unable to get this working. I don't think I've understood how the callSingle method works. Some pointers would be helpful. Thanks.
Ignore callSingle for now and focus on configure headers.
I think you are missing one step - which is to ensure that configure headers has been "applied" before each Scenario. If you are 100% sure that this applies "globally", just do this in karate-config.js:
karate.configure('headers', { Accept: 'application/json' });
Else you use the Background (in each feature):
* configure headers = { Accept: 'application/json' }
Typically you have more steps that are common, so you have them in a "common" feature file and call that for every test. Refer: https://github.com/intuit/karate#shared-scope