def get_test_vars(sender=None): if not RestSetup.__test_vars: r = ably.http.post("/apps", headers=HttpUtils.default_post_headers(), body=app_spec_text, skip_auth=True) AblyException.raise_for_response(r) app_spec = r.json() app_id = app_spec.get("appId", "") test_vars = { "app_id": app_id, "host": host, "port": port, "tls_port": tls_port, "tls": tls, "keys": [{ "key_id": "%s.%s" % (app_id, k.get("id", "")), "key_value": k.get("value", ""), "key_str": "%s.%s:%s" % (app_id, k.get("id", ""), k.get("value", "")), "capability": Capability(json.loads(k.get("capability", "{}"))), } for k in app_spec.get("keys", [])] } RestSetup.__test_vars = test_vars log.debug([(app_id, k.get("id", ""), k.get("value", "")) for k in app_spec.get("keys", [])]) return RestSetup.__test_vars
def make_request(self, method, url, headers=None, body=None, skip_auth=False, timeout=None, scheme=None, host=None, port=0): scheme = scheme or self.preferred_scheme host = host or self.preferred_host port = port or self.preferred_port base_url = "%s://%s:%d" % (scheme, host, port) url = urljoin(base_url, url) hdrs = headers or {} headers = HttpUtils.default_get_headers(not self.options.use_text_protocol) headers.update(hdrs) if not skip_auth: headers.update(self.auth._get_auth_headers()) request = requests.Request(method, url, data=body, headers=headers) prepped = self.__session.prepare_request(request) # log.debug("Method: %s" % method) # log.debug("Url: %s" % url) # log.debug("Headers: %s" % headers) # log.debug("Body: %s" % body) # log.debug("Prepped: %s" % prepped) # TODO add timeouts from options here response = self.__session.send(prepped) AblyException.raise_for_response(response) return Response(response)
def make_request(self, method, path, headers=None, body=None, skip_auth=False, timeout=None, raise_on_error=True): if body is not None and type(body) not in (bytes, str): body = self.dump_body(body) if body: all_headers = HttpUtils.default_post_headers( self.options.use_binary_protocol, self.__ably.variant) else: all_headers = HttpUtils.default_get_headers( self.options.use_binary_protocol, self.__ably.variant) if not skip_auth: if self.auth.auth_mechanism == Auth.Method.BASIC and self.preferred_scheme.lower() == 'http': raise AblyException( "Cannot use Basic Auth over non-TLS connections", 401, 40103) all_headers.update(self.auth._get_auth_headers()) if headers: all_headers.update(headers) timeout = (self.http_open_timeout, self.http_request_timeout) http_max_retry_duration = self.http_max_retry_duration requested_at = time.time() hosts = self.get_rest_hosts() for retry_count, host in enumerate(hosts): base_url = "%s://%s:%d" % (self.preferred_scheme, host, self.preferred_port) url = urljoin(base_url, path) request = requests.Request(method, url, data=body, headers=all_headers) prepped = self.__session.prepare_request(request) try: response = self.__session.send(prepped, timeout=timeout) except Exception as e: # Need to catch `Exception`, see: # https://github.com/kennethreitz/requests/issues/1236#issuecomment-133312626 # if last try or cumulative timeout is done, throw exception up time_passed = time.time() - requested_at if retry_count == len(hosts) - 1 or \ time_passed > http_max_retry_duration: raise e else: try: if raise_on_error: AblyException.raise_for_response(response) # Keep fallback host for later (RSC15f) if retry_count > 0 and host != self.options.get_rest_host(): self.__host = host self.__host_expires = time.time() + (self.options.fallback_retry_timeout / 1000.0) return Response(response) except AblyException as e: if not e.is_server_error: raise e
async def token_request_from_auth_url(self, method, url, token_params, headers, auth_params): body = None params = None if method == 'GET': body = {} params = dict(auth_params, **token_params) elif method == 'POST': params = {} body = dict(auth_params, **token_params) from ably.http.http import Response async with httpx.AsyncClient(http2=True) as client: resp = await client.request(method=method, url=url, headers=headers, params=params, data=body) response = Response(resp) AblyException.raise_for_response(response) try: token_request = response.to_native() except ValueError: token_request = response.text return token_request
def make_request(self, method, path, headers=None, body=None, skip_auth=False, timeout=None, raise_on_error=True): if body is not None and type(body) not in (bytes, str): body = self.dump_body(body) if body: all_headers = HttpUtils.default_post_headers( self.options.use_binary_protocol, self.__ably.variant) else: all_headers = HttpUtils.default_get_headers( self.options.use_binary_protocol, self.__ably.variant) if not skip_auth: if self.auth.auth_mechanism == Auth.Method.BASIC and self.preferred_scheme.lower() == 'http': raise AblyException( "Cannot use Basic Auth over non-TLS connections", 401, 40103) all_headers.update(self.auth._get_auth_headers()) if headers: all_headers.update(headers) http_open_timeout = self.http_open_timeout http_request_timeout = self.http_request_timeout http_max_retry_duration = self.http_max_retry_duration requested_at = time.time() hosts = self.options.get_rest_hosts() for retry_count, host in enumerate(hosts): base_url = "%s://%s:%d" % (self.preferred_scheme, host, self.preferred_port) url = urljoin(base_url, path) request = requests.Request(method, url, data=body, headers=all_headers) prepped = self.__session.prepare_request(request) try: timeout = (http_open_timeout, http_request_timeout) response = self.__session.send(prepped, timeout=timeout) except Exception as e: # Need to catch `Exception`, see: # https://github.com/kennethreitz/requests/issues/1236#issuecomment-133312626 # if last try or cumulative timeout is done, throw exception up time_passed = time.time() - requested_at if retry_count == len(hosts) - 1 or \ time_passed > http_max_retry_duration: raise e else: try: if raise_on_error: AblyException.raise_for_response(response) return Response(response) except AblyException as e: if not e.is_server_error: raise e
def create_token_request(self, token_params=None, key_name=None, key_secret=None, query_time=None): token_params = token_params or {} token_request = {} key_name = key_name or self.auth_options.key_name key_secret = key_secret or self.auth_options.key_secret if not key_name or not key_secret: log.debug('key_name or key_secret blank') raise AblyException( "No key specified: no means to generate a token", 401, 40101) token_request['key_name'] = key_name if token_params.get('timestamp'): token_request['timestamp'] = token_params['timestamp'] else: if query_time is None: query_time = self.auth_options.query_time if query_time: token_request['timestamp'] = self.ably.time() else: token_request['timestamp'] = self._timestamp() token_request['timestamp'] = int(token_request['timestamp']) ttl = token_params.get('ttl') if ttl is not None: if isinstance(ttl, timedelta): ttl = ttl.total_seconds() * 1000 token_request['ttl'] = int(ttl) capability = token_params.get('capability') if capability is not None: token_request['capability'] = six.text_type(Capability(capability)) token_request["client_id"] = (token_params.get('client_id') or self.client_id) # Note: There is no expectation that the client # specifies the nonce; this is done by the library # However, this can be overridden by the client # simply for testing purposes token_request["nonce"] = token_params.get( 'nonce') or self._random_nonce() token_request = TokenRequest(**token_request) if token_params.get('mac') is None: # Note: There is no expectation that the client # specifies the mac; this is done by the library # However, this can be overridden by the client # simply for testing purposes. token_request.sign_request(key_secret.encode('utf8')) else: token_request.mac = token_params['mac'] return token_request
def parse_key(self, key): try: key_name, key_secret = key.split(':') return key_name, key_secret except ValueError: raise AblyException("key of not len 2 parameters: {0}" .format(key.split(':')), 401, 40101)
def get_cipher(cipher_params): if cipher_params is None: params = get_default_params() elif isinstance(cipher_params, CipherParams): params = cipher_params else: raise AblyException("ChannelOptions not supported", 400, 40000) return CbcChannelCipher(params)
def __unpad(self, data): padding_size = six.indexbytes(data, -1) if padding_size > len(data): # Too short raise AblyException('invalid-padding', 0, 0) if padding_size == 0: # Missing padding raise AblyException('invalid-padding', 0, 0) for i in range(padding_size): # Invalid padding bytes if padding_size != six.indexbytes(data, -i - 1): raise AblyException('invalid-padding', 0, 0) return data[:-padding_size]
def as_dict(self, binary=False): data = self.data data_type = None encoding = self._encoding_array[:] if isinstance(data, dict) or isinstance(data, list): encoding.append('json') data = json.dumps(data) elif isinstance(data, six.text_type) and not binary: # text_type is always a unicode string pass elif (not binary and isinstance(data, bytearray) or # bytearray is always bytes isinstance(data, six.binary_type) and six.binary_type != str): # in py3k we will understand <class 'bytes'> as bytes data = base64.b64encode(data).decode('ascii') encoding.append('base64') elif isinstance(data, CipherData): encoding.append(data.encoding_str) data_type = data.type if not binary: data = base64.b64encode(data.buffer).decode('ascii') encoding.append('base64') else: data = data.buffer elif binary and isinstance(data, bytearray): data = six.binary_type(data) if not (isinstance(data, (six.binary_type, six.text_type, list, dict, bytearray)) or data is None): raise AblyException("Invalid data payload", 400, 40011) request_body = { 'name': self.name, 'data': data, 'timestamp': self.timestamp or int(time.time() * 1000.0), } request_body = { k: v for (k, v) in request_body.items() if v is not None } # None values aren't included if encoding: request_body['encoding'] = '/'.join(encoding).strip('/') if data_type: request_body['type'] = data_type if self.client_id: request_body['clientId'] = self.client_id if self.id: request_body['id'] = self.id if self.connection_id: request_body['connectionId'] = self.connection_id return request_body
def token_request_from_auth_url(self, method, url, token_params, headers, auth_params): if method == 'GET': body = {} params = dict(auth_params, **token_params) elif method == 'POST': params = {} body = dict(auth_params, **token_params) from ably.http.http import Response response = Response(requests.request( method, url, headers=headers, params=params, data=body)) AblyException.raise_for_response(response) try: token_request = response.to_native() except ValueError: token_request = response.text return token_request
async def get_test_vars(sender=None): if not RestSetup.__test_vars: r = await ably.http.post("/apps", body=app_spec_local, skip_auth=True) AblyException.raise_for_response(r) app_spec = r.json() app_id = app_spec.get("appId", "") test_vars = { "app_id": app_id, "host": host, "port": port, "tls_port": tls_port, "tls": tls, "environment": environment, "keys": [{ "key_name": "%s.%s" % (app_id, k.get("id", "")), "key_secret": k.get("value", ""), "key_str": "%s.%s:%s" % (app_id, k.get("id", ""), k.get("value", "")), "capability": Capability(json.loads(k.get("capability", "{}"))), } for k in app_spec.get("keys", [])] } RestSetup.__test_vars = test_vars log.debug([(app_id, k.get("id", ""), k.get("value", "")) for k in app_spec.get("keys", [])]) return RestSetup.__test_vars
def set_key(self, key): if key is None: return try: key_name, key_secret = key.split(':') self.auth_options['key_name'] = key_name self.auth_options['key_secret'] = key_secret except ValueError: raise AblyException( "key of not len 2 parameters: {0}".format(key.split(':')), 401, 40101)
def as_dict(self, binary=False): data = self.data data_type = None encoding = self._encoding_array[:] if isinstance(data, (dict, list)): encoding.append('json') data = json.dumps(data) data = str(data) elif isinstance(data, str) and not binary: pass elif not binary and isinstance(data, (bytearray, bytes)): data = base64.b64encode(data).decode('ascii') encoding.append('base64') elif isinstance(data, CipherData): encoding.append(data.encoding_str) data_type = data.type if not binary: data = base64.b64encode(data.buffer).decode('ascii') encoding.append('base64') else: data = data.buffer elif binary and isinstance(data, bytearray): data = bytes(data) if not (isinstance(data, (bytes, str, list, dict, bytearray)) or data is None): raise AblyException("Invalid data payload", 400, 40011) request_body = { 'name': self.name, 'data': data, 'timestamp': self.timestamp or None, 'type': data_type or None, 'clientId': self.client_id or None, 'id': self.id or None, 'connectionId': self.connection_id or None, 'connectionKey': self.connection_key or None, 'extras': self.extras, } if encoding: request_body['encoding'] = '/'.join(encoding).strip('/') # None values aren't included request_body = {k: v for k, v in request_body.items() if v is not None} return request_body
def raise_ably_exception(*args, **kwargs): raise AblyException(message="", status_code=500, code=50000)
def time(self, timeout=None): """Returns the current server time in ms since the unix epoch""" r = self.http.get('/time', skip_auth=True, timeout=timeout) AblyException.raise_for_response(r) return r.json()[0]
def time(self, timeout=None): """Returns the current server time in ms since the unix epoch""" r = self.http.get('/time', skip_auth=True, timeout=timeout) AblyException.raise_for_response(r) return r.to_native()[0]
def as_dict(self, binary=False): data = self.data data_type = None encoding = self._encoding_array[:] if isinstance(data, six.binary_type) and six.binary_type == str: # If using python 2, assume str payloads are intended as strings # if they decode to unicode. If it doesn't, treat as a binary try: data = six.text_type(data) except UnicodeDecodeError: pass if isinstance(data, dict) or isinstance(data, list): encoding.append('json') data = json.dumps(data) data = six.text_type(data) elif isinstance(data, six.text_type) and not binary: # text_type is always a unicode string pass elif (not binary and (isinstance(data, bytearray) or # bytearray is always bytes isinstance(data, six.binary_type))): # at this point binary_type is either a py3k bytes or a py2 # str that failed to decode to unicode data = base64.b64encode(data).decode('ascii') encoding.append('base64') elif isinstance(data, CipherData): encoding.append(data.encoding_str) data_type = data.type if not binary: data = base64.b64encode(data.buffer).decode('ascii') encoding.append('base64') else: data = data.buffer elif binary and isinstance(data, bytearray): data = six.binary_type(data) if not (isinstance(data, (six.binary_type, six.text_type, list, dict, bytearray)) or data is None): raise AblyException("Invalid data payload", 400, 40011) request_body = { u'name': self.name, u'data': data, u'timestamp': self.timestamp or int(time.time() * 1000.0), } request_body = { k: v for (k, v) in request_body.items() if v is not None } # None values aren't included if encoding: request_body[u'encoding'] = u'/'.join(encoding).strip(u'/') if data_type: request_body[u'type'] = data_type if self.client_id: request_body[u'clientId'] = self.client_id if self.id: request_body[u'id'] = self.id if self.connection_id: request_body[u'connectionId'] = self.connection_id if self.connection_key: request_body['connectionKey'] = self.connection_key if self.extras: request_body['extras'] = self.extras return request_body
def request_token( self, token_params=None, # auth_options key_name=None, key_secret=None, auth_callback=None, auth_url=None, auth_method=None, auth_headers=None, auth_params=None, query_time=None): token_params = token_params or {} token_params = dict(self.auth_options.default_token_params, **token_params) key_name = key_name or self.auth_options.key_name key_secret = key_secret or self.auth_options.key_secret log.debug("Auth callback: %s" % auth_callback) log.debug("Auth options: %s" % six.text_type(self.auth_options)) if query_time is None: query_time = self.auth_options.query_time query_time = bool(query_time) auth_callback = auth_callback or self.auth_options.auth_callback auth_url = auth_url or self.auth_options.auth_url auth_params = auth_params or self.auth_options.auth_params or {} auth_method = (auth_method or self.auth_options.auth_method).upper() auth_headers = auth_headers or self.auth_options.auth_headers or {} log.debug("Token Params: %s" % token_params) if auth_callback: log.debug("using token auth with authCallback") token_request = auth_callback(token_params) elif auth_url: log.debug("using token auth with authUrl") token_request = self.token_request_from_auth_url( auth_method, auth_url, token_params, auth_headers, auth_params) else: token_request = self.create_token_request(token_params, key_name=key_name, key_secret=key_secret, query_time=query_time) if isinstance(token_request, TokenDetails): return token_request elif isinstance(token_request, dict) and 'issued' in token_request: return TokenDetails.from_dict(token_request) elif isinstance(token_request, dict): token_request = TokenRequest(**token_request) elif isinstance(token_request, six.text_type): return TokenDetails(token=token_request) # python2 elif isinstance(token_request, six.binary_type) and six.binary_type == str: return TokenDetails(token=token_request) token_path = "/keys/%s/requestToken" % token_request.key_name response = self.ably.http.post(token_path, headers=auth_headers, native_data=token_request.to_dict(), skip_auth=True) AblyException.raise_for_response(response) response_dict = response.to_native() log.debug("Token: %s" % str(response_dict.get("token"))) return TokenDetails.from_dict(response_dict)
def request_token(self, token_params=None, # auth_options key_name=None, key_secret=None, auth_callback=None, auth_url=None, auth_method=None, auth_headers=None, auth_params=None, query_time=None): token_params = token_params or {} token_params = dict(self.auth_options.default_token_params, **token_params) key_name = key_name or self.auth_options.key_name key_secret = key_secret or self.auth_options.key_secret log.debug("Auth callback: %s" % auth_callback) log.debug("Auth options: %s" % six.text_type(self.auth_options)) if query_time is None: query_time = self.auth_options.query_time query_time = bool(query_time) auth_callback = auth_callback or self.auth_options.auth_callback auth_url = auth_url or self.auth_options.auth_url auth_params = auth_params or self.auth_options.auth_params or {} auth_method = (auth_method or self.auth_options.auth_method).upper() auth_headers = auth_headers or self.auth_options.auth_headers or {} log.debug("Token Params: %s" % token_params) if auth_callback: log.debug("using token auth with authCallback") token_request = auth_callback(token_params) elif auth_url: log.debug("using token auth with authUrl") token_request = self.token_request_from_auth_url( auth_method, auth_url, token_params, auth_headers, auth_params) else: token_request = self.create_token_request( token_params, key_name=key_name, key_secret=key_secret, query_time=query_time) if isinstance(token_request, TokenDetails): return token_request elif isinstance(token_request, dict) and 'issued' in token_request: return TokenDetails.from_dict(token_request) elif isinstance(token_request, dict): token_request = TokenRequest(**token_request) elif isinstance(token_request, six.text_type): return TokenDetails(token=token_request) # python2 elif isinstance(token_request, six.binary_type) and six.binary_type == str: return TokenDetails(token=token_request) token_path = "/keys/%s/requestToken" % token_request.key_name response = self.ably.http.post( token_path, headers=auth_headers, native_data=token_request.to_dict(), skip_auth=True ) AblyException.raise_for_response(response) response_dict = response.to_native() log.debug("Token: %s" % str(response_dict.get("token"))) return TokenDetails.from_dict(response_dict)
def make_request(self, method, path, headers=None, body=None, native_data=None, skip_auth=False, timeout=None): fallback_hosts = Defaults.get_fallback_rest_hosts(self.__options) if fallback_hosts: fallback_hosts.insert(0, self.preferred_host) fallback_hosts = itertools.cycle(fallback_hosts) if native_data is not None and body is not None: raise ValueError("make_request takes either body or native_data") elif native_data is not None: body = self.dump_body(native_data) if body: all_headers = HttpUtils.default_post_headers( self.options.use_binary_protocol) else: all_headers = HttpUtils.default_get_headers( self.options.use_binary_protocol) if not skip_auth: if self.auth.auth_mechanism == Auth.Method.BASIC and self.preferred_scheme.lower() == 'http': raise AblyException( "Cannot use Basic Auth over non-TLS connections", 401, 40103) all_headers.update(self.auth._get_auth_headers()) if headers: all_headers.update(headers) http_open_timeout = self.http_open_timeout http_request_timeout = self.http_request_timeout if fallback_hosts: http_max_retry_count = self.http_max_retry_count else: http_max_retry_count = 1 http_max_retry_duration = self.http_max_retry_duration requested_at = time.time() for retry_count in range(http_max_retry_count): host = next(fallback_hosts) if fallback_hosts else self.preferred_host if self.options.environment: host = self.options.environment + '-' + host base_url = "%s://%s:%d" % (self.preferred_scheme, host, self.preferred_port) url = urljoin(base_url, path) request = requests.Request(method, url, data=body, headers=all_headers) prepped = self.__session.prepare_request(request) try: response = self.__session.send( prepped, timeout=(http_open_timeout, http_request_timeout)) except Exception as e: # Need to catch `Exception`, see: # https://github.com/kennethreitz/requests/issues/1236#issuecomment-133312626 # if last try or cumulative timeout is done, throw exception up time_passed = time.time() - requested_at if retry_count == http_max_retry_count - 1 or \ time_passed > http_max_retry_duration: raise e else: try: AblyException.raise_for_response(response) return Response(response) except AblyException as e: if not e.is_server_error: raise e
def request_token(self, key_id=None, key_value=None, query_time=None, auth_token=None, auth_callback=None, auth_url=None, auth_headers=None, auth_params=None, token_params=None): key_id = key_id or self.auth_options.key_id key_value = key_value or self.auth_options.key_value log.debug("Auth callback: %s" % auth_callback) log.debug("Auth options: %s" % six.text_type(self.auth_options)) query_time = bool(query_time) auth_token = auth_token or self.auth_options.auth_token auth_callback = auth_callback or self.auth_options.auth_callback auth_url = auth_url or self.auth_options.auth_url auth_headers = auth_headers or { "Content-Encoding": "utf-8", "Content-Type": "application/json", } auth_params = auth_params or self.auth_params token_params = token_params or {} token_params.setdefault("client_id", self.ably.client_id) signed_token_request = "" log.debug("Token Params: %s" % token_params) if auth_callback: log.debug("using token auth with authCallback") signed_token_request = auth_callback(**token_params) elif auth_url: log.debug("using token auth with authUrl") response = self.ably.http.post( auth_url, headers=auth_headers, body=json.dumps(token_params), skip_auth=True ) AblyException.raise_for_response(response) signed_token_request = response.text elif key_value: log.debug("using token auth with client-side signing") signed_token_request = self.create_token_request( key_id=key_id, key_value=key_value, query_time=query_time, token_params=token_params) else: log.debug('No auth_callback, auth_url or key_value specified') raise AblyException( "Auth.request_token() must include valid auth parameters", 400, 40000) token_path = "/keys/%s/requestToken" % key_id response = self.ably.http.post( token_path, headers=auth_headers, body=signed_token_request, skip_auth=True ) AblyException.raise_for_response(response) access_token = response.json()["access_token"] log.debug("Token: %s" % str(access_token)) return TokenDetails.from_dict(access_token)
async def make_request(self, method, path, headers=None, body=None, skip_auth=False, timeout=None, raise_on_error=True): if body is not None and type(body) not in (bytes, str): body = self.dump_body(body) if body: all_headers = HttpUtils.default_post_headers( self.options.use_binary_protocol) else: all_headers = HttpUtils.default_get_headers( self.options.use_binary_protocol) if not skip_auth: if self.auth.auth_mechanism == Auth.Method.BASIC and self.preferred_scheme.lower( ) == 'http': raise AblyException( "Cannot use Basic Auth over non-TLS connections", 401, 40103) auth_headers = await self.auth._get_auth_headers() all_headers.update(auth_headers) if headers: all_headers.update(headers) timeout = (self.http_open_timeout, self.http_request_timeout) http_max_retry_duration = self.http_max_retry_duration requested_at = time.time() hosts = self.get_rest_hosts() for retry_count, host in enumerate(hosts): base_url = "%s://%s:%d" % (self.preferred_scheme, host, self.preferred_port) url = urljoin(base_url, path) request = self.__client.build_request( method=method, url=url, content=body, headers=all_headers, timeout=timeout, ) try: response = await self.__client.send(request) except Exception as e: # if last try or cumulative timeout is done, throw exception up time_passed = time.time() - requested_at if retry_count == len( hosts) - 1 or time_passed > http_max_retry_duration: raise e else: try: if raise_on_error: AblyException.raise_for_response(response) # Keep fallback host for later (RSC15f) if retry_count > 0 and host != self.options.get_rest_host( ): self.__host = host self.__host_expires = time.time() + ( self.options.fallback_retry_timeout / 1000.0) return Response(response) except AblyException as e: if not e.is_server_error: raise e # if last try or cumulative timeout is done, throw exception up time_passed = time.time() - requested_at if retry_count == len( hosts ) - 1 or time_passed > http_max_retry_duration: raise e