2

I'm trying to use Elixir to access Azure Storage Services via their REST API but I'm having difficulty getting the Authentication Header to work. I am able to connect if I use the ex_azure package (wrapper for erlazure) but not when I try to build the request and use HTTPoison.

Most Recent Error Messages

<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Error>
  <Code>AuthenticationFailed</Code>
  <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:00000000-0000-0000-0000-000000000000\nTime:2017-08-02T21:46:08.6488342Z</Message>
  <AuthenticationErrorDetail>The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\nWed, 02 Aug 2017 21:46:08
    GMT\nx-ms-date-h:Wed, 02 Aug 2017 21:46:08 GMT\nx-ms-version-h:2017-05-10\n/storage_name/container_name?comp=list'.</AuthenticationErrorDetail>
</Error>

After 1st Edit

  <?xml version=\"1.0\" encoding=\"utf-8\"?>
  <Error>
    <Code>AuthenticationFailed</Code>
    <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:00000000-0000-0000-0000-000000000000\nTime:2017-08-03T03:03:57.1385277Z</Message>
    <AuthenticationErrorDetail>The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 03 Aug
      2017 03:03:57 GMT\nx-ms-version:2017-04-17\n/storage_name/container_name\ncomp:list\nrestype:container'.</AuthenticationErrorDetail>
  </Error>

Dependencies

# mix.exs
defp deps do
  {:httpoison, "~> 0.12"}
  {:timex, "~> 3.1"}
end

Code

  • Am I formatting the Authentication Header (string_to_sign) right?
  • Am I using encode/decode right?
  • Am I adding headers correctly to HTTPoison?
  • Should I be using something else for REST actions instead of HTTPoison?
# account credentials
storage_name            = "storage_name"
container_name          = "container_name"
storage_key             = "storage_key"
storage_service_version = "2017-04-17" # fixed version

request_date =
  Timex.now
  |> Timex.format!("{RFC1123}") # Wed, 02 Aug 2017 00:52:10 +0000
  |> String.replace("+0000", "GMT") # Wed, 02 Aug 2017 00:52:10 GMT

# set canonicalized headers
x_ms_date    = "x-ms-date:#{request_date}"
x_ms_version = "x-ms-version:#{storage_service_version}"

# assign values for string_to_sign
verb                   = "GET\n"
content_encoding       = "\n"
content_language       = "\n"
content_length         = "\n"
content_md5            = "\n"
content_type           = "\n"
date                   = "\n"
if_modified_since      = "\n"
if_match               = "\n"
if_none_match          = "\n"
if_unmodified_since    = "\n"
range                  = "\n"
canonicalized_headers  = "#{x_ms_date}\n#{x_ms_version}\n"
canonicalized_resource = "/#{storage_name}/#{container_name}\ncomp:list\nrestype:container" # removed timeout. removed space

# concat string_to_sign
string_to_sign =
  verb                  <>
  content_encoding      <>
  content_language      <>
  content_length        <>
  content_md5           <>
  content_type          <>
  date                  <>
  if_modified_since     <>
  if_match              <>
  if_none_match         <>
  if_unmodified_since   <>
  range                 <>
  canonicalized_headers <>
  canonicalized_resource

# decode storage_key
{:ok, decoded_key} =
  storage_key
  |> Base.decode64

# sign and encode string_to_sign
signature =
  :crypto.hmac(:sha256, decoded_key, string_to_sign)
  |> Base.encode64

# build authorization header
authorization_header = "SharedKey #{storage_name}:#{signature}"

# build request and use HTTPoison
url     = "https://storage_name.blob.core.windows.net/container_name?restype=container&comp=list"
headers = [ # "Date": request_date,
           "x-ms-date": request_date, # fixed typo
           "x-ms-version": storage_service_version, # fixed typo
           # "Accept": "application/json",
           "Authorization": authorization_header]
options = [ssl: [{:versions, [:'tlsv1.2']}], recv_timeout: 500]

HTTPoison.get(url, headers, options)

Notes

Some sources I used/tried...

dwyd
  • 55
  • 2
  • 9

1 Answers1

1

A few issues I noticed:

  1. You included Date request header in your request but it is not included in your string_to_sign. Either include this header in your string_to_sign or remove this header from request headers.
  2. You included timeout:30 in your canonicalized_resource but it is not included in your request URL. Again, either add timeout=30 in your request querystring or remove timeout:30 from canonicalized_resource.
  3. I have not used Elixir as such so I don't know how request headers work there, but you're naming your request headers as x-ms-date-h and x-ms-version-h. Shouldn't they be x-ms-date and x-ms-version respectively?
Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • Thank you for the feedback. #1 I removed `Date` from the header. #2 I removed `timeout:30` from `caonicalized_resource`. #3 I removed `-h`; that was a typo. It's still not working but the `Server used following string to sign` portion of the error message seems to look better. I've updated the question to reflect your suggestions and show the most recent error message. – dwyd Aug 03 '17 at 03:14
  • 1
    I got it working. I had another typo in `canonicalized_resource`. I had to remove a 'space', `/#{storage_name}/ #{container_name}` -> `/#{storage_name}/#{container_name}`. I was following the example `GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n/myaccount/ mycontainer\ncomp:metadata\nrestype:container\ntimeout:20` in Microsoft's docs (first reference in question); the space seems to be a typo `...\n/myaccount/ mycontainer\n...` . The code in the question should now working. Thank you for your help! – dwyd Aug 03 '17 at 03:27
  • You might also try this: https://github.com/chgeuer/ex_microsoft_azure_storage/blob/4bce95d59fe4c3f40373ca4b1fc4831b67fd37aa/lib/microsoft/azure/storage/request_builder.ex#L144-L194 – chgeuer May 29 '18 at 08:57