bryanjos / aws_auth Goto Github PK
View Code? Open in Web Editor NEWAWS Signature Version 4 Signing Library for Elixir
License: Apache License 2.0
AWS Signature Version 4 Signing Library for Elixir
License: Apache License 2.0
Hello,
Thanks a lot for developing this library.
When trying to authenticate a request (by signing headers) to the ProductAdvertisingAPI service, AWS always responds with error 401: InvalidSignature.
After some digging, I noticed that this is caused by this line in the AWSAuth.AuthorizationHeader.sign/9
function:
service = String.downcase(service)
If I comment that line, AWS responds back with a successful response (200 OK).
I'm not sure if downcasing the service name is required for other use cases, but if it's not needed and this is indeed a bug, please let me know and I will submit a PR to fix it :)
EDIT: Submitted a PR in case it may be useful
Just spent an afternoon debugging this, and AWS' return error just says their calculated signature is different than my own.
Considering an ending /
on a URL is often inserted, I feel like the library standardizing this would help ease of use.
The query parameters aren't encoded as stated in the requirements
http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
URI-encode each parameter name and value according to the following rules:Do not URI-encode any of the unreserved characters that RFC 3986 defines: A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ).
Percent-encode all other characters with %XY, where X and Y are hexadecimal characters (0-9 and uppercase A-F). For example, the space character must be encoded as %20 (not using '+', as some encoding schemes do) and extended UTF-8 characters must be in the form %XY%ZA%BC.
Also, if there is no payload the hashed payload should not be: "UNSIGNED-PAYLOAD".
If the payload is empty, use an empty string as the input to the hash function. In the IAM example, the payload is empty.
Example hashed payload (empty string)
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
I'm not sure if this library is intended to be used with s3 only, but in order to sign SNS queries I needed to make those changes. Thank you for publishing this library!
Hi, in AWSAuth.QueryParameters.sign/8
function, AWSAuth.Utils.build_canonical_request/5
function is called with :unsigned
payload parameter.
So hashed_payload
variable in AWSAuth.Utils.build_canonical_request/5
function is set to "UNSIGNED-PAYLOAD"
.
But, I think "UNSIGNED-PAYLOAD"
is only for S3.
S3: Authenticating Requests: Using Query Parameters
In this guide, they instruct to use hashed empty string if payload is empty.
If the payload is empty, use an empty string as the input to the hash function.
Example hashed payload (empty string)
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
I'm not sure my report is right or wrong, but when I use AWSAuth.QueryParameters.sign/8
function to call AWS Elasticsearch service, The request signature we calculated does not match the signature you provided
error message returned.
But when I modify your code in AWSAuth.QueryParameters.sign/8
function like below, worked fine.
string_to_sign = AWSAuth.Utils.build_canonical_request(http_method, uri.path, params, headers, AWSAuth.Utils.hash_sha256(""))
Using the example on the page...
AWSAuth.sign_url("AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"GET",
"https://examplebucket.s3.amazonaws.com/*",
"us-east-1",
"s3",
Map.new,
~N[2013-05-24 00:00:00])
This fails. The exact one I tested was using AWS elasticsearch service but I'm sure it's the same here
Should probably pass in a struct with the various options.
In particular, the various "sign" functions
See comment thread here: 1e8944d
@cdegroot: Let us continue our conversation here.
@cdegroot provided this script to attempt to reproduce the issue:
method = :get
url = "http://foo.bar/lol"
headers = [host: "foo.bar"]
body = "This is some body stuff"
access_key_id = "1234"
secret_access_key = "abcdef"
region = "us-west-2"
aws_config = %{}
|> Map.put(:access_key_id, access_key_id)
|> Map.put(:secret_access_key, secret_access_key)
|> Map.put(:region, region)
|> Map.put(:enabled, true)
Application.put_env(:elastic, :aws, aws_config)
IO.inspect Elastic.AWS.sign_authorization_headers(method, url, headers, body)
This script fails because the sign_authorization_headers
function is not defined here. I think @cdegroot meant sign_url
, so I amended the script to do that.
method = :get
url = "http://foo.bar/lol"
headers = [host: "foo.bar"]
body = "This is some body stuff"
access_key_id = "1234"
secret_access_key = "abcdef"
region = "us-west-2"
aws_config = %{}
|> Map.put(:access_key_id, access_key_id)
|> Map.put(:secret_access_key, secret_access_key)
|> Map.put(:region, region)
|> Map.put(:enabled, true)
Application.put_env(:elastic, :aws, aws_config)
IO.inspect Elastic.AWS.sign_url(method, url, headers, body)
I then attempted to run this under the elastic repo, checked out to current master (radar/elastic@eca120b). The current master has aws_auth locked to 0.6.2.
I then ran this script using mix run repro.exs
, and got the following output:
"http://foo.bar/lol?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=1234%2F20170613%2Fus-west-2%2Fes%2Faws4_request&X-Amz-Date=20170613T032051Z&X-Amz-Expires=86400&X-Amz-Signature=ca0745177024aa6cfc985d629d2b92a8dba9854b9de5572d3d27d5a2fb3c9e7a&X-Amz-SignedHeaders=host"
Then I bumped the dependency to 0.6.4 by running mix deps.update aws_auth
. I then ensured this dependency was indeed updated by running mix deps
:
* aws_auth (Hex package) (mix)
locked at 0.6.4 (aws_auth) 4ecd73cb
Then I ran the script again, using the same command (mix run repro.exs
) and I still see the same output:
"http://foo.bar/lol?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=1234%2F20170613%2Fus-west-2%2Fes%2Faws4_request&X-Amz-Date=20170613T032223Z&X-Amz-Expires=86400&X-Amz-Signature=20849cbf7b66598caa57f1a9255b08431780e12a979ba4b5b881f2045488fdb5&X-Amz-SignedHeaders=host"
I would like @cdegroot to provide steps -- similar to mine -- to show an issue here. I am unable to reproduce it, but I would still like to investigate it as he claims to be seeing something.
First, thanks for the lib, great work!
I'm using it to sign a multipart upload direct to S3, so the payload never hit my server. I'm calculating it in JavaScript and send it to my server to generate the authorization header.
I was thinking in augment AWSAuth.Utils.build_canonical_request to also check for :hashed in the hashed_payload, in this case, the function uses the hashed payload in the header, what do you think? Can I make a PR?
Best regards!
Hi, I think you should update your hex package to use Timex 2.0.
Your mix.exs in master branch is like below:
defp deps do
[{:timex, "~> 2.0"}]
end
But mix.exs in your newest hex package is like below:
defp deps do
[{:timex, "~> 1.0"}]
end
I think you uploaded old source code to hex.pm.
Hey, would you mind tagging the releases you have on hex.pm as releases here as well? Right now there isn't any easy way (other than by date) to determine what ref the package on hex is at.
Thanks!
I'm creating a pre-signed download URL using this library but the URL returns the response
<Error>
<Code>AuthorizationQueryParametersError</Code>
<Message>
X-Amz-Expires must be less than a week (in seconds); that is, the given X-Amz-Expires must be less than 604800 seconds
</Message>
<RequestId>85DDB241260CEC72</RequestId>
<HostId>
pUQGWiJp/zQ5Br8FTFLVmb7ux90BOTdn/H0UIB3dbnbdQ3vO3NJew03lnvd5z3HZPy8R9h9d9Es=
</HostId>
</Error>
The URL is being created simply with
AWSAuth.sign_url(access_key(), secret_key(),
"GET",
"https://#{bucket_name()}.s3.amazonaws.com/#{path}",
"us-east-1",
"s3")
The image URL returned looks like
https://s3-my-bucket.s3.amazonaws.com/path/to/a/file?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIKA6QF7QLU6QQMEA%2F20170718%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20170718T132934Z&X-Amz-Expires=6307000000&X-Amz-Signature=ff29e0c334846ef6c8f2279f9835423d7ce7dc1333a91729fff17707dab2f450&X-Amz-SignedHeaders=host
Is there something obvious that would affect this? I've looked at the library source and nothing stands out.
Thanks
Add support to :crypto.mac/4 and keep back compatibility with the old :crypto.hmac/3.
I was looking at how I could emulate http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html with your library
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.