Reproduce code: https://github.com/p-mongo/tests/blob/master/server-aws/test.rb
If I try to authenticate using AWS mechanism and I send the following authorization header:
payload = {
a: 'AWS4-HMAC-SHA256 \
Credential=ASIAYDYF24CYGCSCSRHQ/20200411/us-east-1/sts/aws4_request, \
SignedHeaders=content-length;content-type;host;x-amz-date;x-mongodb-gs2-cb-flag;x-mongodb-server-nonce, \
Signature=ec792fffff0a39bbaec8c043999d0dd63e401720be860a1496d968ab82dd817b',
d: 'dummy',
}
... the server accepts this header and tries to authenticate to STS, based on the following message that it logs in the log:
{"t":{"$date":"2020-04-10T21:12:07.923-0400"},"s":"I", "c":"ACCESS", "id":20249,"ctx":"conn80","msg":"SASL {mechanism} authentication failed for {principalName} on {authDB} from client {client} ; {result}","attr":{"mechanism":"MONGODB-AWS","principalName":"ASIAYDYF24CYGCSCSRHQ","authDB":"$external","client":"127.0.0.1:44500","result":"OperationFailed: Unexpected http status code from server: 400"}}
If I add an additional header 'anotherhost' to the list of signed headers, such that I now send the following payload:
payload = {
a: 'AWS4-HMAC-SHA256 \
Credential=ASIAYDYF24CYGCSCSRHQ/20200411/us-east-1/sts/aws4_request, \
SignedHeaders=anotherhost;content-length;content-type;host;x-amz-date;x-mongodb-gs2-cb-flag;x-mongodb-server-nonce, \
Signature=ec792fffff0a39bbaec8c043999d0dd63e401720be860a1496d968ab82dd817b',
d: 'dummy',
}
The server writes the following into the logs:
{"t":{"$date":"2020-04-10T21:16:34.600-0400"},"s":"I", "c":"ACCESS", "id":20249,"ctx":"conn82","msg":"SASL {mechanism} authentication failed for {principalName} on {authDB} from client {client} ; {result}","attr":{"mechanism":"MONGODB-AWS","principalName":"","authDB":"$external","client":"127.0.0.1:44514","result":"Location51290: Did not find expected header"}}
This message is extremely confusing because it is also produced when the driver sends the same set of headers that AWS SDK sends plus the required x-mongodb-gs2-cb-flag and x-mongodb-server-nonce headers.
The set of headers that AWS SDK sends can be obtained by running this code in Ruby:
sts_client = Aws::STS::Client.new( http_wire_trace: true, ) sts_client.get_caller_identity
... which produces on my machine:
<- "POST / HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded; charset=utf-8\r\nAccept-Encoding: \r\nUser-Agent: aws-sdk-ruby3/3.94.0 ruby/2.7.0 x86_64-linux aws-sdk-core/3.94.0\r\nHost: sts.us-east-1.amazonaws.com\r\nX-Amz-Date: 20200411T012315Z\r\nX-Amz-Security-Token: FwoGZXIvYXdzEBoaDKUWpj1e7MKi6pCUFiKmAU83cjSecTCVGtqQGABzuBbEXbFQ7dAn7CKTxP1B64WvbwXBQvFrKQFbXSTxD7L/sVpqa2DayZ57JXRnFNvCKA2ic4wmqrPiqoztLMrMI89hKqNE7OWha5p8tRG//mjgEEgcJ9jclweo8ttBjFBK1KKaKbPUDR1RHu8u3A0Y7Gh5VaMatGdnc0wHdTk9SvGcRMfSYMxothKi7buUvSIb8i+JurszVCwo9KbE9AUyLbU3NgWLvUOIG8JrmxGZw5ttjRvgkwnJ2kzXbiZgv9Rl/0tttZhF3jrHZdBx0A==\r\nX-Amz-Content-Sha256: ab821ae955788b0e33ebd34c208442ccfc2d406e2edc5e7a39bd6458fbb4f843\r\nAuthorization: AWS4-HMAC-SHA256 Credential=ASIAYDYF24CYGCSCSRHQ/20200411/us-east-1/sts/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=2f1c07e24e5338e856246c0bda27529ae33ede903dd3499eec1d281e82a1729a\r\nContent-Length: 43\r\nAccept: */*\r\n\r\n"
So, transfering this set of headers to the payload for aws auth:
payload = {
a: 'AWS4-HMAC-SHA256 \
Credential=ASIAYDYF24CYGCSCSRHQ/20200411/us-east-1/sts/aws4_request, \
SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-mongodb-gs2-cb-flag;x-mongodb-server-nonce, \
Signature=ec792fffff0a39bbaec8c043999d0dd63e401720be860a1496d968ab82dd817b',
d: 'dummy',
}
... this produces the "did not find expected header" message.
Since the above request specifies all headers that Amazon's official client uses, it is baffling which other headers are NOT specified.
Another time when this message is extremely confusing is when all of the headers are provided but they are not lexicographically ordered, for example as in the following request:
payload = {
a: 'AWS4-HMAC-SHA256 \
Credential=ASIAYDYF24CYGCSCSRHQ/20200411/us-east-1/sts/aws4_request, \
SignedHeaders=content-length;host;content-type;x-amz-date;x-mongodb-gs2-cb-flag;x-mongodb-server-nonce, \
Signature=ec792fffff0a39bbaec8c043999d0dd63e401720be860a1496d968ab82dd817b',
d: 'dummy',
}
As a driver engineer working with the server, I would like the server to produce error logs that accurately describe the error condition.
According to my investigation, the "did not find expected header" message is produced because the server hardcodes the set of headers it is expecting (and potentially their order?) and when it encounters a header it did not expect, or too many headers, it misreports that condition as "did not find expected header".