OAuth Provider Rewrite (#182)
This commit is contained in:
178
passbook/providers/oauth2/errors.py
Normal file
178
passbook/providers/oauth2/errors.py
Normal file
@ -0,0 +1,178 @@
|
||||
"""OAuth errors"""
|
||||
from urllib.parse import quote
|
||||
|
||||
|
||||
class OAuth2Error(Exception):
|
||||
"""Base class for all OAuth2 Errors"""
|
||||
|
||||
error: str
|
||||
description: str
|
||||
|
||||
def create_dict(self):
|
||||
"""Return error as dict for JSON Rendering"""
|
||||
return {
|
||||
"error": self.error,
|
||||
"error_description": self.description,
|
||||
}
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.error
|
||||
|
||||
|
||||
class RedirectUriError(OAuth2Error):
|
||||
"""The request fails due to a missing, invalid, or mismatching
|
||||
redirection URI (redirect_uri)."""
|
||||
|
||||
error = "Redirect URI Error"
|
||||
description = (
|
||||
"The request fails due to a missing, invalid, or mismatching"
|
||||
" redirection URI (redirect_uri)."
|
||||
)
|
||||
|
||||
|
||||
class ClientIdError(OAuth2Error):
|
||||
"""The client identifier (client_id) is missing or invalid."""
|
||||
|
||||
error = "Client ID Error"
|
||||
description = "The client identifier (client_id) is missing or invalid."
|
||||
|
||||
|
||||
class UserAuthError(OAuth2Error):
|
||||
"""
|
||||
Specific to the Resource Owner Password Credentials flow when
|
||||
the Resource Owners credentials are not valid.
|
||||
"""
|
||||
|
||||
error = "access_denied"
|
||||
description = "The resource owner or authorization server denied the request."
|
||||
|
||||
|
||||
class TokenIntrospectionError(OAuth2Error):
|
||||
"""
|
||||
Specific to the introspection endpoint. This error will be converted
|
||||
to an "active: false" response, as per the spec.
|
||||
See https://tools.ietf.org/html/rfc7662
|
||||
"""
|
||||
|
||||
|
||||
class AuthorizeError(OAuth2Error):
|
||||
"""General Authorization Errors"""
|
||||
|
||||
_errors = {
|
||||
# OAuth2 errors.
|
||||
# https://tools.ietf.org/html/rfc6749#section-4.1.2.1
|
||||
"invalid_request": "The request is otherwise malformed",
|
||||
"unauthorized_client": "The client is not authorized to request an "
|
||||
"authorization code using this method",
|
||||
"access_denied": "The resource owner or authorization server denied "
|
||||
"the request",
|
||||
"unsupported_response_type": "The authorization server does not "
|
||||
"support obtaining an authorization code "
|
||||
"using this method",
|
||||
"invalid_scope": "The requested scope is invalid, unknown, or " "malformed",
|
||||
"server_error": "The authorization server encountered an error",
|
||||
"temporarily_unavailable": "The authorization server is currently "
|
||||
"unable to handle the request due to a "
|
||||
"temporary overloading or maintenance of "
|
||||
"the server",
|
||||
# OpenID errors.
|
||||
# http://openid.net/specs/openid-connect-core-1_0.html#AuthError
|
||||
"interaction_required": "The Authorization Server requires End-User "
|
||||
"interaction of some form to proceed",
|
||||
"login_required": "The Authorization Server requires End-User "
|
||||
"authentication",
|
||||
"account_selection_required": "The End-User is required to select a "
|
||||
"session at the Authorization Server",
|
||||
"consent_required": "The Authorization Server requires End-User" "consent",
|
||||
"invalid_request_uri": "The request_uri in the Authorization Request "
|
||||
"returns an error or contains invalid data",
|
||||
"invalid_request_object": "The request parameter contains an invalid "
|
||||
"Request Object",
|
||||
"request_not_supported": "The provider does not support use of the "
|
||||
"request parameter",
|
||||
"request_uri_not_supported": "The provider does not support use of the "
|
||||
"request_uri parameter",
|
||||
"registration_not_supported": "The provider does not support use of "
|
||||
"the registration parameter",
|
||||
}
|
||||
|
||||
def __init__(self, redirect_uri, error, grant_type):
|
||||
super().__init__()
|
||||
self.error = error
|
||||
self.description = self._errors[error]
|
||||
self.redirect_uri = redirect_uri
|
||||
self.grant_type = grant_type
|
||||
|
||||
def create_uri(self, redirect_uri: str, state: str) -> str:
|
||||
"""Get a redirect URI with the error message"""
|
||||
description = quote(str(self.description))
|
||||
|
||||
# See:
|
||||
# http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthError
|
||||
hash_or_question = "#" if self.grant_type == "implicit" else "?"
|
||||
|
||||
uri = "{0}{1}error={2}&error_description={3}".format(
|
||||
redirect_uri, hash_or_question, self.error, description
|
||||
)
|
||||
|
||||
# Add state if present.
|
||||
uri = uri + ("&state={0}".format(state) if state else "")
|
||||
|
||||
return uri
|
||||
|
||||
|
||||
class TokenError(OAuth2Error):
|
||||
"""
|
||||
OAuth2 token endpoint errors.
|
||||
https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
"""
|
||||
|
||||
_errors = {
|
||||
"invalid_request": "The request is otherwise malformed",
|
||||
"invalid_client": "Client authentication failed (e.g., unknown client, "
|
||||
"no client authentication included, or unsupported "
|
||||
"authentication method)",
|
||||
"invalid_grant": "The provided authorization grant or refresh token is "
|
||||
"invalid, expired, revoked, does not match the "
|
||||
"redirection URI used in the authorization request, "
|
||||
"or was issued to another client",
|
||||
"unauthorized_client": "The authenticated client is not authorized to "
|
||||
"use this authorization grant type",
|
||||
"unsupported_grant_type": "The authorization grant type is not "
|
||||
"supported by the authorization server",
|
||||
"invalid_scope": "The requested scope is invalid, unknown, malformed, "
|
||||
"or exceeds the scope granted by the resource owner",
|
||||
}
|
||||
|
||||
def __init__(self, error):
|
||||
super().__init__()
|
||||
self.error = error
|
||||
self.description = self._errors[error]
|
||||
|
||||
|
||||
class BearerTokenError(OAuth2Error):
|
||||
"""
|
||||
OAuth2 errors.
|
||||
https://tools.ietf.org/html/rfc6750#section-3.1
|
||||
"""
|
||||
|
||||
_errors = {
|
||||
"invalid_request": ("The request is otherwise malformed", 400),
|
||||
"invalid_token": (
|
||||
"The access token provided is expired, revoked, malformed, "
|
||||
"or invalid for other reasons",
|
||||
401,
|
||||
),
|
||||
"insufficient_scope": (
|
||||
"The request requires higher privileges than provided by "
|
||||
"the access token",
|
||||
403,
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, code):
|
||||
super().__init__()
|
||||
self.code = code
|
||||
error_tuple = self._errors.get(code, ("", ""))
|
||||
self.description = error_tuple[0]
|
||||
self.status = error_tuple[1]
|
||||
Reference in New Issue
Block a user