How to post x-www-urlencode request by rest assured - postman

I have a post request where i need to send x-www-form-urlencoded keyValue pair parameters and content-type should be x-www-form-urlencoded.
Before coding ,i've tried in postman successfully,just adding Header"Content-Type=application/x-www-form-urlencoded" with x-www-form-urlencoded body .
Here is my code:`
RestAssured.baseURI="****"
RequestSpecification request = RestAssured.given().config(RestAssured.config()
.encoderConfig(EncoderConfig.encoderConfig()
.encodeContentTypeAs("x-www-form-urlencoded",
ContentType.URLENC)))
.contentType(ContentType.URLENC.withCharset("UTF-8"))
.formParam("grant_type", *)
.formParam("code", *)
.formParam("client_id",*)
.when().log().all()
.then().log().all().request()
request.post("/oauth2/token")`
I guess rest assured posted as formParam not "x-www-form-urlencoded"?
This is rest assured log: `
Request method: POST
Request URI: ***
Proxy: <none>
Request params: <none>
Query params: <none>
Form params: grant_type=***
code=***
client_id=***
Path params: <none>
Headers: Accept=image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap
Content-Type=application/x-www-form-urlencoded; charset=UTF-8
Cookies: <none>
Multiparts: <none>
Body: <none>
HTTP/1.1 405 Method Not Allowed
Content-Length: 61
Date: Tue, 30 Jan 2018 06:59:20 GMT
X-Correlationid: 5d155b6f-0d85-4775-5f50-82c397e5b44b
X-Smp-Log-Correlation-Id: 5d155b6f-0d85-4775-5f50-82c397e5b44b
X-Vcap-Request-Id: 5d155b6f-0d85-4775-5f50-82c397e5b44b
Only support Content-Type:application/x-www-form-urlencoded
`
This problem drives me crazy for a couple f days .
Please do let me know is there any other way to send x-www-form-urlencoded parameters or some updation required in code.
Thanks a lot!

Response response = RestAssured
.given()
.contentType("application/x-www-form-urlencoded; charset=utf-8")
.formParam("grant_type", "password")
.formParam("username", user_email)
.formParam("password", user_password)
.formParam("audience", audience)
.formParam("scope", "openid email")
.formParam("client_id", REGULAR_APP_CLIENT_ID)
.formParam("client_secret", REGULAR_APP_SECRET_ID)
.when()
.post(AUTH0_URL);

If you need send request with params in body:
String body = String.format("grant_type=%s&code=%s&clientid=%s", grantType, code, clientId);
Response response = given().with().
header("Content-Type", "application/x-www-form-urlencoded").
body(body).
post("/oauth2/token");
Case for params in URL:
Response response = given().with().
header("Content-Type", "application/x-www-form-urlencoded").
post("/oauth2/token?grant_type={type}&code={code}&clientid={id}");
Case for params in header (also might use Header object io.restassured.http.Header):
Response response = given().with().
header("Content-Type", "application/x-www-form-urlencoded").
header("grant_type", type).
header("code", code).
header("clientid", id).
post("/oauth2/token");
BTW use static give() for don't duplicate Config
public static RequestSpecification given() {
RestAssured.config = RestAssured.config().
...;
return given().baseUrl(BASE_URL).contentType(ContentType.URLENC);
}

This Method is working for me
public String getAuthForKeyCloak() {
Response response = RestAssured.given().with().auth().preemptive()
.basic(props.get("keycloak_username"), props.get("keycloak_password"))
.header("Content-Type", "application/x-www-form-urlencoded")
.formParam("grant_type", props.get("keycloak_granttype"))
.formParam("client_id", props.get("keycloak_clientid"))
.formParam("username", props.get("keycloak_username"))
.formParam("password", props.get("keycloak_password")).when()
.post(ApplnURIForKeyCloak + props.get("keycloakAuthURL"));
System.out.println(response.getBody().asString());
String responseBody = response.getBody().asString();
String token = new org.json.JSONObject(responseBody).getString("access_token");
System.out.println(token);
return token;
}

Use RA EncoderConfig to encode the content type for content-type x-www-form-urlencoded. Also, post the payload as form parameters
RequestSpecBuilder.setConfig(RestAssured.config().sslConfig(SSLConfig.sslConfig().relaxedHTTPSValidation())
.encoderConfig(EncoderConfig.encoderConfig()
.encodeContentTypeAs("x-www-form-urlencoded",
ContentType.URLENC)))
.setContentType("application/x-www-form-urlencoded; charset=UTF-8");

I had the same issue and I finally found the solution:
Understanding the issue:
Rest Assured automatically concatenates a charset after the content type, even if you do not specify one.
i.e if you set the Content-Type to be application/x-www-form-urlencoded it will automatically set a default charset to it and your log will display:
Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1 or some other charset.
My problem was that I needed the content type to be without any charset, otherwise it was not accepted and returned status code 400.
The solution is to make sure you send the content type WITHOUT ANY charset.
How to use:
Before you set the content type, add this line:
RequestSpecification rs= RestAssured.given();
rs.config(RestAssured.config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false)));
this part :
appendDefaultContentCharsetToContentTypeIfUndefined(false)))
will make sure that no charset will be appended to your content type.
Then set the header:
rs.header("Content-Type", "application/x-www-form-urlencoded");

Related

Google Photos REST API "pageSize" and "pageToken" parameters causing 400 Bad Request

I'm trying to get all media items in my Google Photos library and referred following documentation link.
https://developers.google.com/photos/library/guides/list
Documentation says client can request pages using pageSize and provided following example.
GET https://photoslibrary.googleapis.com/v1/mediaItems
Content-type: application/json
Authorization: Bearer OAUTH2_TOKEN
{
"pageSize":"100",
}
i think the comma after 100 is a documentation error and i removed it from request, but whenever i add pageSize (or pageToken) parameter, server always return with 400 Bad Request <p>Your client has issued a malformed or illegal request.<ins>That’s all we know.</ins>
Here are some example REST API calls i tried
GET /v1/mediaItems HTTP/1.1
Host: photoslibrary.googleapis.com
Content-Type: application/json
Authorization: Bearer xxx
{
"pageSize":10
}
GET /v1/mediaItems HTTP/1.1
Host: photoslibrary.googleapis.com
Content-Type: application/json
Authorization: Bearer xxx
{
"pageSize":"10"
}
GET /v1/mediaItems HTTP/1.1
Host: photoslibrary.googleapis.com
Content-Type: application/json
Authorization: Bearer xxx
{
"pageToken":"blha blha"
}
Please note that whenever i removed the json from request body, it start returning 200 OK with predefined pageSize. but i would like to control the pageSize and request next pages using pageToken.
Thanks for any guidance on this matter.
I just started looking at this too. Those parameters shouldn't be passed in the body. They are query parameters. So something like this:
https://photoslibrary.googleapis.com/v1/mediaItems?pageSize=100
That worked for me at least. Check out further documentation at https://developers.google.com/photos/library/reference/rest/v1/mediaItems/list to review information about the query parameters.

Call S3 pre-signed URL with postman

I am attempting to use a pre-signed URL to upload as described in the docs (https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html) I can retrieve the pre-signed URL but when I attempt to do a PUT in Postman, I receive the following error:
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
Obviously, the way my put call is structured doesn't match with the way AWS is calculating the signature. I can't find a lot of information on what this put call requires.
I've attempted to modify the header for Content-Type to multipart/form-data and application/octet-stream. I've also tried to untick the headers section in postman and rely on the body type for both form-data and binary settings where I select the file. The form-data setting results in the following added to the call:
Content-Disposition: form-data; name="thefiletosend.txt"; filename="thefiletosend.txt
In addition, I noticed that postman is including what it calls "temporary headers" as follows:
Host: s3.amazonaws.com
Content-Type: text/plain
User-Agent: PostmanRuntime/7.13.0
Accept: /
Cache-Control: no-cache
Postman-Token: e11d1ef0-8156-4ca7-9317-9f4d22daf6c5,2135bc0e-1285-4438-bb8e-b21d31dc36db
Host: s3.amazonaws.com
accept-encoding: gzip, deflate
content-length: 14
Connection: keep-alive
cache-control: no-cache
The Content-Type header may be one of the issues, but I'm not certain how to exclude these "temporary headers" in postman.
I am generating the pre-signed URL in a lambda as follows:
public string FunctionHandler(Input input, ILambdaContext context)
{
_logger = context.Logger;
_key = input.key;
_bucketname = input.bucketname;
string signedURL = _s3Client.GetPreSignedURL(new GetPreSignedUrlRequest()
{
Verb = HttpVerb.PUT ,
Protocol = Protocol.HTTPS,
BucketName = _bucketname,
Key = _key,
Expires = DateTime.Now.AddMinutes(5)
});
returnObj returnVal = new returnObj() { url = signedURL };
return JsonConvert.SerializeObject(returnVal);
}
Your pre-signed url should be like https://bucket-name.s3.region.amazonaws.com/folder/filename.jpg?AWSAccessKeyId=XXX&Content-Type=image%2Fjpeg&Expires=XXX&Signature=XXX
You can upload to S3 with postman by
Set above url as endpoint
Select PUT request,
Body -> binary -> Select file
I was able to get this working in Postman using a POST request. Here are the details of what worked for me. When I call my lambda to get a presigned URL here is the json that comes back (after I masked sensitive and app-specific information):
{
"attachmentName": "MySecondAttachment.docx",
"url": "https://my-s3-bucket.s3.amazonaws.com/",
"fields": {
"acl": "public-read",
"Content-Type": "multipart/form-data",
"key": "attachment-upload/R271645/65397746_MySecondAttachment.docx",
"x-amz-algorithm": "AWS4-HMAC-SHA256",
"x-amz-credential": "WWWWWWWW/20200318/us-east-1/s3/aws4_request",
"x-amz-date": "20200318T133309Z",
"x-amz-security-token": "XXXXXXXX",
"policy": "YYYYYYYY",
"x-amz-signature": "ZZZZZZZZ"
}
}
In Postman, create a POST request, and use “form-data” to enter in all the fields you got back, with exactly the same field names you got back in the signedURL shown above. Do not set the content type, however. Then add one more key named “file”:
To the right of the word file if you click the drop-down you can browse to your file and attach it:
In case it helps, I’m using a lambda written in python to generate a presigned URL so a user can upload an attachment. The code looks like this:
signedURL = self.s3.generate_presigned_post(
Bucket= "my-s3-bucket",
Key=putkey,
Fields = {"acl": "public-read", "Content-Type": "multipart/form-data"},
ExpiresIn = 15,
Conditions = [
{"acl": "public-read"},
["content-length-range", 1, 5120000]
]
)
Hope this helps.
Your pre-signed url should be like https://bucket-name.s3.region.amazonaws.com/folder/filename.jpg?AWSAccessKeyId=XXX&Content-Type=image%2Fjpeg&Expires=XXX&Signature=XXX
You can upload to S3 with postman by
Set above url as endpoint
Select PUT request,
Body -> binary -> Select file
I was facing the same problem and below is how it worked for me.
Note, I am making signed URL by using AWS S3 Java SDK as my backend is in Java. I gave content type as "application/octet-stream" while creating this signed Url so that any type of content can be uploaded. Below is my java code generating signed url.
public String createS3SignedURLUpload(String bucketName, String objectKey) {
try {
PutObjectRequest objectRequest = PutObjectRequest.builder().bucket(bucketName).key(objectKey)
.contentType("**application/octet-stream**").build();
S3Presigner presigner = S3Presigner.builder().region(s3bucketRegions.get(bucketName))
.credentialsProvider(StaticCredentialsProvider.create(awsBasicCredentials)).build();
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(presignedURLTimeoutInMins)).putObjectRequest(objectRequest)
.build();
PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest);
return presignedRequest.url().toString();
} catch (Exception e) {
throw new CustomRuntimeException(e.getMessage());
}
}
## Now to upload file using Postman
Set the generated url as endpoint
Select PUT request,
Body -> binary -> Select file
Set header Content-Type as application/octet-stream (This point I was missing earlier)
It's actually depends in how you generated URL,
If you generated using JAVA,
Set the generated url as endpoint
Select PUT request,
Body -> binary -> Select file
If you generated using PYTHON,
Create a POST request, and use form-data to enter in all the fields you got back, with exactly the same field names you got back in the signedURL shown above.
Do not set the content type, however. Then add one more key named “file”:
Refer the accepted answer picture

Make post request with separate hostname and url in python

I am trying to make a request.post(someURL) where the host name is not the same as the url.
The host I am trying to reach is in a private cluster but is accessible from a public URL. The problem is when I make a normal post request I get a 404 response because the host is expecting its internal name (hostName).
Is there a way to do something like response = request.post(someURL, hostname = hostName, data = data) so the request will go to someURL but give hostName as the host name instead of someURL.
"hosts" are almost always passed in the header. try something like this
#add/remove whatever other headers you need
headers={
'Accept':'application/json, text/plain, */*',
'Accept-Encoding':'gzip, deflate, br',
'Accept-Language':'en-US,en;q=0.9',
'Host':'hostName'
}
response = request.post(someURL, headers=headers, data = data)
Note you may want to check the request as some sites require a Host, Origin, Referer, etc.

Django oauth2 token request fails on Swift Alamofire

I am building both an iOS client and a django backend service. The connection made between the systems is OAUTH2, implemented by the django-oauth2-toolkit.
Although the following command done in curl works (returns an access token):
curl -X POST -d "grant_type=password&username=<user>&password=<password>" http://<clientID>:<clientSecret>#localhost:8000/o/token/
The following Swift snippet, that uses Alamofire, receives "invalid_client", as a response.
let request = "http://\(Authentication.clientId):\(Authentication.clientSecret)#localhost:8000/o/token/"
var URLRequest = NSMutableURLRequest(URL: NSURL(string: request)!)
URLRequest.HTTPMethod = "POST"
let parameters = ["grant_type": "password", "username": in_username.text!, "password": in_password.text!]
let encoding = Alamofire.ParameterEncoding.URL
(URLRequest, _) = encoding.encode(URLRequest, parameters: parameters)
URLRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
Alamofire.request(URLRequest)
.responseJSON { response in
let data = response
print(data)
}
I then traced the InvalidClientError in the django-oauth2-toolkit source, and found that the exception was raised in the highlighted snippet of the following file:
oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
if self.request_validator.client_authentication_required(request):
log.debug('Authenticating client, %r.', request)
print(request) # I included this print message to inspect the request variable in console.
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request) # RAISED!
I included the print(request) line to inspect the differences between the request made by curl and by Alamofire. The major difference was that the curl version included an authorization key:
'Authorization': 'Basic Z3ZFSjVXejloUGgybUJmdDNRaGhXZnlhNHpETG5KY3V6djJldWMwcjpSbVNPMkpwRFQ4bHp1UVFDYXN3T3dvVFkzRTBia01YWWxHVHNMcG5JUGZCUHFjbHJSZE5EOXQzd3RCS2xwR09MNWs1bEE4S2hmRUkydEhvWmx3ZVRKZkFXUDM4OERZa1NTZ0RvS0p3WjUyejRSQ29WRkZBS01RS1lydEpsTWNXag=='
and the Alamofire request didn't.
I highly suspect this is the culprit, but I really don't know else to do though from here on. I would really appreciate any wisdom.
Found the answer!
Was reading through a RFC document on the HTTP protocol, when this section caught my eye.
https://www.rfc-editor.org/rfc/rfc1945#section-11.1
Specifically,
To receive authorization, the client sends the user-ID and password,
separated by a single colon (":") character, within a base64 [5]
encoded string in the credentials.
It seems that Alamofire does not encode in 64 bits the clientId and clientSecret, as expected. Obviously, curl does this automatically. So I did the following:
First encode:
static let clientData: NSData = "\(clientId):\(clientSecret)".dataUsingEncoding(NSUTF8StringEncoding)!
static let client64String = clientData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.init(rawValue: 0))
Then set the request header using the resulting value:
let request = "http://localhost:8000/o/token/"
var URLRequest = NSMutableURLRequest(URL: NSURL(string: request)!)
URLRequest.HTTPMethod = "POST"
let parameters = ["grant_type": "password",
"username": in_username.text!,
"password": in_password.text!,
]
let encoding = Alamofire.ParameterEncoding.URL
(URLRequest, _) = encoding.encode(URLRequest, parameters: parameters)
// SOLUTION!
URLRequest.setValue("Basic \(Authentication.client64String)", forHTTPHeaderField: "Authorization")
Alamofire.request(URLRequest)
.responseJSON { response in
let data = response
print(data)
}
I then received the expected token as a response.

http POST: The post body is empty. All data is send in section: "Post Params: key:". Is this OK?

I'm new to internet programming and got a problem when sending a post request to a server (I received an unspecific error message). The server I want to connect is Microsoft HealthVault PreProductionEnvironment. The Specification say the this:
"HealthVault Service communications occur via schematized XML in the body of an HTTP request over a TLS Connection [RFC2818]. The HTTP requests MUST be submitted using the POST HTTP verb."
I tried to check the post request by sending it to "http://posttestserver.com/post.php?dir=ms_hv" (result displayed on "http://posttestserver.com/data/2011/12/05/ms_hv/"). This is the data I got:
Time: Mon, 05 Dec 11 05:26:53 -0800
Source ip: xxx.xxx.xxx.xxx
Headers (Some may be inserted by server)
UNIQUE_ID = TtzGna3sqvkAABZHetMAAAAH
CONTENT_LENGTH = 1157
HTTP_CONNECTION = close
HTTP_ACCEPT_ENCODING = gzip
HTTP_ACCEPT_LANGUAGE = en-US,*
HTTP_USER_AGENT = Mozilla/5.0
HTTP_HOST = posttestserver.com
CONTENT_TYPE = application/x-www-form-urlencoded
REMOTE_ADDR = 188.98.76.99
REMOTE_PORT = 21675
GATEWAY_INTERFACE = CGI/1.1
REQUEST_METHOD = POST
QUERY_STRING = dir=ms_hv
REQUEST_URI = /post.php?dir=ms_hv
REQUEST_TIME = 1323091613
Post Params:
key: '<?xml_version' value: '"1.0" encoding="utf-8"?><wc-request:request xmlns:wc-request="urn:com.microsoft.wc.request"><header><method>CreateAuthenticatedSessionToken</method><method-version>2</method-version><app-id>bc1fdbef-f814-4ee3-b414-1e9f6956c7ab</app-id><language>de</language><country>DE</country><msg-time>2011-12-05T14:26:51.31Z</msg-time><msg-ttl>1800</msg-ttl><version>2.0.0.0</version></header><info><auth-info><app-id>05a059c9-c309-46af-9b86-b06d42510550</app-id><credential><appserver2><sig digestMethod="SHA1" sigMethod="RSA-SHA1" thumbprint="50054D4FAEE16F69AAF66B7596ED30F9922B949E">fZaPzgI3x2ngzKnI2AU0leWgR7ycj7GcABPxktIKRd/u5eWk4dMGLiHv7x9oLKDAGC9BtAOGqe1YX80OpRFQC3VCioc9SGyAtBf0dTiM2tNcDTIboNqq0 m/d8FaI/MjIt8SlvXbV/LmCnEnjToPaiYnXqesJLflNUBRgotH2MK6YljcdB3G2JxghBlaqAYXKfx7c 8WQ9hA nnw75kTaJWXdgTAtdb0yUT5poYvm/ahG1PEl9BQCrR CmdYGECet4nlT1pFozYizI1lpZ4DQEv5eDz9YHGsqGO59oSOTX3iamRK wsaVvhKUBqS6 g7Q34wRa pv9mTocenMmCFOQ==</sig><content><app-id>bc1fdbef-f814-4ee3-b414-1e9f6956c7ab</app-id><hmac>HMACSHA256</hmac><signing-time>2011-12-05T14:26:51.3193190Z</signing-time></content></appserver2></credential></auth-info></info></wc-request:request>'
== Begin post body ==
== End post body ==
The issue I don't understand is the post body beeing empty. All the post-data is shown in "Post Params". Is this correct? Could this be the fault?
Please tell me if you need more detailed description.
Solution (probably):
The post body is empty but in the specification it says "XML in the body of an HTTP request", this probably means "in the POST body" (but mine is empty). I'll check out this posibility.
By using a "?" in your URL, you use the HTTP GET method. You can mix GET and POST in one request (which can lead to some obscure problems, especially when register_globals is switched on in your php-installation), but you shouldn't:
As I interpret your error-message, your server does not accept submitting the informations via HTTP GET. Instead you have to use the HTTP POST method. An example for a HTTP POST using QT you can find here.