Permalink
Browse files

add generic header dict signer

  • Loading branch information...
1 parent c6c36a6 commit 3a3bbfec5e433059b14b2e0436e3070026ee8406 @atl committed Mar 2, 2012
Showing with 49 additions and 2 deletions.
  1. +1 −1 http_signature/__init__.py
  2. +48 −1 http_signature/sign.py
@@ -1 +1 @@
-from .sign import Signer
+from .sign import Signer, HeaderSigner
View
@@ -1,4 +1,8 @@
+from os.path import expanduser
import base64
+from wsgiref.handlers import format_date_time
+from datetime import datetime
+from time import mktime
from Crypto.Hash import SHA256, SHA, SHA512, HMAC
from Crypto.PublicKey import RSA
@@ -14,7 +18,7 @@ def __init__(self, secret='', algorithm='rsa-sha256'):
assert algorithm in ALGORITHMS, "Unknown algorithm"
self.sign_algorithm, self.hash_algorithm = algorithm.split('-')
if self.sign_algorithm == 'rsa':
- with open(secret) as fh:
+ with open(expanduser(secret)) as fh:
rsa_key = RSA.importKey(fh.read())
self._rsa = PKCS1_v1_5.new(rsa_key)
self._hash = HASHES[self.hash_algorithm]
@@ -39,3 +43,46 @@ def sign(self, sign_string):
data = self.sign_hmac(sign_string)
return base64.b64encode(data)
+
+class HeaderSigner(object):
+ '''
+ Generic object that will sign headers as a dictionary using the http-signature scheme.
+ https://github.com/joyent/node-http-signature/blob/master/http_signing.md
+
+ key_id is the mandatory label indicating to the server which secret to use
+ secret is the filename of a pem file in the case of rsa, a password string in the case of an hmac algorithm
+ algorithm is one of the six specified algorithms
+ headers is a list of http headers to be included in the signing string, defaulting to "Date" alone.
+ '''
+ def __init__(self, key_id='', secret='', algorithm='rsa-sha256', headers=None):
+ self.signer = Signer(secret=secret, algorithm=algorithm)
+ self.algorithm = algorithm
+ self.key_id = key_id
+ self.headers = headers
+ self.signature_string_head = self.build_header_content()
+
+ def build_header_content(self):
+ param_map = {'keyId': self.key_id,
+ 'algorithm': self.algorithm}
+ if self.headers:
+ param_map['headers'] = ' '.join(self.headers)
+ kv = map('{0[0]}="{0[1]}"'.format, param_map.items())
+ kv_string = ','.join(kv)
+ sig_string = 'Signature {0} %s'.format(kv_string)
+ return sig_string
+
+ def sign(self, h):
+ header_dict = h.copy()
+ if 'Date' not in header_dict:
+ now = datetime.now()
+ stamp = mktime(now.timetuple())
+ header_dict['Date'] = format_date_time(stamp)
+ if self.headers:
+ signable_list = [header_dict[x] for x in self.headers]
+ signable = '\n'.join(signable_list)
+ else:
+ signable = header_dict['Date']
+ signature = self.signer.sign(signable)
+ header_dict['Authorization'] = self.signature_string_head % signature
+ return header_dict
+

0 comments on commit 3a3bbfe

Please sign in to comment.