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