2015-02-10 13:31:28 +00:00
from werkzeug . exceptions import HTTPException
from jinja2 import DictLoader , Environment
2022-10-10 13:05:56 +00:00
from typing import Any , Optional
2020-11-05 11:20:18 +00:00
import json
2015-02-10 13:31:28 +00:00
2021-07-26 14:21:17 +00:00
# TODO: add "<Type>Sender</Type>" to error responses below?
2015-02-10 13:31:28 +00:00
2019-10-31 15:44:26 +00:00
SINGLE_ERROR_RESPONSE = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
2016-07-08 19:32:34 +00:00
< Error >
< Code > { { error_type } } < / Code >
< Message > { { message } } < / Message >
{ % block extra % } { % endblock % }
2021-07-26 14:21:17 +00:00
< { { request_id_tag } } > 7 a62c49f - 347e-4 fc4 - 9331 - 6e8 eEXAMPLE < / { { request_id_tag } } >
2016-07-08 19:32:34 +00:00
< / Error >
"""
2021-07-26 14:21:17 +00:00
WRAPPED_SINGLE_ERROR_RESPONSE = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
< ErrorResponse { % if xmlns is defined % } xmlns = " {{ xmlns}} " { % endif % } >
< Error >
< Code > { { error_type } } < / Code >
< Message > { { message } } < / Message >
{ % block extra % } { % endblock % }
< { { request_id_tag } } > 7 a62c49f - 347e-4 fc4 - 9331 - 6e8 eEXAMPLE < / { { request_id_tag } } >
< / Error >
< / ErrorResponse > """
2019-10-31 15:44:26 +00:00
ERROR_RESPONSE = """ <?xml version= " 1.0 " encoding= " UTF-8 " ?>
2019-09-27 18:14:53 +00:00
< ErrorResponse >
2015-02-10 13:31:28 +00:00
< Errors >
< Error >
2016-01-17 23:00:57 +00:00
< Code > { { error_type } } < / Code >
2021-09-23 18:56:22 +00:00
< Message > < ! [ CDATA [ { { message } } ] ] > < / Message >
2015-02-10 13:31:28 +00:00
{ % block extra % } { % endblock % }
< / Error >
< / Errors >
2021-07-26 14:21:17 +00:00
< { { request_id_tag } } > 7 a62c49f - 347e-4 fc4 - 9331 - 6e8 eEXAMPLE < / { { request_id_tag } } >
2019-09-27 18:14:53 +00:00
< / ErrorResponse >
2015-02-10 13:31:28 +00:00
"""
2017-02-24 02:37:43 +00:00
2015-02-10 13:31:28 +00:00
class RESTError ( HTTPException ) :
2017-10-28 19:17:34 +00:00
code = 400
2021-07-26 14:21:17 +00:00
# most APIs use <RequestId>, but some APIs (including EC2, S3) use <RequestID>
request_id_tag_name = " RequestId "
2017-10-28 19:17:34 +00:00
2015-02-10 13:31:28 +00:00
templates = {
2019-10-31 15:44:26 +00:00
" single_error " : SINGLE_ERROR_RESPONSE ,
2021-07-26 14:21:17 +00:00
" wrapped_single_error " : WRAPPED_SINGLE_ERROR_RESPONSE ,
2019-10-31 15:44:26 +00:00
" error " : ERROR_RESPONSE ,
2015-02-10 13:31:28 +00:00
}
2022-10-19 20:56:24 +00:00
def __init__ (
self , error_type : str , message : str , template : str = " error " , * * kwargs : Any
) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ ( )
2016-01-17 23:00:57 +00:00
self . error_type = error_type
self . message = message
2021-11-17 16:19:03 +00:00
if template in self . templates . keys ( ) :
env = Environment ( loader = DictLoader ( self . templates ) )
self . description = env . get_template ( template ) . render (
error_type = error_type ,
message = message ,
request_id_tag = self . request_id_tag_name ,
* * kwargs
)
self . content_type = " application/xml "
2021-07-26 14:21:17 +00:00
2022-03-11 21:28:45 +00:00
def get_headers ( self , * args , * * kwargs ) : # pylint: disable=unused-argument
2021-12-08 15:42:08 +00:00
return {
" X-Amzn-ErrorType " : self . error_type or " UnknownError " ,
" Content-Type " : self . content_type ,
}
2021-07-26 14:21:17 +00:00
2022-03-11 21:28:45 +00:00
def get_body ( self , * args , * * kwargs ) : # pylint: disable=unused-argument
2021-07-26 14:21:17 +00:00
return self . description
2016-01-17 23:00:57 +00:00
2017-02-24 00:43:48 +00:00
class DryRunClientError ( RESTError ) :
2021-09-07 16:10:01 +00:00
code = 412
2017-02-24 00:43:48 +00:00
2016-01-17 23:00:57 +00:00
class JsonRESTError ( RESTError ) :
2022-10-10 13:05:56 +00:00
def __init__ (
self , error_type : str , message : str , template : str = " error_json " , * * kwargs : Any
) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ ( error_type , message , template , * * kwargs )
2021-11-17 16:19:03 +00:00
self . description = json . dumps (
{ " __type " : self . error_type , " message " : self . message }
)
2021-07-26 14:21:17 +00:00
self . content_type = " application/json "
2016-01-17 23:00:57 +00:00
2022-10-06 08:37:35 +00:00
def get_body ( self , * args , * * kwargs ) - > str :
2016-01-17 23:00:57 +00:00
return self . description
2019-07-02 15:40:08 +00:00
class SignatureDoesNotMatchError ( RESTError ) :
2019-07-24 15:21:33 +00:00
code = 403
2019-07-02 15:40:08 +00:00
def __init__ ( self ) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ (
2019-10-31 15:44:26 +00:00
" SignatureDoesNotMatch " ,
" The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. " ,
)
2019-07-02 15:40:08 +00:00
class InvalidClientTokenIdError ( RESTError ) :
2019-07-24 15:21:33 +00:00
code = 403
2019-07-02 15:40:08 +00:00
def __init__ ( self ) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ (
2019-10-31 15:44:26 +00:00
" InvalidClientTokenId " ,
" The security token included in the request is invalid. " ,
)
2019-07-02 15:40:08 +00:00
class AccessDeniedError ( RESTError ) :
code = 403
2019-07-08 17:57:14 +00:00
def __init__ ( self , user_arn , action ) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ (
2019-10-31 15:44:26 +00:00
" AccessDenied " ,
2019-07-08 17:57:14 +00:00
" User: {user_arn} is not authorized to perform: {operation} " . format (
2019-10-31 15:44:26 +00:00
user_arn = user_arn , operation = action
) ,
)
2019-07-08 17:57:14 +00:00
class AuthFailureError ( RESTError ) :
2019-07-24 15:21:33 +00:00
code = 401
2019-07-08 17:57:14 +00:00
def __init__ ( self ) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ (
2019-10-31 15:44:26 +00:00
" AuthFailure " ,
" AWS was not able to validate the provided access credentials " ,
)
2019-09-24 00:16:20 +00:00
2022-03-15 16:42:46 +00:00
class AWSError ( JsonRESTError ) :
2022-10-07 14:41:31 +00:00
TYPE : Optional [ str ] = None
2020-11-05 11:20:18 +00:00
STATUS = 400
2022-10-07 14:41:31 +00:00
def __init__ (
self , message : str , exception_type : str = None , status : Optional [ int ] = None
) :
2022-03-15 16:42:46 +00:00
super ( ) . __init__ ( exception_type or self . TYPE , message )
self . code = status or self . STATUS
2020-11-05 11:20:18 +00:00
2019-09-24 00:16:20 +00:00
class InvalidNextTokenException ( JsonRESTError ) :
""" For AWS Config resource listing. This will be used by many different resource types, and so it is in moto.core. """
2019-10-31 15:44:26 +00:00
2019-09-24 00:16:20 +00:00
code = 400
def __init__ ( self ) :
2021-12-01 23:06:58 +00:00
super ( ) . __init__ (
2019-10-31 15:44:26 +00:00
" InvalidNextTokenException " , " The nextToken provided is invalid "
)
2021-10-09 20:18:13 +00:00
class InvalidToken ( AWSError ) :
2022-03-15 16:42:46 +00:00
code = 400
2021-10-09 20:18:13 +00:00
def __init__ ( self , message = " Invalid token " ) :
2022-03-15 16:42:46 +00:00
super ( ) . __init__ ( " Invalid Token: {} " . format ( message ) , " InvalidToken " )