How to test web service with authentication using JMeter - web-services

I'm using Apache JMeter 2.11 to test a web service with authentication. For the sample request I'm using View Results Tree as a listener and a SOAP/XML-RPC Request with the following syntax to my parameters:
URL: http://www.domain.com:####/dir/dir/webservice.asmx
SOAPAction: http://www.domain.com/action
What I have tried
1) Adding an HTTP Header Manager using
Name: Authorization:
Value: Basic [Base64 code encoded in ASCII, UTF-8, with or without domain in the user name] as explained here
With result: Response headers: HTTP/1.1 401 Unauthorized
2) Adding an HTTP Authorization Manager using
Base URL: http://www.domain.com:####
Username: [USERNAME]
Password: [PASSWORD]
Domain: [DOMAIN]
Realm: [NULL]
Mechanism: [BASIC_DIGEST/KERBEROS] as explained here
With result: Response headers: HTTP/1.1 401 Unauthorized
I also tried enabling Keep Alive in the request as suggested here
What am I doing wrong?

First you need to know the auth type, is it basic ? Digest ? Kerberos or other ?
Second, don't use SOAP/XML-RPC Request, use Http Request,
See Templates > Webservice in jmeter menu, it creates a sample test plan for Soap testing.
Add then your authentication with the correct Auth Manager using HttpClient 4 as sampler implementation and check.

Related

Getting the OAuth Token from FedEx to use for Track API

I'm trying to get the OAuth Token to get auth access to some of the FedEx APIs ( like Track API for tracking shipments ), but I get a
401 (NOT.AUTHORIZED.ERROR -> "The given client credentials were not valid. Please modify your request and try again") error.
(At the moment, I'm using Postman to try and test the APIs.)
Here is the url I'm using, found provided by FedEx:
https://apis-sandbox.fedex.com/oauth/token
I've followed ( to my understanding ) how the body and headers should be set:
Headers: Content-Type: application/x-www-form-urlencoded
Body: x-www-form-urlencoded (Postman option):
grant_type: client_crendentials
client_id: ***PROJECT_API_KEY
client_secret: ***PROJECT_SECRET KEY
After sending, I only get the error message above. I checked / doubled-checked my API keys, but I can't seem to get it to go through.
Any ideas?
postman settings:
POST - URL https://apis-sandbox.fedex.com/oauth/token
Headers - Content-Type: application/x-www-form-urlencoded
Body - x-www-form-urlencoded:
grant_type: client_credentials
client_id: *******
client_secret: *******
(information gotten from https://developer.fedex.com/api/en-us/catalog/authorization/v1/docs.html)
The sandbox API credentials are not immediately usable when creating a new account. It took >1 hour for me to get a registration complete email from FedEx after which the sandbox credentials became valid.

Tavern authorization

I'm running a flask api and I want to write some tavern tests for it. I use a basic base64 encode for the username and password that I send in the header when making requests which works fine on the API but I can't seem to get it to work for tavern.
stages:
- name: login
request:
url: url
method: GET
headers:
Authorization: Basic aGVsbG9zdGFja292ZXJmbG93
accept: application/json
response:
My api keeps refusing the authorization and without the Basic tag it doesn't recognize the format. Here is the flask authorization logic:
try:
api_key = base64.b64decode(api_key)
username, password = api_key.split(':')
if password == users[username]:
user = User(username)
return user
except TypeError:
current_app.login_manager.unauthorized()
All help/suggestions are appreciated
There's documentation on this feature here: https://taverntesting.github.io/documentation#http-basic-auth

Vue.js frontend interacting with Flask backend CORS issues due to not allowed preflight headers

I am stuck with the following error message in the Chrome browser:
Failed to load http://localhost:5000/my_endpoint: Request header field
Access-Control-Allow-Origin is not allowed by
Access-Control-Allow-Headers in preflight response.
The browser is loading a webpage from a Vue.js frontend app with webpack etc. and vue-resource to perform HTTP requests to the REST backend.
The URL http://localhost:5000/my_endpoint is a HTTP GET/POST endpoint served by a python Flask application.
On the frontend Javascript I have these CORS settings:
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.http.options.crossOrigin = true
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*'
On the backend python code in the Flask app I have the following CORS configuration details:
#app.after_request
def add_header(response):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'Access-Control-Allow-Headers, Origin, X-Requested-With, Content-Type, Accept, Authorization'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS, HEAD'
response.headers['Access-Control-Expose-Headers'] = '*'
return response
When performing this HTTP POST request in the Javascript frontend:
this.$http.post("http://localhost:5000/my_endpoint", { my_custom_key: "my custom value"})//, {emulateJSON: true})
.then((response) => {
// do stuff
})
where { my_custom_key: "my custom value"} is the JSON body of the HTTP POST request, then in the Flask backend for some reason I see an HTTP OPTIONS request coming, cf. the Flask log:
127.0.0.1 - - [26/Jun/2018 21:45:53] "OPTIONS /ad HTTP/1.1" 200 -
There must be some sort of back/forth ceremony to honor before being able to retrieve the JSON data from the backend, but I am lost in these details.
On the internet I've seen all sorts of explanations, and I've been playing a bit with the vue-resource configuration details like:
adding/removing {emulateJSON: true} to the HTTP POST request
adding/removing Vue.http.options.xhr = { withCredentials : true }; to the configuration of Vue.js
but I am not able retrieve the JSON data coming from the backend.
Searching for "CORS" on the Vue.js documentation or on https://github.com/pagekit/vue-resource does not give any information on how to fix these issues with Cross-origin resource sharing (CORS).
How do I get a Vue.js frontend working with a Flask backend on these CORS issues?
The solution was to remove from the frontend: Vue.http.headers.common['Access-Control-Allow-Origin'] = '*' (which actually does not make sense as it's an HTTP header that usually goes into the response from the backend).
Also to clean up a bit more the backend I found out that response.headers['Access-Control-Expose-Headers'] = '*' was not needed. Probably the other HTTP headers could be more slim, but for now I keep them as they are.

why is XMLHttpRequest.withCredentials necessary even for same site Ajax requests

I am trying to implement an authentication service deployed in a different HTTP server from the one serving my login page.
The following diagram depicts my setup:
On step #1 my browser makes an HTTP GET request to fetch the login page. This is provided as the HTTP response in #2. My browser renders the login page and when I click the login button I send an HTTP POST to a different server (on the same localhost). This is done in #3. The authentication server checks the login details and sends a response that sets the cookie in #4.
The ajax POST request in #3 is made using jQuery:
$.post('http://127.0.0.1:8080/auth-server/some/path/',
{username: 'foo', password: 'foo'},
someCallback);
The authentication service's response (assuming authentication was successful) has the following header:
HTTP/1.1 200
Set-Cookie: session-id=v3876gc9jf22krlun57j6ellaq;Version=1
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: origin, content-type, accept, authorization
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 21 Nov 2016 16:17:08 GMT
So the cookie (session-id) is present in the HTTP response in step #4.
Now if the user tries to login again I would like the authentication service to detect that. To test that scenario I press the login button again in order to repeat the post in #3. I would have expected the second request to contain the cookie. However the second time I press the login button, the request header in the post sent out in #3 does not contain the cookie.
What I have discovered is that for the post in #3 to contain the cookie, I have to do it like this:
$.ajax({
type: 'post',
url: 'http://127.0.0.1:8080/auth-server/some/path',
crossDomain: true,
dataType: 'text',
xhrFields: {
withCredentials: true
},
data: {
username : 'foo',
password : 'foo',
},
success: someCallback
});
Why would that be necessary? MDN states that this is only required for cross-site requests. This SO post also uses xhrFields but only in relation to a cross-domain scenario. I understand that my case is not cross-domain as both the page that serves the script is on localhost, and the page to where the ajax request is sent is on the same host. I also understand that cookie domains are not port specific. Moreover, since my cookie did not explicitly specify a domain, then the effective domain is that of the request meaning 127.0.0.1 which is identical the second time I send the POST request (#3). Finally, the HTTP reponse on #4 already includes Access-Control-Allow-Origin: * which means that the resource can be accessed by any domain in a cross-site manner.
So why did I have to use the xhrFields: {withCredentials: true} to make this work?
What I understand is that setting Access-Control-Allow-Origin: * is simply enabling cross-site requests but that in order for cookies to be sent then the xhrFields: {withCredentials: true} should be used regardless (as explained in MDN section on requests with credentials). Moreover, I understand that the request is indeed cross-site since the port number is important when deciding whether a request is cross-site or not. Whether the domain of a cookie includes ports is irrelevant. Is this understanding correct?
update
I think this is explained very clearly in this answer, so maybe this question should be deleted.
All parts of the origin must match the host(ajax target) for it to be considered same-origin. The 3 part of the origin https://sales.company.com:9443 for example includes:
protocol/scheme (https - won't match http)
hostname (sales.company.com - won't match subdomain.sales.company.com)
port (9443 - won't match 443)
see https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

Setting Custom cookie and user-agent values in swagger

We are using swagger for api documentation.
I'm facing an issue on tryit out. Basically the rest endpoints which we indent to call from swagger requires
Cookie(ex: cookie : token=xxxxx;) and User-Agent(User-Agent:custom values;) parameters.
But when I try to set this parameter
Cookie is not send as part of the request.
User-Agent is being overridden by browser values. I tried on firefox and chrome both.
I did tried search online but didn't find suitable answer solve my issue, There were suggestion to set
useJQuery: true and withCredentials: true to set the cookies, but non worked fine.
Any suggestion on this?
As presented on their website:
In OpenAPI 3.0 terms, cookie authentication is an API key that is sent
in: cookie. For example, authentication via a cookie named JSESSIONID
is defined as follows:
openapi: 3.0.0
...
# 1) Define the cookie name
components:
securitySchemes:
cookieAuth: # arbitrary name for the security scheme; will be used in the "security" key later
type: apiKey
in: cookie
name: JSESSIONID # cookie name
And then at the endpoint level:
paths:
/users:
get:
security:
- cookieAuth: [] # note the arbitrary name defined earlier
description: Returns a list of users.
responses:
'200':
description: OK
For swagger: "2.0" you can define cookie authentication like this:
securityDefinitions:
cookieAuth:
type: apiKey
name:
Cookie # this is actually the Cookie header which will be sent by curl -H
in: cookie
Referencing it at the endpoint is done the same way as for OpenAPI 3.