179 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """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]
 | 
