GithubHelp home page GithubHelp logo

handnot2 / sigaws Goto Github PK

View Code? Open in Web Editor NEW
11.0 1.0 17.0 39 KB

An Elixir library to sign and verify HTTP requests using AWS Signature V4

License: MIT License

Elixir 100.00%
aws-signature elixir-library authentication

sigaws's Introduction

Sigaws

An Elixir library to sign and verify HTTP requests using AWS Signature V4.

Inline docs

Installation

This package can be installed by adding sigaws to your list of dependencies in mix.exs:

def deps do
  [{:sigaws, "~> 0.7"}]
end

Documentation

Examples

Signature to be passed as request headers

url = "https://ec2.amazonaws.com/Action=DescribeRegions&Version=2013-10-15"

{:ok, %{} = sig_data, _} =
  Sigaws.sign_req(url, region: "us-east-1", service: "ec2",
    access_key: System.get_env("AWS_ACCESS_KEY_ID"),
    secret:     System.get_env("AWS_SECRET_ACCESS_KEY"))

{:ok, resp} = HTTPoison.get(url, sig_data)

You can pass in request headers to be included in the signature. Make sure to merge the signature with the headers before sending the request.

The same example is shown here making use of the temporary credentials obtained using AWS STS Secure Token Service. Assuming the temporary credentials and the session token are made available in environment variables:

url = "https://ec2.amazonaws.com/Action=DescribeRegions&Version=2013-10-15"
headers = %{"X-Amz-Secure-Token" => System.get_env("AWS_SESSION_TOKEN")}

{:ok, %{} = sig_data, _} =
  Sigaws.sign_req(url, region: "us-east-1", service: "ec2", headers: headers,
    access_key: System.get_env("AWS_ACCESS_KEY_ID"),
    secret:     System.get_env("AWS_SECRET_ACCESS_KEY"))

{:ok, resp} = HTTPoison.get(url, Map.merge(headers, sig_data))

Make sure to merge sig_data with other headers before calling HTTPoison. If not done, the HTTP request will fail with signature verification error.

Signature to be passed in query string ("presigned" URL)

url = "https://iam.amazonaws.com/Action=CreateUser&UserName=NewUser&Version=2010-05-08"

{:ok, %{} = sig_data, _} =
  Sigaws.sign_req(url, region: "us-east-1", service: "iam", body: :unsigned,
    access_key: System.get_env("AWS_ACCESS_KEY_ID"),
    secret: System.get_env("AWS_SECRET_ACCESS_KEY"))

presigned_url = Sigaws.Util.add_params_to_url(url, sig_data)

{:ok, resp} = HTTPoison.get(presigned_url)

When creating pre-signed URL for AWS S3, make sure to pass in body: :unsigned option. It is also very importnt to merge the signature data with other query parameters before sending the request (Sigaws.Util.add_params_to_url). The request will fail if these are not taken care of.

Signature Verification

The verification process relies on a provider module that implements Sigaws.Provider behavior. The provider is expected to supply the signing key based on the information present in the context (primarily the access key).

{:ok, %Sigaws.Ctxt{} = ctxt} =
  Sigaws.Verify(conn.request_path,
    method: conn.method,
    params: conn.query_params,
    headers: conn.req_headers,
    body: get_raw_body(conn),
    provider: SigawsQuickStartProvider)

The above example is using the sigaws_quickstart_provider Hex package. Check the blog listed earlier.

Test Suite

Part of the tests in this package rely on AWS Signature Version 4 Test Suite. This test suite should be downloaded and unpacked before running the tests.

mkdir -p test/testsuite
cd test/testsuite
wget https://docs.aws.amazon.com/general/latest/gr/samples/aws-sig-v4-test-suite.zip
unzip aws-sig-v4-test-suite.zip

sigaws's People

Contributors

handnot2 avatar zeroasterisk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

sigaws's Issues

put Bucket Versioning API returning Signature Error

We tried to use the put_bucket_versioning API but we cannot make it work.
We are using SigAWS library in elixir for a signature generation

Here I provide my code and response:
` url = "http://localhost:9000/test-2/?versioning"

body = Poison.encode!(%{
VersioningConfiguration: %{
Status: "Enabled"
}
})

{:ok, %{} = sig_data, _} =
Sigaws.sign_req(url, service: "s3",
method: "PUT",
access_key: "minioadmin",
secret: "minioadmin" )
response = HTTPoison.put(url, body, sig_data, [])`
Our Signature:

%{ "Authorization" => "AWS4-HMAC-SHA256 Credential=minioadmin/20200803/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=8ebe222447092a680ec23b5a39a9a23c7534f553532c1d3795f02cae8edd94cc", "X-Amz-Algorithm" => "AWS4-HMAC-SHA256", "X-Amz-Content-Sha256" => "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "X-Amz-Date" => "20200803T123312Z", "X-Amz-SignedHeaders" => "host;x-amz-date" }

The response we are getting from Minio:
{:ok, %HTTPoison.Response{ body: "\nXAmzContentSHA256MismatchThe provided 'x-amz-content-sha256' header does not match what was computed.test-2/test-2/1627C21608F0480A628b08f3-7ffe-442d-bf96-20083da98366", headers: [ {"Accept-Ranges", "bytes"}, {"Content-Length", "347"}, {"Content-Security-Policy", "block-all-mixed-content"}, {"Content-Type", "application/xml"}, {"Server", "MinIO/RELEASE.2020-07-27T18-37-02Z"}, {"Vary", "Origin"}, {"X-Amz-Request-Id", "1627C21608F0480A"}, {"X-Xss-Protection", "1; mode=block"}, {"Date", "Mon, 03 Aug 2020 12:33:12 GMT"} ], request: %HTTPoison.Request{ body: "{"VersioningConfiguration":{"Status":"Enabled"}}", headers: [ {"Authorization", "AWS4-HMAC-SHA256 Credential=minioadmin/20200803/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=8ebe222447092a680ec23b5a39a9a23c7534f553532c1d3795f02cae8edd94cc"}, {"X-Amz-Algorithm", "AWS4-HMAC-SHA256"}, {"X-Amz-Content-Sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}, {"X-Amz-Date", "20200803T123312Z"}, {"X-Amz-SignedHeaders", "host;x-amz-date"} ], method: :put, options: [], params: %{}, url: "http://localhost:9000/test-2/?versioning" }, request_url: "http://localhost:9000/test-2/?versioning", status_code: 400 }}

Looks like the sigAws library generating the wrong signature.

Tests are failing

Two tests are failing when trying them locally.

  1) test test/testsuite/aws-sig-v4-test-suite/get-vanilla-query-order-key/get-vanilla-query-order-key.req (AwsSigV4Test)
     test/aws_sig_v4_test.exs:72
     Assertion with == failed
     code:  assert authz == Map.get(sig_data, "Authorization")
     left:  "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=eedbc4e291e521cf13422ffca22be7d2eb8146eecf653089df300a15b2382bd1"
     right: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=9edc3141d0593b544cd4a62b4813f99f33ae0ce979d7a3a6ab9828e2b9355ef4"
     stacktrace:
       test/aws_sig_v4_test.exs:72: (test)

  2) test test/testsuite/aws-sig-v4-test-suite/get-vanilla-query-order-value/get-vanilla-query-order-value.req (AwsSigV4Test)
     test/aws_sig_v4_test.exs:72
     Assertion with == failed
     code:  assert authz == Map.get(sig_data, "Authorization")
     left:  "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5772eed61e12b33fae39ee5e7012498b51d56abc0abb7c60486157bd471c4694"
     right: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=a67d582fa61cc504c4bae71f336f98b97f1ea3c7a6bfe1b6e45aec72011b9aeb"
     stacktrace:
       test/aws_sig_v4_test.exs:72: (test)

Any idea?

I'm trying to use this library to generate presigned S3 URLs, but with little luck.

Does not work in production: because `Mix.env` is not there

When I build my application with edeliver + distillery this package stops working, because Mix.env is not there

I am getting:

function Mix.env/0 is undefined (module Mix is not available)

   sigaws lib/sigaws/signer.ex:46 Sigaws.Signer.sign_req/1

see this article brief note on mix

Release doesn’t have Mix application!
Forget about custom Mix tasks and all functions from Mix module in your code. They gonna fail in production. There are some alternatives that you can read about in Distillery docs.


Can you recommend a solution?

request for help - using this to authenticate an "execute-api" on AWS API Gateway endpoint

I am trying to use your mix package to execute API Gateway, authenticated requests.

background

The goal is to replace a node app I've been using, which uses this client:
https://github.com/kndt84/aws-api-gateway-client

The npm client is largely a modified copy of the AWS generated SDK for it's gateway.

goal

I'm trying to use a access_key and a secret to authenticate to an endpoint which also requires a api-key... without my handy client, I'm not exactly sure how the parts fit together...

Would you be willing to attempt to help me out?

hangouts: zeroasterisk

defmodule Demo do

  def attempt do

    # Root URL
    url = "https://xxxxxxx.execute-api.us-east-1.amazonaws.com"

    # JSON body
    body = "{ example: true }"

    # setup auth
    {:ok, %{} = sig_data, _c} = Sigaws.sign_req(
      url,
      region: "us-east-1",
      service: "execute-api",
      access_key: "xxxxxxx",
      secret:     "xxxxxxx",
      body: body
    )
    IO.puts("Sig Data")
    IO.inspect(sig_data)

    # merge in auth headers
    headers = Map.merge(sig_data, %{
      "x-api-key" => "xxxxxxx"
    })
    IO.puts("merged headers")
    IO.inspect(headers)

    # make API request
    {:ok, resp} = HTTPoison.post(url, body, headers)
    IO.puts("response")
    IO.inspect(resp)
    #%HTTPoison.Response{body: "{\"message\":\"Forbidden\"}"

    # make an API request on an "actual" endpoint
    url = "https://xxxxxxx.execute-api.us-east-1.amazonaws.com/QA/demo"
    {:ok, resp} = HTTPoison.post(url, body, headers)
    IO.puts("response")
    IO.inspect(resp)
    # %HTTPoison.Response{body: "{\"message\":\"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\\n\\nThe Canonical String for this request should have been\\n'POST\\n/QA/demo\\n\\nhost:xxxxxxx.execute-api.us-east-1.amazonaws.com\\nx-amz-date:20170720T185813Z\\n\\nhost;x-amz-date\\ne6705fd96b8778645629e04fd92336470a27ad9baea2109f1e9dd145c4ddbe22'\\n\\nThe String-to-Sign should have been\\n'AWS4-HMAC-SHA256\\n20170720T185813Z\\n20170720/us-east-1/execute-api/aws4_request\\n4b289201e109fe8ae1ff6fc9480120566f954e3a40f3fdb1aa839e37b7481838'\\n\"}",

  end
end

Handle normalization of path segments during signature computation

The set of AWS Signature V4 normalize-path tests in the test suite is failing as the path normalization is not done during the canonical request computation.

Introduce an option (normalize_path) to the signing as well as the verification functions to turn this on. By default this is turned off.

Update the API doc for Sigaws.sign_req, Sigaws.sign_url and Sigaws.verify functions.

Support precomputed content hash

How body/content are treated during signing and verification:

  • :body option not given -- Use an empty string for hash calculation
  • body: "somedata" -- Compute SHA256 for the given binary
  • body: :unsigned -- Content is not included in signature computation
  • body: {:content_hash: hash_value_as_string} -- Use the provided hash value in signature computation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.