0

I'm in the process of creating a ruby wrapper for an API, but they seem to be using some kind of weird authorization which isn't supported in Faraday so it seems that I have to create my own function to generate this. They have this on their site

Your API credentials consist of a public client identifier (UUIDv4), and a secret key (32 bytes, delivered base64 encoded). Organization level request authentication is done with a Amazon-style HMAC

and this

Content-MD5: base64(md5(body)), RFC 1864 (binary md5)
Content-Type: 'application/json'
Date: 'Mon, 07 Dec 2015 22:57:52 +0200' (RFC 2822)
Authorization: 'Success ' + client_identifier + ':' +
    base64(
      sha512_hmac( // returned as binary
        join(
          '\n', // unix newline, not the 2 character string
          [
            http_verb,    // 'POST' / 'GET' / etc.
            Content-MD5,  // Same as header above. Include even for empty string body.
            Content-Type, // Same as header above. Can be empty.
            Date,         // Same as header above.
            http_path     // '/api/v1/document/?foo=bar'
          ]
        ),
        key // in binary, remember to decode base64
      )
    )

now I've managed to construct a pretty messy function as follows

def create_authorization_header(path, payload)
    date = Date.today.rfc2822            
    md5_file = Digest::MD5.hexdigest(payload)
    content_md5 = Base64.strict_encode64(md5_file)
    digest = OpenSSL::Digest.new('sha512')                
    autorization_header = "GET " + content_md5 + " application/json " + date + path
    autorization_header_enc =  'Success '+ identifier + ':' + Base64.strict_encode64(OpenSSL::HMAC.digest(digest, api_key, autorization_header))
    connection.headers['Authorization'] = autorization_header_enc
    connection.headers['Content-MD5'] = content_md5
    connection.headers['Content-type'] = "application/json"     
    connection.headers['Date'] = date       
end

but this doesn't seem to be working and I cannot find what I'm missing. Any suggestions on what might be wrong here?

Daniel
  • 183
  • 1
  • 7

1 Answers1

0

You concatenate most parts of your autorization_header with a space as a separator. According to the python example code, they should all be separated by a newline character. You could use something like this instead:

autorization_header = ["GET", content_md5, "application/json", date, path].join("\n")

Additionally, your content_md5 uses the base64 encoded hex-encoded output of the MD5 hash. However, you should use the base64 encoded raw binary output of the md5 hash, i.e.

md5_file = Digest::MD5.digest(payload)

Finally, the date should be the current timestamp, i.e.

date = Time.now.rfc2822

There might be more issues but this is what I found now. When implementing such a protocol, you have toi make sure to follow the encoding requirements and hash formats exactly. Else, the data will not match. You should try to find an example of a valid request and try to build your implmenetation so that it is able to re-create this exact request.

Holger Just
  • 52,918
  • 14
  • 115
  • 123