1717 'sha512' : SHA512 }
1818
1919class Signer (object ):
20- def __init__ (self , secret = '~/.ssh/id_rsa' , algorithm = 'rsa-sha256' ,
21- allow_agent = False ):
20+ def __init__ (self , secret = '~/.ssh/id_rsa' , algorithm = 'rsa-sha256' ):
2221 assert algorithm in ALGORITHMS , "Unknown algorithm"
23- self ._agent_key = False
2422 self ._rsa = False
2523 self ._hash = None
2624 self .sign_algorithm , self .hash_algorithm = algorithm .split ('-' )
27- if allow_agent :
28- try :
29- import paramiko as ssh
30- except ImportError :
31- import ssh
32- keys = ssh .Agent ().get_keys ()
33- self ._keys = filter (is_rsa , keys )
34- if self ._keys :
35- self ._agent_key = self ._keys [0 ]
36- self ._keys = self ._keys [1 :]
37- self .sign_algorithm , self .hash_algorithm = ('rsa' , 'sha1' )
38- if not self ._agent_key and self .sign_algorithm == 'rsa' :
25+ self ._get_key (secret )
26+
27+ @property
28+ def algorithm (self ):
29+ return '%s-%s' % (self .sign_algorithm , self .hash_algorithm )
30+
31+ def _get_key (self , secret ):
32+ if self .sign_algorithm == 'rsa' :
3933 if (secret .startswith ('-----BEGIN RSA PRIVATE KEY-----' ) or
4034 secret .startswith ('-----BEGIN PRIVATE KEY-----' )):
4135 # string with PEM encoded key data
@@ -54,13 +48,7 @@ def __init__(self, secret='~/.ssh/id_rsa', algorithm='rsa-sha256',
5448 elif self .sign_algorithm == 'hmac' :
5549 self ._hash = HMAC .new (secret , digestmod = HASHES [self .hash_algorithm ])
5650
57- @property
58- def algorithm (self ):
59- return '%s-%s' % (self .sign_algorithm , self .hash_algorithm )
60-
61- def sign_agent (self , sign_string ):
62- data = self ._agent_key .sign_ssh_data (None , sign_string )
63- return sig (data )
51+ return ""
6452
6553 def sign_rsa (self , sign_string ):
6654 h = self ._hash .new ()
@@ -72,18 +60,10 @@ def sign_hmac(self, sign_string):
7260 hmac .update (sign_string )
7361 return hmac .digest ()
7462
75- def swap_keys (self ):
76- if self ._keys :
77- self ._agent_key = self ._keys [0 ]
78- self ._keys = self ._keys [1 :]
79- else :
80- self ._agent_key = None
8163
8264 def sign (self , sign_string ):
8365 data = None
84- if self ._agent_key :
85- data = self .sign_agent (sign_string )
86- elif self ._rsa :
66+ if self ._rsa :
8767 data = self .sign_rsa (sign_string )
8868 elif self ._hash :
8969 data = self .sign_hmac (sign_string )
@@ -92,7 +72,40 @@ def sign(self, sign_string):
9272 return base64 .b64encode (data )
9373
9474
95- class HeaderSigner (object ):
75+ class AgentSigner (Signer ):
76+ def __init__ (self , secret = '~/.ssh/id_rsa' , algorithm = 'rsa-sha256' ):
77+ super (AgentSigner , self ).__init__ ()
78+ self ._agent_key = False
79+
80+ def _get_key (self ):
81+ try :
82+ import paramiko as ssh
83+ except ImportError :
84+ import ssh
85+ keys = ssh .Agent ().get_keys ()
86+ self ._keys = filter (is_rsa , keys )
87+ if self ._keys :
88+ self ._agent_key = self ._keys [0 ]
89+ self ._keys = self ._keys [1 :]
90+ self .sign_algorithm , self .hash_algorithm = ('rsa' , 'sha1' )
91+
92+ def swap_keys (self ):
93+ if self ._keys :
94+ self ._agent_key = self ._keys [0 ]
95+ self ._keys = self ._keys [1 :]
96+ else :
97+ self ._agent_key = None
98+
99+ def sign_agent (self , sign_string ):
100+ data = self ._agent_key .sign_ssh_data (None , sign_string )
101+ return sig (data )
102+
103+ def sign (self , sign_string ):
104+ data = self .sign_agent (sign_string )
105+ return base64 .b64encode (data )
106+
107+
108+ class HeaderSigner (Signer ):
96109 '''
97110 Generic object that will sign headers as a dictionary using the http-signature scheme.
98111 https://github.com/joyent/node-http-signature/blob/master/http_signing.md
@@ -103,9 +116,8 @@ class HeaderSigner(object):
103116 headers is a list of http headers to be included in the signing string, defaulting to "Date" alone.
104117 '''
105118 def __init__ (self , key_id = '' , secret = '~/.ssh/id_rsa' ,
106- algorithm = 'rsa-sha256' , headers = None , allow_agent = False ):
107- self .signer = Signer (secret = secret , algorithm = algorithm ,
108- allow_agent = allow_agent )
119+ algorithm = 'rsa-sha256' , headers = None ):
120+ super (HeaderSigner , self ).__init__ (secret = secret , algorithm = algorithm )
109121 self .headers = headers
110122 self .signature_template = self .build_signature_template (
111123 key_id , algorithm , headers )
@@ -138,9 +150,10 @@ def sign_headers(self, headers, host=None, method=None, path=None,
138150 headers is a case-insensitive dict of mutable headers.
139151 host is a override for the 'host' header (defaults to value in headers).
140152 method is the HTTP method (used for 'request-line').
141- pat is the HTTP path (used for 'request-line').
153+ path is the HTTP path (used for 'request-line').
142154 http_version is the HTTP version (used for 'request-line').
143155 """
156+ headers = CaseInsensitiveDict (headers )
144157 if 'date' not in headers :
145158 now = datetime .now ()
146159 stamp = mktime (now .timetuple ())
@@ -170,24 +183,7 @@ def sign_headers(self, headers, host=None, method=None, path=None,
170183
171184 signable_list .append ('%s: %s' % (h .lower (), headers [h ]))
172185 signable = '\n ' .join (signable_list )
173- signature = self .signer . sign (signable )
186+ signature = self .sign (signable )
174187 headers ['Authorization' ] = self .signature_template % signature
175-
176- def sign (self , h , method = None , path = None , http_version = '1.1' ):
177- """
178- Return a dict of headers with the Authorization header added.
179-
180- h is a dict of headers.
181- method is the HTTP method (used for 'request-line').
182- pat is the HTTP path (used for 'request-line').
183- http_version is the HTTP version (used for 'request-line').
184- """
185- # case insensitive copy of headers
186- headers = CaseInsensitiveDict (h )
187- self .sign_headers (
188- headers = headers ,
189- method = method ,
190- path = path ,
191- http_version = http_version
192- )
193188 return headers
189+
0 commit comments