File: errors.py

package info (click to toggle)
python-authlib 1.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,016 kB
  • sloc: python: 26,998; makefile: 53; sh: 14
file content (247 lines) | stat: -rw-r--r-- 7,242 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
"""authlib.oauth2.rfc6749.errors.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Implementation for OAuth 2 Error Response. A basic error has
parameters:

Error:
REQUIRED.  A single ASCII [USASCII] error code.

error_description
OPTIONAL.  Human-readable ASCII [USASCII] text providing
additional information, used to assist the client developer in
understanding the error that occurred.

error_uri
OPTIONAL.  A URI identifying a human-readable web page with
information about the error, used to provide the client
developer with additional information about the error.
Values for the "error_uri" parameter MUST conform to the
URI-reference syntax and thus MUST NOT include characters
outside the set %x21 / %x23-5B / %x5D-7E.

state
REQUIRED if a "state" parameter was present in the client
authorization request.  The exact value received from the
client.

https://tools.ietf.org/html/rfc6749#section-5.2

:copyright: (c) 2017 by Hsiaoming Yang.

"""

from authlib.common.security import is_secure_transport
from authlib.oauth2.base import OAuth2Error

__all__ = [
    "OAuth2Error",
    "InsecureTransportError",
    "InvalidRequestError",
    "InvalidClientError",
    "UnauthorizedClientError",
    "InvalidGrantError",
    "UnsupportedResponseTypeError",
    "UnsupportedGrantTypeError",
    "InvalidScopeError",
    "AccessDeniedError",
    "MissingAuthorizationError",
    "UnsupportedTokenTypeError",
    "MissingCodeException",
    "MissingTokenException",
    "MissingTokenTypeException",
    "MismatchingStateException",
]


class InsecureTransportError(OAuth2Error):
    error = "insecure_transport"
    description = "OAuth 2 MUST utilize https."

    @classmethod
    def check(cls, uri):
        """Check and raise InsecureTransportError with the given URI."""
        if not is_secure_transport(uri):
            raise cls()


class InvalidRequestError(OAuth2Error):
    """The request is missing a required parameter, includes an
    unsupported parameter value (other than grant type),
    repeats a parameter, includes multiple credentials,
    utilizes more than one mechanism for authenticating the
    client, or is otherwise malformed.

    https://tools.ietf.org/html/rfc6749#section-5.2
    """

    error = "invalid_request"


class InvalidClientError(OAuth2Error):
    """Client authentication failed (e.g., unknown client, no
    client authentication included, or unsupported
    authentication method).  The authorization server MAY
    return an HTTP 401 (Unauthorized) status code to indicate
    which HTTP authentication schemes are supported.  If the
    client attempted to authenticate via the "Authorization"
    request header field, the authorization server MUST
    respond with an HTTP 401 (Unauthorized) status code and
    include the "WWW-Authenticate" response header field
    matching the authentication scheme used by the client.

    https://tools.ietf.org/html/rfc6749#section-5.2
    """

    error = "invalid_client"
    status_code = 400

    def get_headers(self):
        headers = super().get_headers()
        if self.status_code == 401:
            error_description = self.get_error_description()
            # safe escape
            error_description = error_description.replace('"', "|")
            extras = [
                f'error="{self.error}"',
                f'error_description="{error_description}"',
            ]
            headers.append(("WWW-Authenticate", "Basic " + ", ".join(extras)))
        return headers


class InvalidGrantError(OAuth2Error):
    """The provided authorization grant (e.g., authorization
    code, resource owner credentials) or refresh token is
    invalid, expired, revoked, does not match the redirection
    URI used in the authorization request, or was issued to
    another client.

    https://tools.ietf.org/html/rfc6749#section-5.2
    """

    error = "invalid_grant"


class UnauthorizedClientError(OAuth2Error):
    """The authenticated client is not authorized to use this
    authorization grant type.

    https://tools.ietf.org/html/rfc6749#section-5.2
    """

    error = "unauthorized_client"


class UnsupportedResponseTypeError(OAuth2Error):
    """The authorization server does not support obtaining
    an access token using this method.
    """

    error = "unsupported_response_type"

    def __init__(self, response_type, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.response_type = response_type

    def get_error_description(self):
        return f"response_type={self.response_type} is not supported"


class UnsupportedGrantTypeError(OAuth2Error):
    """The authorization grant type is not supported by the
    authorization server.

    https://tools.ietf.org/html/rfc6749#section-5.2
    """

    error = "unsupported_grant_type"

    def __init__(self, grant_type):
        super().__init__()
        self.grant_type = grant_type

    def get_error_description(self):
        return f"grant_type={self.grant_type} is not supported"


class InvalidScopeError(OAuth2Error):
    """The requested scope is invalid, unknown, malformed, or
    exceeds the scope granted by the resource owner.

    https://tools.ietf.org/html/rfc6749#section-5.2
    """

    error = "invalid_scope"
    description = "The requested scope is invalid, unknown, or malformed."


class AccessDeniedError(OAuth2Error):
    """The resource owner or authorization server denied the request.

    Used in authorization endpoint for "code" and "implicit". Defined in
    `Section 4.1.2.1`_.

    .. _`Section 4.1.2.1`: https://tools.ietf.org/html/rfc6749#section-4.1.2.1
    """

    error = "access_denied"
    description = "The resource owner or authorization server denied the request"


# -- below are extended errors -- #


class ForbiddenError(OAuth2Error):
    status_code = 401

    def __init__(self, auth_type=None, realm=None):
        super().__init__()
        self.auth_type = auth_type
        self.realm = realm

    def get_headers(self):
        headers = super().get_headers()
        if not self.auth_type:
            return headers

        extras = []
        if self.realm:
            extras.append(f'realm="{self.realm}"')
        extras.append(f'error="{self.error}"')
        error_description = self.description
        extras.append(f'error_description="{error_description}"')
        headers.append(("WWW-Authenticate", f"{self.auth_type} " + ", ".join(extras)))
        return headers


class MissingAuthorizationError(ForbiddenError):
    error = "missing_authorization"
    description = "Missing 'Authorization' in headers."


class UnsupportedTokenTypeError(ForbiddenError):
    error = "unsupported_token_type"


# -- exceptions for clients -- #


class MissingCodeException(OAuth2Error):
    error = "missing_code"
    description = "Missing 'code' in response."


class MissingTokenException(OAuth2Error):
    error = "missing_token"
    description = "Missing 'access_token' in response."


class MissingTokenTypeException(OAuth2Error):
    error = "missing_token_type"
    description = "Missing 'token_type' in response."


class MismatchingStateException(OAuth2Error):
    error = "mismatching_state"
    description = "CSRF Warning! State not equal in request and response."