1""" 
    2oauthlib.oauth2.rfc6749.errors 
    3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    4 
    5Error used both by OAuth 2 clients and providers to represent the spec 
    6defined error responses for all four core grant types. 
    7""" 
    8import json 
    9import inspect 
    10import sys 
    11 
    12from oauthlib.common import add_params_to_uri, urlencode 
    13 
    14 
    15class OAuth2Error(Exception): 
    16    error = None 
    17    status_code = 400 
    18    description = '' 
    19 
    20    def __init__(self, description=None, uri=None, state=None, 
    21                 status_code=None, request=None): 
    22        """ 
    23        :param description: A human-readable ASCII [USASCII] text providing 
    24                            additional information, used to assist the client 
    25                            developer in understanding the error that occurred. 
    26                            Values for the "error_description" parameter 
    27                            MUST NOT include characters outside the set 
    28                            x20-21 / x23-5B / x5D-7E. 
    29 
    30        :param uri: A URI identifying a human-readable web page with information 
    31                    about the error, used to provide the client developer with 
    32                    additional information about the error.  Values for the 
    33                    "error_uri" parameter MUST conform to the URI- Reference 
    34                    syntax, and thus MUST NOT include characters outside the set 
    35                    x21 / x23-5B / x5D-7E. 
    36 
    37        :param state: A CSRF protection value received from the client. 
    38 
    39        :param status_code: 
    40 
    41        :param request: OAuthlib request. 
    42        :type request: oauthlib.common.Request 
    43        """ 
    44        if description is not None: 
    45            self.description = description 
    46 
    47        message = '({}) {}'.format(self.error, self.description) 
    48        if request: 
    49            message += ' ' + repr(request) 
    50        super().__init__(message) 
    51 
    52        self.uri = uri 
    53        self.state = state 
    54 
    55        if status_code: 
    56            self.status_code = status_code 
    57 
    58        if request: 
    59            self.redirect_uri = request.redirect_uri 
    60            self.client_id = request.client_id 
    61            self.scopes = request.scopes 
    62            self.response_type = request.response_type 
    63            self.response_mode = request.response_mode 
    64            self.grant_type = request.grant_type 
    65            if state is None: 
    66                self.state = request.state 
    67        else: 
    68            self.redirect_uri = None 
    69            self.client_id = None 
    70            self.scopes = None 
    71            self.response_type = None 
    72            self.response_mode = None 
    73            self.grant_type = None 
    74 
    75    def in_uri(self, uri): 
    76        fragment = self.response_mode == "fragment" 
    77        return add_params_to_uri(uri, self.twotuples, fragment) 
    78 
    79    @property 
    80    def twotuples(self): 
    81        error = [('error', self.error)] 
    82        if self.description: 
    83            error.append(('error_description', self.description)) 
    84        if self.uri: 
    85            error.append(('error_uri', self.uri)) 
    86        if self.state: 
    87            error.append(('state', self.state)) 
    88        return error 
    89 
    90    @property 
    91    def urlencoded(self): 
    92        return urlencode(self.twotuples) 
    93 
    94    @property 
    95    def json(self): 
    96        return json.dumps(dict(self.twotuples)) 
    97 
    98    @property 
    99    def headers(self): 
    100        if self.status_code == 401: 
    101            """ 
    102            https://tools.ietf.org/html/rfc6750#section-3 
    103 
    104            All challenges defined by this specification MUST use the auth-scheme 
    105            value "Bearer".  This scheme MUST be followed by one or more 
    106            auth-param values. 
    107            """ 
    108            authvalues = ['error="{}"'.format(self.error)] 
    109            if self.description: 
    110                authvalues.append('error_description="{}"'.format(self.description)) 
    111            if self.uri: 
    112                authvalues.append('error_uri="{}"'.format(self.uri)) 
    113            return {"WWW-Authenticate": "Bearer " + ", ".join(authvalues)} 
    114        return {} 
    115 
    116 
    117class TokenExpiredError(OAuth2Error): 
    118    error = 'token_expired' 
    119 
    120 
    121class InsecureTransportError(OAuth2Error): 
    122    error = 'insecure_transport' 
    123    description = 'OAuth 2 MUST utilize https.' 
    124 
    125 
    126class MismatchingStateError(OAuth2Error): 
    127    error = 'mismatching_state' 
    128    description = 'CSRF Warning! State not equal in request and response.' 
    129 
    130 
    131class MissingCodeError(OAuth2Error): 
    132    error = 'missing_code' 
    133 
    134 
    135class MissingTokenError(OAuth2Error): 
    136    error = 'missing_token' 
    137 
    138 
    139class MissingTokenTypeError(OAuth2Error): 
    140    error = 'missing_token_type' 
    141 
    142 
    143class FatalClientError(OAuth2Error): 
    144    """ 
    145    Errors during authorization where user should not be redirected back. 
    146 
    147    If the request fails due to a missing, invalid, or mismatching 
    148    redirection URI, or if the client identifier is missing or invalid, 
    149    the authorization server SHOULD inform the resource owner of the 
    150    error and MUST NOT automatically redirect the user-agent to the 
    151    invalid redirection URI. 
    152 
    153    Instead the user should be informed of the error by the provider itself. 
    154    """ 
    155 
    156 
    157class InvalidRequestFatalError(FatalClientError): 
    158    """ 
    159    For fatal errors, the request is missing a required parameter, includes 
    160    an invalid parameter value, includes a parameter more than once, or is 
    161    otherwise malformed. 
    162    """ 
    163    error = 'invalid_request' 
    164 
    165 
    166class InvalidRedirectURIError(InvalidRequestFatalError): 
    167    description = 'Invalid redirect URI.' 
    168 
    169 
    170class MissingRedirectURIError(InvalidRequestFatalError): 
    171    description = 'Missing redirect URI.' 
    172 
    173 
    174class MismatchingRedirectURIError(InvalidRequestFatalError): 
    175    description = 'Mismatching redirect URI.' 
    176 
    177 
    178class InvalidClientIdError(InvalidRequestFatalError): 
    179    description = 'Invalid client_id parameter value.' 
    180 
    181 
    182class MissingClientIdError(InvalidRequestFatalError): 
    183    description = 'Missing client_id parameter.' 
    184 
    185 
    186class InvalidRequestError(OAuth2Error): 
    187    """ 
    188    The request is missing a required parameter, includes an invalid 
    189    parameter value, includes a parameter more than once, or is 
    190    otherwise malformed. 
    191    """ 
    192    error = 'invalid_request' 
    193 
    194 
    195class MissingResponseTypeError(InvalidRequestError): 
    196    description = 'Missing response_type parameter.' 
    197 
    198 
    199class MissingCodeChallengeError(InvalidRequestError): 
    200    """ 
    201    If the server requires Proof Key for Code Exchange (PKCE) by OAuth 
    202    public clients and the client does not send the "code_challenge" in 
    203    the request, the authorization endpoint MUST return the authorization 
    204    error response with the "error" value set to "invalid_request".  The 
    205    "error_description" or the response of "error_uri" SHOULD explain the 
    206    nature of error, e.g., code challenge required. 
    207    """ 
    208    description = 'Code challenge required.' 
    209 
    210 
    211class MissingCodeVerifierError(InvalidRequestError): 
    212    """ 
    213    The request to the token endpoint, when PKCE is enabled, has 
    214    the parameter `code_verifier` REQUIRED. 
    215    """ 
    216    description = 'Code verifier required.' 
    217 
    218 
    219class AccessDeniedError(OAuth2Error): 
    220    """ 
    221    The resource owner or authorization server denied the request. 
    222    """ 
    223    error = 'access_denied' 
    224 
    225 
    226class UnsupportedResponseTypeError(OAuth2Error): 
    227    """ 
    228    The authorization server does not support obtaining an authorization 
    229    code using this method. 
    230    """ 
    231    error = 'unsupported_response_type' 
    232 
    233 
    234class UnsupportedCodeChallengeMethodError(InvalidRequestError): 
    235    """ 
    236    If the server supporting PKCE does not support the requested 
    237    transformation, the authorization endpoint MUST return the 
    238    authorization error response with "error" value set to 
    239    "invalid_request".  The "error_description" or the response of 
    240    "error_uri" SHOULD explain the nature of error, e.g., transform 
    241    algorithm not supported. 
    242    """ 
    243    description = 'Transform algorithm not supported.' 
    244 
    245 
    246class InvalidScopeError(OAuth2Error): 
    247    """ 
    248    The requested scope is invalid, unknown, or malformed, or 
    249    exceeds the scope granted by the resource owner. 
    250 
    251    https://tools.ietf.org/html/rfc6749#section-5.2 
    252    """ 
    253    error = 'invalid_scope' 
    254 
    255 
    256class ServerError(OAuth2Error): 
    257    """ 
    258    The authorization server encountered an unexpected condition that 
    259    prevented it from fulfilling the request.  (This error code is needed 
    260    because a 500 Internal Server Error HTTP status code cannot be returned 
    261    to the client via a HTTP redirect.) 
    262    """ 
    263    error = 'server_error' 
    264 
    265 
    266class TemporarilyUnavailableError(OAuth2Error): 
    267    """ 
    268    The authorization server is currently unable to handle the request 
    269    due to a temporary overloading or maintenance of the server. 
    270    (This error code is needed because a 503 Service Unavailable HTTP 
    271    status code cannot be returned to the client via a HTTP redirect.) 
    272    """ 
    273    error = 'temporarily_unavailable' 
    274 
    275 
    276class InvalidClientError(FatalClientError): 
    277    """ 
    278    Client authentication failed (e.g. unknown client, no client 
    279    authentication included, or unsupported authentication method). 
    280    The authorization server MAY return an HTTP 401 (Unauthorized) status 
    281    code to indicate which HTTP authentication schemes are supported. 
    282    If the client attempted to authenticate via the "Authorization" request 
    283    header field, the authorization server MUST respond with an 
    284    HTTP 401 (Unauthorized) status code, and include the "WWW-Authenticate" 
    285    response header field matching the authentication scheme used by the 
    286    client. 
    287    """ 
    288    error = 'invalid_client' 
    289    status_code = 401 
    290 
    291 
    292class InvalidGrantError(OAuth2Error): 
    293    """ 
    294    The provided authorization grant (e.g. authorization code, resource 
    295    owner credentials) or refresh token is invalid, expired, revoked, does 
    296    not match the redirection URI used in the authorization request, or was 
    297    issued to another client. 
    298 
    299    https://tools.ietf.org/html/rfc6749#section-5.2 
    300    """ 
    301    error = 'invalid_grant' 
    302    status_code = 400 
    303 
    304 
    305class UnauthorizedClientError(OAuth2Error): 
    306    """ 
    307    The authenticated client is not authorized to use this authorization 
    308    grant type. 
    309    """ 
    310    error = 'unauthorized_client' 
    311 
    312 
    313class UnsupportedGrantTypeError(OAuth2Error): 
    314    """ 
    315    The authorization grant type is not supported by the authorization 
    316    server. 
    317    """ 
    318    error = 'unsupported_grant_type' 
    319 
    320 
    321class UnsupportedTokenTypeError(OAuth2Error): 
    322    """ 
    323    The authorization server does not support the hint of the 
    324    presented token type.  I.e. the client tried to revoke an access token 
    325    on a server not supporting this feature. 
    326    """ 
    327    error = 'unsupported_token_type' 
    328 
    329 
    330class InvalidTokenError(OAuth2Error): 
    331    """ 
    332    The access token provided is expired, revoked, malformed, or 
    333    invalid for other reasons.  The resource SHOULD respond with 
    334    the HTTP 401 (Unauthorized) status code.  The client MAY 
    335    request a new access token and retry the protected resource 
    336    request. 
    337    """ 
    338    error = 'invalid_token' 
    339    status_code = 401 
    340    description = ("The access token provided is expired, revoked, malformed, " 
    341                   "or invalid for other reasons.") 
    342 
    343 
    344class InsufficientScopeError(OAuth2Error): 
    345    """ 
    346    The request requires higher privileges than provided by the 
    347    access token.  The resource server SHOULD respond with the HTTP 
    348    403 (Forbidden) status code and MAY include the "scope" 
    349    attribute with the scope necessary to access the protected 
    350    resource. 
    351    """ 
    352    error = 'insufficient_scope' 
    353    status_code = 403 
    354    description = ("The request requires higher privileges than provided by " 
    355                   "the access token.") 
    356 
    357 
    358class ConsentRequired(OAuth2Error): 
    359    """ 
    360    The Authorization Server requires End-User consent. 
    361 
    362    This error MAY be returned when the prompt parameter value in the 
    363    Authentication Request is none, but the Authentication Request cannot be 
    364    completed without displaying a user interface for End-User consent. 
    365    """ 
    366    error = 'consent_required' 
    367 
    368 
    369class LoginRequired(OAuth2Error): 
    370    """ 
    371    The Authorization Server requires End-User authentication. 
    372 
    373    This error MAY be returned when the prompt parameter value in the 
    374    Authentication Request is none, but the Authentication Request cannot be 
    375    completed without displaying a user interface for End-User authentication. 
    376    """ 
    377    error = 'login_required' 
    378 
    379 
    380class CustomOAuth2Error(OAuth2Error): 
    381    """ 
    382    This error is a placeholder for all custom errors not described by the RFC. 
    383    Some of the popular OAuth2 providers are using custom errors. 
    384    """ 
    385    def __init__(self, error, *args, **kwargs): 
    386        self.error = error 
    387        super().__init__(*args, **kwargs) 
    388 
    389 
    390def raise_from_error(error, params=None): 
    391    kwargs = { 
    392        'description': params.get('error_description'), 
    393        'uri': params.get('error_uri'), 
    394        'state': params.get('state') 
    395    } 
    396    for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): 
    397        if cls.error == error: 
    398            raise cls(**kwargs) 
    399    raise CustomOAuth2Error(error=error, **kwargs)