2

I'm trying to create a SAS url for my windows media services file using custom ruby code (ported from official php library for azure). The code looks like that:

def create_signature(path = '/', resource = 'b', permissions = 'r', start = '', expiry = '', identifier = '')
  # If resource is a container, remove the last part (which is the filename)
  path = path.split('/').reverse.drop(1).reverse.join('/') if resource == 'c'
  canonicalizedResource = "/mediasvc78m7lfh2gnn2x/#{path}"

  stringToSign  = []
  stringToSign << permissions
  stringToSign << start
  stringToSign << expiry
  stringToSign << canonicalizedResource
  stringToSign << identifier

  stringToSign = stringToSign.join("\n")
  signature    = OpenSSL::HMAC.digest('sha256', wms_api_key, stringToSign.encode(Encoding::UTF_8))
  signature    = Base64.encode64(signature)

  return signature
end

def createSignedQueryString(path = '/', query_string = '', resource = 'b', permissions = 'r', start = '', expiry = '', identifier = '')
  base = 'https://mediasvc78m7lfh2gnn2x.blob.core.windows.net'
  uri  = Addressable::URI.new

  # Parts
  parts       = {}
  parts[:st]  = URI.unescape(start) unless start == ''
  parts[:se]  = URI.unescape(expiry)
  parts[:sr]  = URI.unescape(resource)
  parts[:sp]  = URI.unescape(permissions)
  parts[:si]  = URI.unescape(identifier) unless identifier == ''
  parts[:sig] = URI.unescape( create_signature(path, resource, permissions, start, expiry) )

  uri.query_values = parts
  return "#{base}/#{path}?#{uri.query}"
end

When running:

puts createSignedQueryString(
  'asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4',
  nil,
  'b', 
  'r', 
  (Time.now - 5*60).utc.iso8601, 
  (Time.now + 30*60).utc.iso8601
)

it gives me the following url: https://mediasvc78m7lfh2gnn2x.blob.core.windows.net/asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4?se=2014-02-20T12%3A59%3A19Z&sig=RDc9nVMuf1dy%2BPrnzCkA8pZfgry2ZwrF08u9itf4v%2FA%3D%0A&sp=r&sr=b&st=2014-02-20T12%3A24%3A19Z

When i try to point my browser to it, i'm getting:

<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:ee7fd18f-cd1f-4179-8a58-c8b746d0549c Time:2014-02-20T12:29:27.0468171Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was r 2014-02-20T12:24:19Z 2014-02-20T12:59:19Z /mediasvc78m7lfh2gnn2x/asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4
</AuthenticationErrorDetail>
</Error>

Have you any idea what can be causing that error (or how to debug it?) and how to deal with that? Thanks in advance.

mbajur
  • 4,406
  • 5
  • 49
  • 79

1 Answers1

4

Assuming you're using the storage key directly from the portal and using that in your wms_api_key variable (or in other words your wms_api_key is a Base64 encoded string, I believe you would need to convert it first as byte array for calculating signature. You would need to do something like:

signature    = OpenSSL::HMAC.digest('sha256', Base64.strict_decode64(wms_api_key), stringToSign.encode(Encoding::UTF_8))

This is based on the source code for Azure SDK for Ruby on Github.

UPDATE

One more issue I discovered. If you notice your SAS URL, you would notice %0A at the end of sig query string parameter which is essentially a new line character. Not sure why this is coming but I think it is inserted automatically when you do the following:

signature    = Base64.encode64(signature)

However if I use strict_encode64 instead of encode64 method, this is not inserted and everything works great. So try the following code:

signature    = Base64.strict_encode64(signature)

I just tried it and it worked great for me.

Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • Thank you for beeing more helpfull than payed azure support :) Anyway, i'm using the "Primary Windows Media Service access key" as my wms_api_key variable. When i'm trying to use your code on it, it throws `unpack: invalid base64 (ArgumentError)` – mbajur Feb 25 '14 at 08:48
  • I see. You actually need to use storage account key for wms_api_key variable and not media service access key. – Gaurav Mantri Feb 25 '14 at 08:49
  • Oh ok. I didn't have any info on what should be used there so i tried it with wms key. Anyway, it still throws the same error. New link is https://mediasvc78m7lfh2gnn2x.blob.core.windows.net/asset-12514a3b-565f-4150-9543-e3c2b4531428/video.mp4?se=2014-02-25T09%3A21%3A28Z&sig=AV9nieaGkq1x3EXEvk3T2CQz0ZK41g9rwgxrTOjnnVs%3D%0A&sp=r&sr=b&st=2014-02-25T08%3A46%3A28Z – mbajur Feb 25 '14 at 09:17
  • I just tried with my storage account and it worked perfectly fine. Can you update your question with the latest code? – Gaurav Mantri Feb 25 '14 at 09:34
  • Here is my full code - http://gist.github.com/mbajur/0de637fe68fe9333856b . My setup is: windows media service is creating a new `asset-7f8f4ccc-e889-41b9-9df2-d14a5666080f` [private] container (with `video.mp4` file inside) in `mediasvc78m7lfh2gnn2x` storage. – mbajur Feb 25 '14 at 10:21
  • Updated my answer. HTH. – Gaurav Mantri Feb 25 '14 at 10:37
  • Oh my god, thank you SO MUCH! There should be some way to compensate on stack overflow with something more than just an up-vote and accepted answer. You're truly awsome, thank you. – mbajur Feb 25 '14 at 10:46
  • 1
    :). I also learnt a bit of Ruby today so thank you for that. BTW, you may find this thread useful on this new line character when calling Base64.encode64: http://stackoverflow.com/questions/2620975/strange-n-in-base64-encoded-string-in-ruby. – Gaurav Mantri Feb 25 '14 at 10:48
  • Yeah i can now remember i had a similar issue with the new line character at the end of base64 string when i was generating some kind of auth token using different API :) – mbajur Feb 25 '14 at 16:06