9
9
10
10
import pytz
11
11
12
- from .consts import DATE_FORMAT , UNSIGNED_PAYLOAD , LAST_MODIFY_TIME_DATE_FORMAT
12
+ from .consts import DATE_FORMAT , UNSIGNED_PAYLOAD , LAST_MODIFY_TIME_DATE_FORMAT , SIGNATURE_QUERY_LOWER , V4_PREFIX
13
13
from .credential import FederationCredentials , StaticCredentialsProvider
14
14
from .exceptions import TosClientError
15
15
from .models2 import PreSignedPostSignatureOutPut , ContentLengthRange
21
21
def _canonical_query_string_params (params ):
22
22
results = []
23
23
for param in sorted (params ):
24
+ if param .lower () == SIGNATURE_QUERY_LOWER :
25
+ continue
24
26
value = str (params [param ])
25
27
results .append ('%s=%s' % (quote (param , safe = '-_.~' ),
26
28
quote (value , safe = '-_.~' )))
27
29
cqs = '&' .join (results )
28
30
return cqs
29
31
30
32
31
- def _signed_headers (headers ):
32
- hl = sorted (headers .items (), key = lambda d : d [0 ].lower ())
33
- vl = []
34
- for v in hl :
35
- vl .append (v [0 ].lower ())
36
- return ';' .join (vl )
33
+ def _need_signed_headers (key , is_signing_query ):
34
+ return (key == "content-type" and not is_signing_query ) or key .startswith (V4_PREFIX ) or key == 'host'
35
+
36
+
37
+ def _get_signed_headers (headers , is_signing_query = False ):
38
+ signed_headers = {}
39
+ for k , v in headers .items ():
40
+ k = k .lower ()
41
+ if _need_signed_headers (k , is_signing_query ):
42
+ signed_headers [k ] = v
43
+ return sorted (signed_headers .items (), key = lambda d : d [0 ].lower ())
44
+
45
+
46
+ def _get_signed_header_key (signed_headers ):
47
+ return ';' .join ([v [0 ] for v in signed_headers ])
37
48
38
49
39
50
def _canonical_headers (headers ):
40
- hl = sorted (headers .items (), key = lambda d : d [0 ].lower ())
41
51
s = ''
42
- for val in hl :
52
+ for val in headers :
43
53
if isinstance (val [1 ], list ):
44
54
tlist = sorted (val [1 ])
45
55
for v in tlist :
46
- s += val [0 ] + ':' + v + '\n '
56
+ s += val [0 ]. lower () + ':' + v + '\n '
47
57
else :
48
58
s += val [0 ].lower () + ':' + str (val [1 ]) + '\n '
49
59
return s
50
60
51
61
52
- def _canonical_request (req ):
62
+ def _canonical_request (req , signed_headers ):
53
63
cr = [req .method .upper (), quote (req .path , safe = '/~' ), _canonical_query_string_params (req .params ),
54
- _canonical_headers (req . headers ), _signed_headers ( req . headers )]
64
+ _canonical_headers (signed_headers ), _get_signed_header_key ( signed_headers )]
55
65
if req .headers .get ('x-tos-content-sha256' ):
56
66
cr .append (req .headers ['x-tos-content-sha256' ])
57
67
else :
@@ -134,8 +144,9 @@ def sign_request(self, req):
134
144
req .headers ['Date' ] = date
135
145
req .headers ['x-tos-date' ] = date
136
146
137
- signature = self ._make_signature (req = req , date = date )
138
- req .headers ['Authorization' ] = self ._inject_signature_to_request (req , signature , date )
147
+ signed_headers = _get_signed_headers (req .headers )
148
+ signature = self ._make_signature (req = req , date = date , signed_headers = signed_headers )
149
+ req .headers ['Authorization' ] = self ._inject_signature_to_request (signature , date , signed_headers )
139
150
140
151
def sign_url (self , req , expires ):
141
152
if expires is None :
@@ -147,11 +158,11 @@ def sign_url(self, req, expires):
147
158
req .params ['X-Tos-Credential' ] = self ._credential (date )
148
159
req .params ['X-Tos-Date' ] = date
149
160
req .params ['X-Tos-Expires' ] = expires
150
- req .params ['X-Tos-SignedHeaders' ] = _signed_headers (req .headers )
151
-
152
161
if self .credential .get_security_token ():
153
162
req .params ["X-Tos-Security-Token" ] = self .credential .get_security_token ()
154
- req .params ['X-Tos-Signature' ] = self ._make_signature (req = req , date = date )
163
+ signed_headers = _get_signed_headers (req .headers , True )
164
+ req .params ['X-Tos-SignedHeaders' ] = _get_signed_header_key (signed_headers )
165
+ req .params ['X-Tos-Signature' ] = self ._make_signature (req = req , date = date , signed_headers = signed_headers )
155
166
156
167
return req .url + '?' + '&' .join (_param_to_quoted_query (k , v ) for k , v in req .params .items ())
157
168
@@ -190,9 +201,9 @@ def x_tos_post_sign(self, expires: int, conditions: []):
190
201
191
202
return '&' .join (_param_to_quoted_query (k , v ) for k , v in params .items ())
192
203
193
- def _make_signature (self , date , req = None , string_to_sign = None ):
204
+ def _make_signature (self , date , req = None , string_to_sign = None , signed_headers = None ):
194
205
if not string_to_sign :
195
- canonical_request = _canonical_request (req )
206
+ canonical_request = _canonical_request (req , signed_headers )
196
207
logger .debug ("pre-request: canonical_request:\n %s" , canonical_request )
197
208
string_to_sign = self ._string_to_sign (canonical_request , date )
198
209
logger .debug ("pre-request: string_to_sign:\n %s" , string_to_sign )
@@ -209,9 +220,9 @@ def _make_x_tos_policy_signature(self, date, params):
209
220
logger .debug ("pre-request: signature:\n %s" , signature )
210
221
return signature
211
222
212
- def _inject_signature_to_request (self , req , signature , date ):
223
+ def _inject_signature_to_request (self , signature , date , signed_headers ):
213
224
results = ['TOS4-HMAC-SHA256 Credential=%s' % self ._credential (date ),
214
- 'SignedHeaders=%s' % _signed_headers ( req . headers ), 'Signature=%s' % signature ]
225
+ 'SignedHeaders=%s' % _get_signed_header_key ( signed_headers ), 'Signature=%s' % signature ]
215
226
return ', ' .join (results )
216
227
217
228
def _string_to_sign (self , canonical_request , date ):
0 commit comments