def string_to_sign(self, request): """ Return the canonical StringToSign as well as a dict containing the original version of all headers that were included in the StringToSign. """ headers_to_sign = self.headers_to_sign(request.headers) canonical_headers = self.canonical_headers(headers_to_sign) string_to_sign = b'\n'.join([ utf8(request.method.upper()), utf8(request.uri), utf8(canonical_headers), utf8(request.body) ]) return string_to_sign
def test_delete(self): client = APIClient(self.access_key, self.secret_key, self.api_server) req = APIRequest(client, self.endpoint, self.version) r = req.delete('/resource') logger.debug(r.content) self.assertEqual(r.status_code, 200) self.assertEqual(r.content, utf8('delete'))
def check_response(self, sign_response, request, response): # 不需要检查返回的签名就直接返回 if not sign_response: return True # logger.debug(response.headers) try: timestamp = int(response.headers.get(HEADER_X_TIMESTAMP)) except ValueError: logger.debug('Invalid X-Api-Timestamp Header') return False now_ts = int(time.time()) if abs(timestamp - now_ts) > self.client.signature_expire_seconds: logger.debug('Expired signature, timestamp: %s' % timestamp) return False signature = response.headers.get(HEADER_X_SIGNATURE) if signature: del response.headers[HEADER_X_SIGNATURE] else: logger.debug('No signature provide') return False string_to_sign = self.response_string_to_sign(request, response) # 如果不是 unicode 输出会引发异常 # logger.debug('string_to_sign: %s' % string_to_sign.decode('utf-8')) # hash_value = sha1(utf8(string_to_sign)).hexdigest() real_signature = self.sign_string(utf8(string_to_sign)) if signature != real_signature: logger.debug('Signature not match: %s, %s' % (signature, real_signature)) return False else: return True
def _do_fetch(self, method, uri, params=None, headers=None, data=None, json=None, access_token=None, **kwargs): url = self.prepare_request(method, uri, params=params, data=data, json=json, headers=headers, access_token=access_token) if self.encrypt_type == 'aes': url = self.encrypt_data() self.request_data.headers.update(self.get_auth_headers()) # 需要对请求的内容进行 hmac 签名 if self.require_hmac: signature = self.hmac_handler.signature_request(self.request_data) self.request_data.headers[HEADER_X_SIGNATURE] = signature if method in ['get', 'head', 'options', 'delete']: func = getattr(requests, method) r = func(url, headers=self.request_data.headers, **kwargs) elif method in ['post', 'put']: func = getattr(requests, method) r = func(url, headers=self.request_data.headers, data=utf8(self.request_data.body), **kwargs) else: raise ValueError('method not allowed') if r.status_code != GATEWAY_ERROR_STATUS_CODE: is_valid = self.hmac_handler.check_response( self.sign_response, self.request_data, r) if not is_valid: logger.debug('返回结果签名不正确') r_encrypt_type = r.headers.get(HEADER_X_ENCRYPT_TYPE, 'raw') if r_encrypt_type == 'aes': r._content = self.decrypt_data(r.content) return r
def decrypt_data(self, body): try: aes_cipher = AESCipher(self.secret_key) if body and len(body) > 0: logger.debug('解密 body') body = aes_cipher.decrypt(utf8(body)) # logger.debug(body.decode('hex')) except Exception as e: logger.error('解密数据出错') logger.error(e) logger.error(traceback.format_exc()) return None # 由于 requests 的 content 不是 unicode 类型, 为了兼容, 这里改成 utf8 if isinstance(body, text_type): body = body.encode('utf-8') return body
def sign_string(self, string_to_sign): logger.debug(string_to_sign) new_hmac = hmac.new(utf8(self.client.secret_key), utf8(string_to_sign), digestmod=self.algorithm) return to_unicode(urlsafe_b64encode(new_hmac.digest()).rstrip(b'='))
def signature_request(self, request): signature = self.sign_string(utf8(self.string_to_sign(request))) logger.debug('signature: %s' % signature) return signature