Implementing Version 2 of the Amazon AWS HTTP Request Signature in Ruby
This took me a long time to work out this afternoon so I guess it might be useful to others. I couldn’t find an implementation (of version 2 of the request signing) in any of the existing Amazon AWS libraries and although I did find a promising looking post here it just didn’t work for me. I ended up using the Simple DB PHP sample code to obtain some test data1 that I could use to debug my own code2 and eventually got it working.
1 I plan to post some test data (to help others attempting to write a client) in a follow up post.
2 I printed the parameters and signature at various stages of the request so that I could compare it to the output from my client.
require 'rubygems'
require 'cgi'
require 'time'
require 'hmac'
require 'hmac-sha2'
require 'base64'
ACCESS_IDENTIFIER = 'your-access-identifier'
SECRET_IDENTIFIER = 'your-secret-identifier'
AMAZON_ENDPOINT = 'https://sdb.amazonaws.com/'
params = {
'Action' => 'ListDomains',
'AWSAccessKeyId' => ACCESS_IDENTIFIER,
'SignatureMethod' => 'HmacSHA256',
'SignatureVersion' => 2,
'Timestamp' => Time.now.iso8601,
'Version' => '2007-11-07'
}
canonical_querystring = params.sort.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&')
string_to_sign = "GET
sdb.amazonaws.com
/
#{canonical_querystring}"
hmac = HMAC::SHA256.new(SECRET_IDENTIFIER)
hmac.update(string_to_sign)
signature = Base64.encode64(hmac.digest).chomp # chomp is important! the base64 encoded version will have a newline at the end
params['Signature'] = signature
querystring = params.collect { |key, value| [CGI.escape(key.to_s), CGI.escape(value.to_s)].join('=') }.join('&') # order doesn't matter for the actual request
puts `curl -X"GET" "#{AMAZON_ENDPOINT}?#{querystring}" -A"simple ruby aws sdb wrapper"`