def _process_response(self, response, request_time): # type: (PipelineResponse, int) -> AccessToken content = response.context.get( ContentDecodePolicy.CONTEXT_NAME ) or ContentDecodePolicy.deserialize_from_http_generics( response.http_response) if response.http_request.body.get("grant_type") == "refresh_token": if content.get("error") == "invalid_grant": # the request's refresh token is invalid -> evict it from the cache cache_entries = self._cache.find( TokenCache.CredentialType.REFRESH_TOKEN, query={ "secret": response.http_request.body["refresh_token"] }, ) for invalid_token in cache_entries: self._cache.remove_rt(invalid_token) if "refresh_token" in content: # AAD returned a new refresh token -> update the cache entry cache_entries = self._cache.find( TokenCache.CredentialType.REFRESH_TOKEN, query={ "secret": response.http_request.body["refresh_token"] }, ) # If the old token is in multiple cache entries, the cache is in a state we don't # expect or know how to reason about, so we update nothing. if len(cache_entries) == 1: self._cache.update_rt(cache_entries[0], content["refresh_token"]) del content[ "refresh_token"] # prevent caching a redundant entry _raise_for_error(response, content) if "expires_on" in content: expires_on = int(content["expires_on"]) elif "expires_in" in content: expires_on = request_time + int(content["expires_in"]) else: _scrub_secrets(content) raise ClientAuthenticationError( message="Unexpected response from Azure Active Directory: {}". format(content)) token = AccessToken(content["access_token"], expires_on) # caching is the final step because 'add' mutates 'content' self._cache.add( event={ "client_id": self._client_id, "response": content, "scope": response.http_request.body["scope"].split(), "token_endpoint": response.http_request.url, }, now=request_time, ) return token
async def record_wrap(*args, **kwargs): def transform_args(*args, **kwargs): copied_positional_args = list(args) request = copied_positional_args[1] transform_request(request, recording_id) return tuple(copied_positional_args), kwargs trimmed_kwargs = {k: v for k, v in kwargs.items()} trim_kwargs_from_test_function(test_func, trimmed_kwargs) if is_live_and_not_recording(): return await test_func(*args, **trimmed_kwargs) test_id = get_test_id() recording_id, variables = start_record_or_playback(test_id) original_transport_func = AioHttpTransport.send async def combined_call(*args, **kwargs): adjusted_args, adjusted_kwargs = transform_args(*args, **kwargs) result = await original_transport_func(*adjusted_args, **adjusted_kwargs) # make the x-recording-upstream-base-uri the URL of the request # this makes the request look like it was made to the original endpoint instead of to the proxy # without this, things like LROPollers can get broken by polling the wrong endpoint parsed_result = url_parse.urlparse(result.request.url) upstream_uri = url_parse.urlparse(result.request.headers["x-recording-upstream-base-uri"]) upstream_uri_dict = {"scheme": upstream_uri.scheme, "netloc": upstream_uri.netloc} original_target = parsed_result._replace(**upstream_uri_dict).geturl() result.request.url = original_target return result AioHttpTransport.send = combined_call # call the modified function # we define test_output before invoking the test so the variable is defined in case of an exception test_output = None try: try: test_output = await test_func(*args, variables=variables, **trimmed_kwargs) except TypeError: logger = logging.getLogger() logger.info( "This test can't accept variables as input. The test method should accept `**kwargs` and/or a " "`variables` parameter to make use of recorded test variables." ) test_output = await test_func(*args, **trimmed_kwargs) except ResourceNotFoundError as error: error_body = ContentDecodePolicy.deserialize_from_http_generics(error.response) message = error_body.get("message") or error_body.get("Message") error_with_message = ResourceNotFoundError(message=message, response=error.response) raise error_with_message from error finally: AioHttpTransport.send = original_transport_func stop_record_or_playback(test_id, recording_id, test_output) return test_output
def process_batch_error(error): """Raise detailed error message for HttpResponseErrors """ raise_error = HttpResponseError if error.status_code == 401: raise_error = ClientAuthenticationError error_message = error.message error_code = error.status_code error_body = None try: error_body = ContentDecodePolicy.deserialize_from_http_generics( error.response) except DecodeError: pass try: if error_body is not None: error_resp = error_body["error"] if "innerError" in error_resp: error_resp = error_resp["innerError"] error_message = error_resp["message"] error_code = error_resp["code"] error_message += "\nErrorCode:{}".format(error_code) except KeyError: raise HttpResponseError( message="There was an unknown error with the request.") error = raise_error(message=error_message, response=error.response) error.error_code = error_code raise error
def _process_response(self, response, request_time): # type: (PipelineResponse, int) -> AccessToken # ContentDecodePolicy sets this, and should have raised if it couldn't deserialize the response content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) # type: dict if not content: raise ClientAuthenticationError(message="No token received.", response=response.http_response) if "access_token" not in content or not ("expires_in" in content or "expires_on" in content): if content and "access_token" in content: content["access_token"] = "****" raise ClientAuthenticationError( message='Unexpected response "{}"'.format(content), response=response.http_response ) if self._content_callback: self._content_callback(content) expires_on = int(content.get("expires_on") or int(content["expires_in"]) + request_time) content["expires_on"] = expires_on token = AccessToken(content["access_token"], content["expires_on"]) # caching is the final step because TokenCache.add mutates its "event" self._cache.add( event={"response": content, "scope": [content["resource"]]}, now=request_time, ) return token
def obtain_token_by_refresh_token(self, scopes, refresh_token, **kwargs): # type: (Sequence[str], str, **Any) -> AccessToken request = self._get_refresh_token_request(scopes, refresh_token) now = int(time.time()) response = self._pipeline.run(request, stream=False, **kwargs) content = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) return self._process_response(response=content, scopes=scopes, now=now)
async def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs): # type: (Sequence[str], AadClientCertificate, **Any) -> AccessToken request = self._get_client_certificate_request(scopes, certificate) now = int(time.time()) response = await self._pipeline.run(request, stream=False, **kwargs) content = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) return self._process_response(response=content, scopes=scopes, now=now)
async def obtain_token_by_refresh_token(self, scopes: "Sequence[str]", refresh_token: str, **kwargs: "Any") -> "AccessToken": request = self._get_refresh_token_request(scopes, refresh_token) now = int(time.time()) response = await self._pipeline.run(request, **kwargs) content = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) return self._process_response(response=content, scopes=scopes, now=now)
def get_exception_for_key_vault_error(cls, response): # type: (Type[AzureError], HttpResponse) -> AzureError try: body = ContentDecodePolicy.deserialize_from_http_generics(response) message = "({}) {}".format(body["error"]["code"], body["error"]["message"]) except (DecodeError, KeyError): # Key Vault error response bodies have the expected shape and should be deserializable. # If we somehow land here, we'll take HttpResponse's default message. message = None return cls(message=message, response=response)
def on_response(self, request, response): if self._response_callback: data = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) statistics = data.get("statistics", None) model_version = data.get("modelVersion", None) batch_statistics = TextDocumentBatchStatistics._from_generated( statistics) # pylint: disable=protected-access response.statistics = batch_statistics response.model_version = model_version response.raw_response = data self._response_callback(response)
def _get_exception_for_key_vault_error(cls, response): # type: (Type[HttpResponseError], HttpResponse) -> HttpResponseError """Construct cls (HttpResponseError or subclass thereof) with Key Vault's error message.""" try: body = ContentDecodePolicy.deserialize_from_http_generics(response) message = "({}) {}".format( body["error"]["code"], body["error"]["message"]) # type: Optional[str] except (DecodeError, KeyError): # Key Vault error response bodies should have the expected shape and be deserializable. # If we somehow land here, we'll take HttpResponse's default message. message = None return cls(message=message, response=response)
def send(self, request): response_callback = request.context.options.pop("response_hook", self._response_callback) if response_callback: response = self.next.send(request) data = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) statistics = data.get("statistics", None) model_version = data.get("modelVersion", None) batch_statistics = TextDocumentBatchStatistics._from_generated(statistics) # pylint: disable=protected-access response.statistics = batch_statistics response.model_version = model_version response.raw_response = data response_callback(response) return response return self.next.send(request)
async def obtain_token_by_authorization_code( self, scopes: "Sequence[str]", code: str, redirect_uri: str, client_secret: "Optional[str]" = None, **kwargs: "Any") -> "AccessToken": request = self._get_auth_code_request(scopes=scopes, code=code, redirect_uri=redirect_uri, client_secret=client_secret) now = int(time.time()) response = await self._pipeline.run(request, **kwargs) content = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) return self._process_response(response=content, scopes=scopes, now=now)
def obtain_token_by_authorization_code(self, scopes, code, redirect_uri, client_secret=None, **kwargs): # type: (Sequence[str], str, str, Optional[str], **Any) -> AccessToken request = self._get_auth_code_request(scopes=scopes, code=code, redirect_uri=redirect_uri, client_secret=client_secret) now = int(time.time()) response = self._pipeline.run(request, stream=False, **kwargs) content = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) return self._process_response(response=content, scopes=scopes, now=now)
def _decode_proxy_error(response, error_message=None, error_type=None, **kwargs): # pylint: disable=too-many-branches try: error_body = ContentDecodePolicy.deserialize_from_http_generics( response) if isinstance(error_body, dict): # Special case: there was a playback error during test execution (test proxy only) message = error_body.get("Message") if message and message.startswith( "Unable to find a record for the request"): error = ResourceNotFoundError(message=error_message, response=response) error.error_code = 'ResourceNotFoundError' return error except DecodeError: pass return _decode_error(response, error_message, error_type, **kwargs)
async def send(self, request): response_callback = request.context.options.pop( "response_hook", self._response_callback) if response_callback: response = await self.next.send(request) data = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) statistics = data.get("statistics", None) model_version = data.get("modelVersion", None) batch_statistics = RequestStatistics._from_generated(statistics) # pylint: disable=protected-access response.statistics = batch_statistics response.model_version = model_version response.raw_response = data if asyncio.iscoroutine(response_callback): await response_callback(response) else: response_callback(response) return response return await self.next.send(request)
def on_response(self, request, response): if self._is_lro is None: # determine LRO based off of initial response. If 202, we say it's an LRO self._is_lro = response.http_response.status_code == 202 if self._response_callback: data = ContentDecodePolicy.deserialize_from_http_generics( response.http_response) if self._is_lro and (not data or data.get("status") not in _FINISHED): return if data: statistics = data.get("statistics", None) model_version = data.get("modelVersion", None) if statistics or model_version: batch_statistics = TextDocumentBatchStatistics._from_generated( # pylint: disable=protected-access statistics) response.statistics = batch_statistics response.model_version = model_version response.raw_response = data self._response_callback(response)
def process_storage_error(storage_error): # pylint:disable=too-many-statements raise_error = HttpResponseError serialized = False if not storage_error.response: raise storage_error # If it is one of those three then it has been serialized prior by the generated layer. if isinstance(storage_error, (ResourceNotFoundError, ClientAuthenticationError, ResourceExistsError)): serialized = True error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message additional_data = {} error_dict = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics( storage_error.response) # If it is an XML response if isinstance(error_body, Element): error_dict = { child.tag.lower(): child.text for child in error_body } # If it is a JSON response elif isinstance(error_body, dict): error_dict = error_body.get('error', {}) elif not error_code: _LOGGER.warning( 'Unexpected return type % from ContentDecodePolicy.deserialize_from_http_generics.', type(error_body)) error_dict = {'message': str(error_body)} # If we extracted from a Json or XML response if error_dict: error_code = error_dict.get('code') error_message = error_dict.get('message') additional_data = { k: v for k, v in error_dict.items() if k not in {'code', 'message'} } except DecodeError: pass try: # This check would be unnecessary if we have already serialized the error. if error_code and not serialized: error_code = StorageErrorCode(error_code) if error_code in [StorageErrorCode.condition_not_met]: raise_error = ResourceModifiedError if error_code in [ StorageErrorCode.invalid_authentication_info, StorageErrorCode.authentication_failed ]: raise_error = ClientAuthenticationError if error_code in [ StorageErrorCode.resource_not_found, StorageErrorCode.invalid_property_name, StorageErrorCode.invalid_source_uri, StorageErrorCode.source_path_not_found, StorageErrorCode.lease_name_mismatch, StorageErrorCode.file_system_not_found, StorageErrorCode.path_not_found, StorageErrorCode.parent_not_found, StorageErrorCode.invalid_destination_path, StorageErrorCode.invalid_rename_source_path, StorageErrorCode.lease_is_already_broken, StorageErrorCode. invalid_source_or_destination_resource_type, StorageErrorCode.rename_destination_parent_path_not_found ]: raise_error = ResourceNotFoundError if error_code in [ StorageErrorCode.account_already_exists, StorageErrorCode.account_being_created, StorageErrorCode.resource_already_exists, StorageErrorCode.resource_type_mismatch, StorageErrorCode.source_path_is_being_deleted, StorageErrorCode.path_already_exists, StorageErrorCode.destination_path_is_being_deleted, StorageErrorCode.file_system_already_exists, StorageErrorCode.file_system_being_deleted, StorageErrorCode.path_conflict ]: raise_error = ResourceExistsError except ValueError: # Got an unknown error code pass # Error message should include all the error properties try: error_message += "\nErrorCode:{}".format(error_code.value) except AttributeError: error_message += "\nErrorCode:{}".format(error_code) for name, info in additional_data.items(): error_message += "\n{}:{}".format(name, info) # No need to create an instance if it has already been serialized by the generated layer if serialized: storage_error.message = error_message error = storage_error else: error = raise_error(message=error_message, response=storage_error.response) # Ensure these properties are stored in the error instance as well (not just the error message) error.error_code = error_code error.additional_info = additional_data # error.args is what's surfaced on the traceback - show error message in all cases error.args = (error.message, ) try: # `from None` prevents us from double printing the exception (suppresses generated layer error context) exec("raise error from None") # pylint: disable=exec-used # nosec except SyntaxError: raise error
def process_storage_error(storage_error): raise_error = HttpResponseError error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message additional_data = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics( storage_error.response) if error_body: for info in error_body.iter(): if info.tag.lower() == 'code': error_code = info.text elif info.tag.lower() == 'message': error_message = info.text else: additional_data[info.tag] = info.text except DecodeError: pass try: if error_code: error_code = StorageErrorCode(error_code) if error_code in [ StorageErrorCode.condition_not_met, StorageErrorCode.blob_overwritten ]: raise_error = ResourceModifiedError if error_code in [ StorageErrorCode.invalid_authentication_info, StorageErrorCode.authentication_failed ]: raise_error = ClientAuthenticationError if error_code in [ StorageErrorCode.resource_not_found, StorageErrorCode.cannot_verify_copy_source, StorageErrorCode.blob_not_found, StorageErrorCode.queue_not_found, StorageErrorCode.container_not_found, StorageErrorCode.parent_not_found, StorageErrorCode.share_not_found ]: raise_error = ResourceNotFoundError if error_code in [ StorageErrorCode.account_already_exists, StorageErrorCode.account_being_created, StorageErrorCode.resource_already_exists, StorageErrorCode.resource_type_mismatch, StorageErrorCode.blob_already_exists, StorageErrorCode.queue_already_exists, StorageErrorCode.container_already_exists, StorageErrorCode.container_being_deleted, StorageErrorCode.queue_being_deleted, StorageErrorCode.share_already_exists, StorageErrorCode.share_being_deleted ]: raise_error = ResourceExistsError except ValueError: # Got an unknown error code pass try: error_message += "\nErrorCode:{}".format(error_code.value) except AttributeError: error_message += "\nErrorCode:{}".format(error_code) for name, info in additional_data.items(): error_message += "\n{}:{}".format(name, info) error = raise_error(message=error_message, response=storage_error.response) error.error_code = error_code error.additional_info = additional_data raise error
def _process_table_error(storage_error): raise_error = HttpResponseError error_code = storage_error.response.headers.get("x-ms-error-code") error_message = storage_error.message additional_data = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics( storage_error.response) if isinstance(error_body, dict): for info in error_body.get("odata.error", {}): if info == "code": error_code = error_body["odata.error"][info] elif info == "message": error_message = error_body["odata.error"][info]["value"] else: additional_data[info.tag] = info.text else: if error_body: for info in error_body.iter(): if info.tag.lower().find("code") != -1: error_code = info.text elif info.tag.lower().find("message") != -1: error_message = info.text else: additional_data[info.tag] = info.text except DecodeError: pass try: if error_code: error_code = TableErrorCode(error_code) if error_code in [TableErrorCode.condition_not_met]: raise_error = ResourceModifiedError if error_code in [ TableErrorCode.invalid_authentication_info, TableErrorCode.authentication_failed, ]: raise_error = ClientAuthenticationError if error_code in [ TableErrorCode.resource_not_found, TableErrorCode.table_not_found, TableErrorCode.entity_not_found, ResourceNotFoundError, ]: raise_error = ResourceNotFoundError if error_code in [ TableErrorCode.resource_already_exists, TableErrorCode.table_already_exists, TableErrorCode.account_already_exists, TableErrorCode.entity_already_exists, ResourceExistsError, ]: raise_error = ResourceExistsError except ValueError: # Got an unknown error code pass try: error_message += "\nErrorCode:{}".format(error_code.value) except AttributeError: error_message += "\nErrorCode:{}".format(error_code) for name, info in additional_data.items(): error_message += "\n{}:{}".format(name, info) error = raise_error(message=error_message, response=storage_error.response) error.error_code = error_code error.additional_info = additional_data raise error
def _decode_error(response, error_message=None, error_type=None, **kwargs): # pylint: disable=too-many-branches error_code = response.headers.get("x-ms-error-code") additional_data = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics( response) if isinstance(error_body, dict): for info in error_body.get("odata.error", {}): if info == "code": error_code = error_body["odata.error"][info] elif info == "message": error_message = error_body["odata.error"][info]["value"] else: additional_data[info.tag] = info.text else: if error_body: for info in error_body.iter(): if info.tag.lower().find("code") != -1: error_code = info.text elif info.tag.lower().find("message") != -1: error_message = info.text else: additional_data[info.tag] = info.text except DecodeError: pass try: if not error_type: error_code = TableErrorCode(error_code) if error_code in [ TableErrorCode.condition_not_met, TableErrorCode.update_condition_not_satisfied ]: error_type = ResourceModifiedError elif error_code in [ TableErrorCode.invalid_authentication_info, TableErrorCode.authentication_failed, ]: error_type = ClientAuthenticationError elif error_code in [ TableErrorCode.resource_not_found, TableErrorCode.table_not_found, TableErrorCode.entity_not_found, ResourceNotFoundError, ]: error_type = ResourceNotFoundError elif error_code in [ TableErrorCode.resource_already_exists, TableErrorCode.table_already_exists, TableErrorCode.account_already_exists, TableErrorCode.entity_already_exists, ResourceExistsError, ]: error_type = ResourceExistsError else: error_type = HttpResponseError except ValueError: # Got an unknown error code error_type = HttpResponseError try: error_message += "\nErrorCode:{}".format(error_code.value) except AttributeError: error_message += "\nErrorCode:{}".format(error_code) for name, info in additional_data.items(): error_message += "\n{}:{}".format(name, info) error = error_type(message=error_message, response=response, **kwargs) error.error_code = error_code error.additional_info = additional_data return error
def process_storage_error(storage_error): raise_error = HttpResponseError error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message additional_data = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics( storage_error.response) if error_body: for info in error_body: if info == 'code': error_code = error_body[info] elif info == 'message': error_message = error_body[info] else: additional_data[info] = error_body[info] except DecodeError: pass try: if error_code: error_code = StorageErrorCode(error_code) if error_code in [StorageErrorCode.condition_not_met]: raise_error = ResourceModifiedError if error_code in [ StorageErrorCode.invalid_authentication_info, StorageErrorCode.authentication_failed ]: raise_error = ClientAuthenticationError if error_code in [ StorageErrorCode.resource_not_found, StorageErrorCode.invalid_property_name, StorageErrorCode.invalid_source_uri, StorageErrorCode.source_path_not_found, StorageErrorCode.lease_name_mismatch, StorageErrorCode.file_system_not_found, StorageErrorCode.path_not_found, StorageErrorCode.parent_not_found, StorageErrorCode.invalid_destination_path, StorageErrorCode.invalid_rename_source_path, StorageErrorCode.lease_is_already_broken, StorageErrorCode. invalid_source_or_destination_resource_type, StorageErrorCode.rename_destination_parent_path_not_found ]: raise_error = ResourceNotFoundError if error_code in [ StorageErrorCode.account_already_exists, StorageErrorCode.account_being_created, StorageErrorCode.resource_already_exists, StorageErrorCode.resource_type_mismatch, StorageErrorCode.source_path_is_being_deleted, StorageErrorCode.path_already_exists, StorageErrorCode.destination_path_is_being_deleted, StorageErrorCode.file_system_already_exists, StorageErrorCode.file_system_being_deleted, StorageErrorCode.path_conflict ]: raise_error = ResourceExistsError except ValueError: # Got an unknown error code pass try: error_message += "\nErrorCode:{}".format(error_code.value) except AttributeError: error_message += "\nErrorCode:{}".format(error_code) for name, info in additional_data.items(): error_message += "\n{}:{}".format(name, info) error = raise_error(message=error_message, response=storage_error.response, continuation_token=storage_error.continuation_token) error.error_code = error_code error.additional_info = additional_data raise error