More specific rules for an AWS Canonical Request header list? - amazon-web-services

The AWS documentation here seems to have somewhat confusing, incomplete or contradictory information. It states that
CanonicalHeaders is a list of request headers with their values.
Which suggests that we'd put all request headers in the canonical request. However, later, they state
The CanonicalHeaders list must include the following:
HTTP host header
If the Content-Type header is present in the request, it must be added to the CanonicalHeaders list.
Any x-amz-* headers that you plan to include in your request must also be added. For example, if you are using temporary security credentials, you will include x-amz-security-token in your request. You must add this header in the list of CanonicalHeaders.
OK, the bit about the Content-Type and x-amz headers suggests that we don't actually take all headers, because otherwise they wouldn't need to state that they'd be must be included. So then perhaps, we only need to take the Host header, the Content-Type header, and any x-amz-* headers. But then below, it gets more confusing, because here's an example request:
GET /test.txt HTTP/1.1
Host: examplebucket.s3.amazonaws.com
Date: Fri, 24 May 2013 00:00:00 GMT
Authorization: SignatureToBeCalculated
Range: bytes=0-9
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date: 20130524T000000Z
And here's the example canonical request created from it:
GET
/test.txt
host:examplebucket.s3.amazonaws.com
range:bytes=0-9
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date:20130524T000000Z
host;range;x-amz-content-sha256;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
But this is inconsistent with both of the interpretations earlier: if we're supposed to only have Content-Type, Host and x-amz-* headers, then what is the range header doing in the list? And if we're just supposed to take all of the headers, then why isn't the Date header in the list?
Is the list of headers to put in a canonical request then arbitrary, as long as it contains at least the minimum headers? What, exactly, is the definitive set of rules to construct the canonical request headers?

if we're supposed to only have Content-Type, Host and x-amz-* headers,
then what is the range header doing in the list?
You are only required to have Content-Type, Host, and x-amz-*, but you can add other headers that you would like to add to the signature to be validated.
See the note in the docs that says: "For the purpose of calculating a signature, only the host and any x-amz-* headers are required; however, in order to prevent data tampering, you should consider including all the headers in the signature calculation."
And if we're just supposed to take all of the headers, then why isn't
the Date header in the list?
The Date header is special, because it is added by the browser according to client system time that may be incorrect. Because of that, you can use x-amz-date instead.
Is the list of headers to put in a canonical request then arbitrary,
as long as it contains at least the minimum headers?
Yes!
What, exactly, is the definitive set of rules to construct the
canonical request headers?
That would be those defined in the documentation of AWS signature version 4... but you got the idea: you must sign the minimal set of request data and can sign all headers that you'd like.
That said, avoid all this if you can. The SDK for [Javascript, Java, .NET, Python, Ruby, PHP,...] already sign requests for you, manages temporary credentials, credential chains, threading, retries and a lot more. If you can use that, it would probably save a lot of headache.

Related

Postman: add a given header to all requests in the given collection or collection-level header

My question:
Postman: add a given header to all requests in the given collection or collection-level header.
Details (like screenshots):
I have “x-apikey” header & a bunch of requests in the collection without this specific header.
How can I avoid manual work of adding header one by one to each request?
Anyone has an existing solution, please?
How I found the problem:
Imported OpenAPI spec & it does not contain the needed header. Hence, need to add to each request.
You should be able to do this in your Pre-request Scripts at the Collection level.
pm.request.headers.add({key: 'x-apikey', value: 'token_value' })

In Owin is it possible to set multiple set-cookie headers

It seems that OWIN uses "context.Response.Headers" as a IDictionary. This precludes returning multiple cookies ("Set-Cookie") for a request.
Is there a way around this silly limitation.
Use ResponseCookieCollection.Append method.
Example usage:
context.Response.Cookies.Append("cookie", "1");
context.Response.Cookies.Append("cookie", "2");
Side note:
From section 4.1 of RFC 6265:
Servers SHOULD NOT include more than one Set-Cookie header field in
the same response with the same cookie-name. (See Section 5.2 for
how user agents handle this case.)
Hence multiple Set-Cookie headers with the same key (as in example above) are not recommended, but not forbidden.

In REST, How to discover acceptable media types?

Given a REST api.
I want to learn what media types I can set in the Accept header.
How should I this?
I know I could do a random
GET http://some.api.com/
Accept:flying/elephants
and hope for a 406 with a body that has the correct acceptable media types.
Is there a better way?
In theory, API could indicate supported Content Types via HTTP OPTIONS
Usually, API offers either
Documentation
Specific resource of supported Accept-header values.
Also (as you might know), Accept-header values are usually bound to IANA defined MIME types
One issue with this is any URI within the API can respond with different media types. It's very common to have different endpoints in the API return different content types.
You could use multiple wildcard requests to probe for support.
You can start with Accept: */* and then application/* text/* */json */xml etc. You would receive a non-exhaustive list, but you'd get the big ones and the the preferred ones.
There's other weird edge cases. For example OData allows you to specify a $format parameter in the URL to define the response type. This overrides the accept header. Thus every format is it's own URI.
It'd be cool if APIs made more use of the alternate link relationship (http://www.w3.org/TR/html5/links.html#rel-alternate), i think that would be the most appropriate. That combined with the type attribute of the link would let you know all the formats for any resource you retrieve. Again it would be specific to each URI though.

Using HTTP URIs as identifiers of resources in RESTful web API

Usually to retrieve a resource one uses:
GET http://ws.mydomain.com/resource/123212
But what if your item IDs are HTTP URIs?:
GET http://ws.mydomain.com/resource/http://id.someotherdomain.com/SGX.3211
Browsers replace two slashes with one, and the request turns into:
GET http://ws.mydomain.com/resource/http:/id.someotherdomain.com/SGX.3211
which will not work.
URI encoding the "http://id.someotherdomain.com/SGX.3211" -part results in HTTP 400 - Bad request.
Is there a best practice for handling this?
Edit:
Then of course if we would need to have (I don't at the moment) request in form:
resources/ID/collections/ID
and all IDs are HTTP URIs, things get out of hand... Possibly one could do something like this and parse the contents inside the curly braces:
resources/{http://id...}/collections/{http://id...}
Encode the other system's URI, and then pass the value as a query parameter:
GET http://ws.mydomain.com/resource?ref=http%3A%2F%2Fid.someotherdomain.com%2FSGX.3211
Ugly looking, but no one said that URIs used in a REST architecture have to be beautiful. :)
By the way, a GET actually looks like this when it's sent:
GET /resource?ref=http%3A%2F%2Fid.someotherdomain.com%2FSGX.3211 HTTP/1.1
Host: ws.mydomain.com
UPDATE: apparently you no longer have to encode "/" and "?" within a query component. From RFC 3986:
The characters slash ("/") and question mark ("?") may represent data
within the query component. Beware that some older, erroneous
implementations may not handle such data correctly when it is used as
the base URI for relative references (Section 5.1), apparently
because they fail to distinguish query data from path data when
looking for hierarchical separators. However, as query components are
often used to carry identifying information in the form of "key=value"
pairs and one frequently used value is a reference to another URI, it
is sometimes better for usability to avoid percent-encoding those
characters.
So you could legally do this:
GET /resource?ref=id.someotherdomain.com/SGX.3211 HTTP/1.1
Host: ws.mydomain.com

How to properly send 406 status code?

I'm developing a RESTful API service which initially will only be accepting and responding in JSON format. I want to follow standards and in case of requester's Accept header was different than JSON I want to respond with 406 HTTP status code to inform the requester I cannot output data in other format.
According to W3 I "SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate" in my response.
How do I do that, because the above explanation doesn't tell me much. What is the mentioned entity?
Any ideas/suggestions?
EDIT
Initially I thought that maybe could be a comma separated list in Content-Type header but after rethinking maybe I should do the same thing browsers do and use Accept header? This makes much more sense actually, but I cannot find any information to support this.
Three issues here:
First, the note from RFC 2616 is meant to address URI schemes where responses of different types are made available at various URI's, such as "/path/to/thing.xml" vs "/path/to/thing.json". That's not always a popular choice, but if you can do that, do so and include hyperlinks to each one in the "entity"; that is, in the body of the response. Since the RFC doesn't mandate a Content-Type or processing model for such links, you're on your own regarding how to return them, but HTML with <a> tags is common and useful.
If you don't want to expose multiple types at separate URI's, but just want to expose one type at the original URI, then it's perfectly fine to respond with 406 and an entity that simply says which types the resource can emit.
Second, note that most web browsers send */* in the Accept header (with a low quality value), which should match any Content-Type. In addition, the spec says "...if no Accept header field is present, then it is assumed that the client accepts all media types." So the cases where you should be raising 406 are rare.
Third, don't emit a Content-Type response header that is anything other than the Content-Type of the response entity. It should not be used to list acceptable types. You should also not emit a response header named 'Accept'; the 'Accept' header is for requests only; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1