public
Last active

A basic utility class written in Python that verifies an Amazon Simple Payments return url or IPN url using VerifySignature from the FPS API

  • Download Gist
AmazonSignatureUtil.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
import base64
import hmac
import hashlib
import urllib
import urllib2
import time
from datetime import datetime, tzinfo
from xml.dom import minidom
 
 
def upcase_compare(left, right):
left = left.upper()
right = right.upper()
if(left < right):
return -1
elif(left > right):
return 1
return 0
 
 
class AmazonSignatureUtil:
"""
This class performs the seemingly simple task of verifying a signature
passed to the return url or IPN url from an Amazon Simple Payments button.
It calls VerifySignature from the FPS (Flexible Payments Service) API.
 
You will need:
An AWS account access key and secret.
 
Usage:
sig_util = AmazonSignatureUtil('YOUR_ACCESS_KEY','YOUR_SECRET_KEY')
sig_util.verify('http://example.com/success', {'params':'here'})
"""
fps_sandbox_endpoint = 'https://fps.sandbox.amazonaws.com/'
fps_prod_endpoint = 'https://fps.amazonaws.com/'
aws_access_key = ''
aws_secret_access_key = ''
use_sandbox = True
 
def __init__(self, access_key, secret_key, use_sandbox=True):
self.aws_access_key = access_key
self.aws_secret_access_key = secret_key
self.use_sandbox = bool(use_sandbox)
 
def verify(self, url_endpoint, params):
"""
Performs an API request to VerifySignature passing along the
parameters received from an Amazon Payment button.
 
url_endpoint is the full return url you provided when you made your
button. E.g. http://example.com/success
 
params is a dict containing all the parameters that were passed back
to your application, including the signature you wish to verify.
"""
params = urllib.urlencode(params)
 
values = {
'Action': 'VerifySignature',
'UrlEndPoint': url_endpoint,
'HttpParameters': params,
'AWSAccessKeyId': self.aws_access_key,
'SignatureVersion': 2,
'SignatureMethod': 'HmacSHA256',
'Timestamp': time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
'Version': '2008-09-17',
}
 
data = self.get_signed_query(values)
 
if self.use_sandbox == True:
req = urllib2.Request(self.fps_sandbox_endpoint + '?%s' % data)
else:
req = urllib2.Request(self.fps_prod_endpoint + '?%s' % data)
 
try:
response = urllib2.urlopen(req)
result = minidom.parseString(response.read())
 
# parse response
verify_sig_response = result.getElementsByTagName('VerifySignatureResponse')[0]
verify_sig_result = verify_sig_response.getElementsByTagName('VerifySignatureResult')[0]
verify_status = verify_sig_result.getElementsByTagName('VerificationStatus')[0]
 
if 'Success' == verify_status.childNodes[0].data:
return True
else:
return False
 
except urllib2.HTTPError:
# error response, no signature match
return False
 
def sign_string(self, string):
"""
Strings going to and from the Amazon FPS service must be cryptographically
signed to validate the identity of the caller.
 
Sign the given string with the aws_secret_access_key using the SHA1 algorithm,
Base64 encode the result and strip whitespace.
 
NOTE: this was borrowed from the FyPS class
"""
sig = base64.encodestring(hmac.new(self.aws_secret_access_key,
string, hashlib.sha256)
.digest()).strip()
return(sig)
 
def get_signed_query(self, parameters, signature_name='Signature'):
"""
Returns a signed query string ready for use against the FPS REST
interface. Encodes the given parameters and adds a signature
parameter.
 
NOTE: this was borrowed from the FyPS class
"""
keys = parameters.keys()
keys.sort(upcase_compare)
message = ''
for k in keys:
message += "%s%s" % (k, parameters[k])
sig = self.sign_string(message)
 
parameters[signature_name] = sig
return urllib.urlencode(parameters)

Note that this gist is for Signature Version 1 which is no longer supported by Amazon.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.