On GAE I’m using hmac to produce a signature for an AWS API request. My code was originally this:
import urllib
import urllib2
import time
import hmac
import base64
from hashlib import sha256 as sha256
class AmazonProductAdvertisingAPI:
secret_access_key = '...'
my_hmac = hmac.new(secret_access_key, digestmod=sha256)
def get_signed_url(self, params):
....
# Sign it
self.my_hmac.update('GET' + "\n" + server + "\n" + path + "\n" + paramstring)
urlstring = urlstring + "&Signature=" + \
urllib.quote(base64.encodestring(self.my_hmac.digest()).strip())
return urlstring
With this, I found that the API request (using the URL given by get_signed_url) if and only if the request was a “cold start” for the instance, e.g. after I’d deployed the code and was running it for the first time.
However, subsequent requests failed, with AWS claiming that the signature was invalid. This was resolved by moving my_hmac to within the method, so that it was a variable within the method rather than an instance variable within the class.
...
def get_signed_url(self, params):
my_hmac = hmac.new(self.secret_access_key, digestmod=sha256)
...
I have one question: why?
Your
my_hmacvariable was a class variable; one shared by all instances of the class.This means that for every call to
.get_signed_url()theself.my_hmac.update()call would add data to the digest, across instances, globally to the application.Since you only want to calculate the digest for one string only, (the
"GET ..."string) and not for all strings cumulatively, you must create a newhmacobject for each new digest you want to calculate.Note the documentation for the .update()` method: