开发者

Signing a SimpleDB request

I'm trying to make an API call to Amazon's SimpleDB service with Python. As an example, I开发者_StackOverflow社区'm using the simplest request there is to make, ListDomains. No matter what I try, however, the response is always "The request signature we calculated does not match the signature you provided."

This is the string I'm signing (as per documentation here):

GET
https://sdb.amazonaws.com/
/
AWSAccessKeyId=<redacted>&Action=ListDomains&SignatureMethod=HmacSHA1&SignatureVersion=2&Timestamp=2011-04-19T18%3A50%3A43&Version=2009-04-15

I'm signing it with the following code:

import base64,hashlib,hmac,time                                            
# Sign the request                                                                           
signature = hmac.new(                                                                        
    key=AWS_SECRET_ACCESS_KEY,                                                               
    msg=string_to_sign,                                                                      
    digestmod=hashlib.sha1).digest()                                                         
# Base64 encode the signature                                                                
signature = base64.encodestring( signature )

I've tried it with both HmacSHA256 and HmacSHA1. Nothing seems to work. What am I doing wrong?


A key issue is that you have to properly URL encode all of the HTTP parameter values.

The following documentation has disappeared from the SimpleDB docs, but can be found in the SQS docs and is still very relevant to SimpleDB:

Do not URL encode any of the unreserved characters that RFC 3986 defines.

These unreserved characters are A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ).

Percent encode all other characters with %XY, where X and Y are hex characters 0-9 and uppercase A-F.

Percent encode extended UTF-8 characters in the form %XY%ZA

Percent encode the space character as %20 (and not +, as common encoding schemes do).

You'll notice that in the python-simpledb module, linked by Roger, they follow these rules when forming the request:

def escape(s):
  return urllib.quote(s, safe='-_~')

def urlencode(d):
  if isinstance(d, dict):
    d = d.iteritems()
  return '&'.join(['%s=%s' % (escape(k), escape(v)) for k, v in d])


I wouldn't re-invent the wheel - there are several python simpledb libraries such as;

  • https://github.com/sixapart/python-simpledb
  • http://code.google.com/p/boto/wiki/SimpleDbIntro

If nothing else, their signing code should clarify what your mistake is, but seriously, use an existing maintained API, it will make your life much easier.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜