Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/request_validator.py: 53%
59 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:22 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:22 +0000
1"""
2oauthlib.oauth2.rfc6749.request_validator
3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4"""
5import logging
7log = logging.getLogger(__name__)
10class RequestValidator:
12 def client_authentication_required(self, request, *args, **kwargs):
13 """Determine if client authentication is required for current request.
15 According to the rfc6749, client authentication is required in the following cases:
16 - Resource Owner Password Credentials Grant, when Client type is Confidential or when
17 Client was issued client credentials or whenever Client provided client
18 authentication, see `Section 4.3.2`_.
19 - Authorization Code Grant, when Client type is Confidential or when Client was issued
20 client credentials or whenever Client provided client authentication,
21 see `Section 4.1.3`_.
22 - Refresh Token Grant, when Client type is Confidential or when Client was issued
23 client credentials or whenever Client provided client authentication, see
24 `Section 6`_
26 :param request: OAuthlib request.
27 :type request: oauthlib.common.Request
28 :rtype: True or False
30 Method is used by:
31 - Authorization Code Grant
32 - Resource Owner Password Credentials Grant
33 - Refresh Token Grant
35 .. _`Section 4.3.2`: https://tools.ietf.org/html/rfc6749#section-4.3.2
36 .. _`Section 4.1.3`: https://tools.ietf.org/html/rfc6749#section-4.1.3
37 .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6
38 """
39 return True
41 def authenticate_client(self, request, *args, **kwargs):
42 """Authenticate client through means outside the OAuth 2 spec.
44 Means of authentication is negotiated beforehand and may for example
45 be `HTTP Basic Authentication Scheme`_ which utilizes the Authorization
46 header.
48 Headers may be accesses through request.headers and parameters found in
49 both body and query can be obtained by direct attribute access, i.e.
50 request.client_id for client_id in the URL query.
52 The authentication process is required to contain the identification of
53 the client (i.e. search the database based on the client_id). In case the
54 client doesn't exist based on the received client_id, this method has to
55 return False and the HTTP response created by the library will contain
56 'invalid_client' message.
58 After the client identification succeeds, this method needs to set the
59 client on the request, i.e. request.client = client. A client object's
60 class must contain the 'client_id' attribute and the 'client_id' must have
61 a value.
63 :param request: OAuthlib request.
64 :type request: oauthlib.common.Request
65 :rtype: True or False
67 Method is used by:
68 - Authorization Code Grant
69 - Resource Owner Password Credentials Grant (may be disabled)
70 - Client Credentials Grant
71 - Refresh Token Grant
73 .. _`HTTP Basic Authentication Scheme`: https://tools.ietf.org/html/rfc1945#section-11.1
74 """
75 raise NotImplementedError('Subclasses must implement this method.')
77 def authenticate_client_id(self, client_id, request, *args, **kwargs):
78 """Ensure client_id belong to a non-confidential client.
80 A non-confidential client is one that is not required to authenticate
81 through other means, such as using HTTP Basic.
83 Note, while not strictly necessary it can often be very convenient
84 to set request.client to the client object associated with the
85 given client_id.
87 :param client_id: Unicode client identifier.
88 :param request: OAuthlib request.
89 :type request: oauthlib.common.Request
90 :rtype: True or False
92 Method is used by:
93 - Authorization Code Grant
94 """
95 raise NotImplementedError('Subclasses must implement this method.')
97 def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request,
98 *args, **kwargs):
99 """Ensure that the authorization process represented by this authorization
100 code began with this 'redirect_uri'.
102 If the client specifies a redirect_uri when obtaining code then that
103 redirect URI must be bound to the code and verified equal in this
104 method, according to RFC 6749 section 4.1.3. Do not compare against
105 the client's allowed redirect URIs, but against the URI used when the
106 code was saved.
108 :param client_id: Unicode client identifier.
109 :param code: Unicode authorization_code.
110 :param redirect_uri: Unicode absolute URI.
111 :param client: Client object set by you, see ``.authenticate_client``.
112 :param request: OAuthlib request.
113 :type request: oauthlib.common.Request
114 :rtype: True or False
116 Method is used by:
117 - Authorization Code Grant (during token request)
118 """
119 raise NotImplementedError('Subclasses must implement this method.')
121 def get_default_redirect_uri(self, client_id, request, *args, **kwargs):
122 """Get the default redirect URI for the client.
124 :param client_id: Unicode client identifier.
125 :param request: OAuthlib request.
126 :type request: oauthlib.common.Request
127 :rtype: The default redirect URI for the client
129 Method is used by:
130 - Authorization Code Grant
131 - Implicit Grant
132 """
133 raise NotImplementedError('Subclasses must implement this method.')
135 def get_default_scopes(self, client_id, request, *args, **kwargs):
136 """Get the default scopes for the client.
138 :param client_id: Unicode client identifier.
139 :param request: OAuthlib request.
140 :type request: oauthlib.common.Request
141 :rtype: List of default scopes
143 Method is used by all core grant types:
144 - Authorization Code Grant
145 - Implicit Grant
146 - Resource Owner Password Credentials Grant
147 - Client Credentials grant
148 """
149 raise NotImplementedError('Subclasses must implement this method.')
151 def get_original_scopes(self, refresh_token, request, *args, **kwargs):
152 """Get the list of scopes associated with the refresh token.
154 :param refresh_token: Unicode refresh token.
155 :param request: OAuthlib request.
156 :type request: oauthlib.common.Request
157 :rtype: List of scopes.
159 Method is used by:
160 - Refresh token grant
161 """
162 raise NotImplementedError('Subclasses must implement this method.')
164 def is_within_original_scope(self, request_scopes, refresh_token, request, *args, **kwargs):
165 """Check if requested scopes are within a scope of the refresh token.
167 When access tokens are refreshed the scope of the new token
168 needs to be within the scope of the original token. This is
169 ensured by checking that all requested scopes strings are on
170 the list returned by the get_original_scopes. If this check
171 fails, is_within_original_scope is called. The method can be
172 used in situations where returning all valid scopes from the
173 get_original_scopes is not practical.
175 :param request_scopes: A list of scopes that were requested by client.
176 :param refresh_token: Unicode refresh_token.
177 :param request: OAuthlib request.
178 :type request: oauthlib.common.Request
179 :rtype: True or False
181 Method is used by:
182 - Refresh token grant
183 """
184 return False
186 def introspect_token(self, token, token_type_hint, request, *args, **kwargs):
187 """Introspect an access or refresh token.
189 Called once the introspect request is validated. This method should
190 verify the *token* and either return a dictionary with the list of
191 claims associated, or `None` in case the token is unknown.
193 Below the list of registered claims you should be interested in:
195 - scope : space-separated list of scopes
196 - client_id : client identifier
197 - username : human-readable identifier for the resource owner
198 - token_type : type of the token
199 - exp : integer timestamp indicating when this token will expire
200 - iat : integer timestamp indicating when this token was issued
201 - nbf : integer timestamp indicating when it can be "not-before" used
202 - sub : subject of the token - identifier of the resource owner
203 - aud : list of string identifiers representing the intended audience
204 - iss : string representing issuer of this token
205 - jti : string identifier for the token
207 Note that most of them are coming directly from JWT RFC. More details
208 can be found in `Introspect Claims`_ or `JWT Claims`_.
210 The implementation can use *token_type_hint* to improve lookup
211 efficiency, but must fallback to other types to be compliant with RFC.
213 The dict of claims is added to request.token after this method.
215 :param token: The token string.
216 :param token_type_hint: access_token or refresh_token.
217 :param request: OAuthlib request.
218 :type request: oauthlib.common.Request
220 Method is used by:
221 - Introspect Endpoint (all grants are compatible)
223 .. _`Introspect Claims`: https://tools.ietf.org/html/rfc7662#section-2.2
224 .. _`JWT Claims`: https://tools.ietf.org/html/rfc7519#section-4
225 """
226 raise NotImplementedError('Subclasses must implement this method.')
228 def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs):
229 """Invalidate an authorization code after use.
231 :param client_id: Unicode client identifier.
232 :param code: The authorization code grant (request.code).
233 :param request: OAuthlib request.
234 :type request: oauthlib.common.Request
236 Method is used by:
237 - Authorization Code Grant
238 """
239 raise NotImplementedError('Subclasses must implement this method.')
241 def revoke_token(self, token, token_type_hint, request, *args, **kwargs):
242 """Revoke an access or refresh token.
244 :param token: The token string.
245 :param token_type_hint: access_token or refresh_token.
246 :param request: OAuthlib request.
247 :type request: oauthlib.common.Request
249 Method is used by:
250 - Revocation Endpoint
251 """
252 raise NotImplementedError('Subclasses must implement this method.')
254 def rotate_refresh_token(self, request):
255 """Determine whether to rotate the refresh token. Default, yes.
257 When access tokens are refreshed the old refresh token can be kept
258 or replaced with a new one (rotated). Return True to rotate and
259 and False for keeping original.
261 :param request: OAuthlib request.
262 :type request: oauthlib.common.Request
263 :rtype: True or False
265 Method is used by:
266 - Refresh Token Grant
267 """
268 return True
270 def save_authorization_code(self, client_id, code, request, *args, **kwargs):
271 """Persist the authorization_code.
273 The code should at minimum be stored with:
274 - the client_id (``client_id``)
275 - the redirect URI used (``request.redirect_uri``)
276 - a resource owner / user (``request.user``)
277 - the authorized scopes (``request.scopes``)
279 To support PKCE, you MUST associate the code with:
280 - Code Challenge (``request.code_challenge``) and
281 - Code Challenge Method (``request.code_challenge_method``)
283 To support OIDC, you MUST associate the code with:
284 - nonce, if present (``code["nonce"]``)
286 The ``code`` argument is actually a dictionary, containing at least a
287 ``code`` key with the actual authorization code:
289 ``{'code': 'sdf345jsdf0934f'}``
291 It may also have a ``claims`` parameter which, when present, will be a dict
292 deserialized from JSON as described at
293 http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
294 This value should be saved in this method and used again in ``.validate_code``.
296 :param client_id: Unicode client identifier.
297 :param code: A dict of the authorization code grant and, optionally, state.
298 :param request: OAuthlib request.
299 :type request: oauthlib.common.Request
301 Method is used by:
302 - Authorization Code Grant
303 """
304 raise NotImplementedError('Subclasses must implement this method.')
306 def save_token(self, token, request, *args, **kwargs):
307 """Persist the token with a token type specific method.
309 Currently, only save_bearer_token is supported.
311 :param token: A (Bearer) token dict.
312 :param request: OAuthlib request.
313 :type request: oauthlib.common.Request
314 """
315 return self.save_bearer_token(token, request, *args, **kwargs)
317 def save_bearer_token(self, token, request, *args, **kwargs):
318 """Persist the Bearer token.
320 The Bearer token should at minimum be associated with:
321 - a client and it's client_id, if available
322 - a resource owner / user (request.user)
323 - authorized scopes (request.scopes)
324 - an expiration time
325 - a refresh token, if issued
326 - a claims document, if present in request.claims
328 The Bearer token dict may hold a number of items::
330 {
331 'token_type': 'Bearer',
332 'access_token': 'askfjh234as9sd8',
333 'expires_in': 3600,
334 'scope': 'string of space separated authorized scopes',
335 'refresh_token': '23sdf876234', # if issued
336 'state': 'given_by_client', # if supplied by client (implicit ONLY)
337 }
339 Note that while "scope" is a string-separated list of authorized scopes,
340 the original list is still available in request.scopes.
342 The token dict is passed as a reference so any changes made to the dictionary
343 will go back to the user. If additional information must return to the client
344 user, and it is only possible to get this information after writing the token
345 to storage, it should be added to the token dictionary. If the token
346 dictionary must be modified but the changes should not go back to the user,
347 a copy of the dictionary must be made before making the changes.
349 Also note that if an Authorization Code grant request included a valid claims
350 parameter (for OpenID Connect) then the request.claims property will contain
351 the claims dict, which should be saved for later use when generating the
352 id_token and/or UserInfo response content.
354 :param token: A Bearer token dict.
355 :param request: OAuthlib request.
356 :type request: oauthlib.common.Request
357 :rtype: The default redirect URI for the client
359 Method is used by all core grant types issuing Bearer tokens:
360 - Authorization Code Grant
361 - Implicit Grant
362 - Resource Owner Password Credentials Grant (might not associate a client)
363 - Client Credentials grant
364 """
365 raise NotImplementedError('Subclasses must implement this method.')
367 def validate_bearer_token(self, token, scopes, request):
368 """Ensure the Bearer token is valid and authorized access to scopes.
370 :param token: A string of random characters.
371 :param scopes: A list of scopes associated with the protected resource.
372 :param request: OAuthlib request.
373 :type request: oauthlib.common.Request
375 A key to OAuth 2 security and restricting impact of leaked tokens is
376 the short expiration time of tokens, *always ensure the token has not
377 expired!*.
379 Two different approaches to scope validation:
381 1) all(scopes). The token must be authorized access to all scopes
382 associated with the resource. For example, the
383 token has access to ``read-only`` and ``images``,
384 thus the client can view images but not upload new.
385 Allows for fine grained access control through
386 combining various scopes.
388 2) any(scopes). The token must be authorized access to one of the
389 scopes associated with the resource. For example,
390 token has access to ``read-only-images``.
391 Allows for fine grained, although arguably less
392 convenient, access control.
394 A powerful way to use scopes would mimic UNIX ACLs and see a scope
395 as a group with certain privileges. For a restful API these might
396 map to HTTP verbs instead of read, write and execute.
398 Note, the request.user attribute can be set to the resource owner
399 associated with this token. Similarly the request.client and
400 request.scopes attribute can be set to associated client object
401 and authorized scopes. If you then use a decorator such as the
402 one provided for django these attributes will be made available
403 in all protected views as keyword arguments.
405 :param token: Unicode Bearer token
406 :param scopes: List of scopes (defined by you)
407 :param request: OAuthlib request.
408 :type request: oauthlib.common.Request
409 :rtype: True or False
411 Method is indirectly used by all core Bearer token issuing grant types:
412 - Authorization Code Grant
413 - Implicit Grant
414 - Resource Owner Password Credentials Grant
415 - Client Credentials Grant
416 """
417 raise NotImplementedError('Subclasses must implement this method.')
419 def validate_client_id(self, client_id, request, *args, **kwargs):
420 """Ensure client_id belong to a valid and active client.
422 Note, while not strictly necessary it can often be very convenient
423 to set request.client to the client object associated with the
424 given client_id.
426 :param client_id: Unicode client identifier.
427 :param request: OAuthlib request.
428 :type request: oauthlib.common.Request
429 :rtype: True or False
431 Method is used by:
432 - Authorization Code Grant
433 - Implicit Grant
434 """
435 raise NotImplementedError('Subclasses must implement this method.')
437 def validate_code(self, client_id, code, client, request, *args, **kwargs):
438 """Verify that the authorization_code is valid and assigned to the given
439 client.
441 Before returning true, set the following based on the information stored
442 with the code in 'save_authorization_code':
444 - request.user
445 - request.scopes
446 - request.claims (if given)
448 OBS! The request.user attribute should be set to the resource owner
449 associated with this authorization code. Similarly request.scopes
450 must also be set.
452 The request.claims property, if it was given, should assigned a dict.
454 If PKCE is enabled (see 'is_pkce_required' and 'save_authorization_code')
455 you MUST set the following based on the information stored:
457 - request.code_challenge
458 - request.code_challenge_method
460 :param client_id: Unicode client identifier.
461 :param code: Unicode authorization code.
462 :param client: Client object set by you, see ``.authenticate_client``.
463 :param request: OAuthlib request.
464 :type request: oauthlib.common.Request
465 :rtype: True or False
467 Method is used by:
468 - Authorization Code Grant
469 """
470 raise NotImplementedError('Subclasses must implement this method.')
472 def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs):
473 """Ensure client is authorized to use the grant_type requested.
475 :param client_id: Unicode client identifier.
476 :param grant_type: Unicode grant type, i.e. authorization_code, password.
477 :param client: Client object set by you, see ``.authenticate_client``.
478 :param request: OAuthlib request.
479 :type request: oauthlib.common.Request
480 :rtype: True or False
482 Method is used by:
483 - Authorization Code Grant
484 - Resource Owner Password Credentials Grant
485 - Client Credentials Grant
486 - Refresh Token Grant
487 """
488 raise NotImplementedError('Subclasses must implement this method.')
490 def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs):
491 """Ensure client is authorized to redirect to the redirect_uri requested.
493 All clients should register the absolute URIs of all URIs they intend
494 to redirect to. The registration is outside of the scope of oauthlib.
496 :param client_id: Unicode client identifier.
497 :param redirect_uri: Unicode absolute URI.
498 :param request: OAuthlib request.
499 :type request: oauthlib.common.Request
500 :rtype: True or False
502 Method is used by:
503 - Authorization Code Grant
504 - Implicit Grant
505 """
506 raise NotImplementedError('Subclasses must implement this method.')
508 def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs):
509 """Ensure the Bearer token is valid and authorized access to scopes.
511 OBS! The request.user attribute should be set to the resource owner
512 associated with this refresh token.
514 :param refresh_token: Unicode refresh token.
515 :param client: Client object set by you, see ``.authenticate_client``.
516 :param request: OAuthlib request.
517 :type request: oauthlib.common.Request
518 :rtype: True or False
520 Method is used by:
521 - Authorization Code Grant (indirectly by issuing refresh tokens)
522 - Resource Owner Password Credentials Grant (also indirectly)
523 - Refresh Token Grant
524 """
525 raise NotImplementedError('Subclasses must implement this method.')
527 def validate_response_type(self, client_id, response_type, client, request, *args, **kwargs):
528 """Ensure client is authorized to use the response_type requested.
530 :param client_id: Unicode client identifier.
531 :param response_type: Unicode response type, i.e. code, token.
532 :param client: Client object set by you, see ``.authenticate_client``.
533 :param request: OAuthlib request.
534 :type request: oauthlib.common.Request
535 :rtype: True or False
537 Method is used by:
538 - Authorization Code Grant
539 - Implicit Grant
540 """
541 raise NotImplementedError('Subclasses must implement this method.')
543 def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
544 """Ensure the client is authorized access to requested scopes.
546 :param client_id: Unicode client identifier.
547 :param scopes: List of scopes (defined by you).
548 :param client: Client object set by you, see ``.authenticate_client``.
549 :param request: OAuthlib request.
550 :type request: oauthlib.common.Request
551 :rtype: True or False
553 Method is used by all core grant types:
554 - Authorization Code Grant
555 - Implicit Grant
556 - Resource Owner Password Credentials Grant
557 - Client Credentials Grant
558 """
559 raise NotImplementedError('Subclasses must implement this method.')
561 def validate_user(self, username, password, client, request, *args, **kwargs):
562 """Ensure the username and password is valid.
564 OBS! The validation should also set the user attribute of the request
565 to a valid resource owner, i.e. request.user = username or similar. If
566 not set you will be unable to associate a token with a user in the
567 persistence method used (commonly, save_bearer_token).
569 :param username: Unicode username.
570 :param password: Unicode password.
571 :param client: Client object set by you, see ``.authenticate_client``.
572 :param request: OAuthlib request.
573 :type request: oauthlib.common.Request
574 :rtype: True or False
576 Method is used by:
577 - Resource Owner Password Credentials Grant
578 """
579 raise NotImplementedError('Subclasses must implement this method.')
581 def is_pkce_required(self, client_id, request):
582 """Determine if current request requires PKCE. Default, False.
583 This is called for both "authorization" and "token" requests.
585 Override this method by ``return True`` to enable PKCE for everyone.
586 You might want to enable it only for public clients.
587 Note that PKCE can also be used in addition of a client authentication.
589 OAuth 2.0 public clients utilizing the Authorization Code Grant are
590 susceptible to the authorization code interception attack. This
591 specification describes the attack as well as a technique to mitigate
592 against the threat through the use of Proof Key for Code Exchange
593 (PKCE, pronounced "pixy"). See `RFC7636`_.
595 :param client_id: Client identifier.
596 :param request: OAuthlib request.
597 :type request: oauthlib.common.Request
598 :rtype: True or False
600 Method is used by:
601 - Authorization Code Grant
603 .. _`RFC7636`: https://tools.ietf.org/html/rfc7636
604 """
605 return False
607 def get_code_challenge(self, code, request):
608 """Is called for every "token" requests.
610 When the server issues the authorization code in the authorization
611 response, it MUST associate the ``code_challenge`` and
612 ``code_challenge_method`` values with the authorization code so it can
613 be verified later.
615 Typically, the ``code_challenge`` and ``code_challenge_method`` values
616 are stored in encrypted form in the ``code`` itself but could
617 alternatively be stored on the server associated with the code. The
618 server MUST NOT include the ``code_challenge`` value in client requests
619 in a form that other entities can extract.
621 Return the ``code_challenge`` associated to the code.
622 If ``None`` is returned, code is considered to not be associated to any
623 challenges.
625 :param code: Authorization code.
626 :param request: OAuthlib request.
627 :type request: oauthlib.common.Request
628 :rtype: code_challenge string
630 Method is used by:
631 - Authorization Code Grant - when PKCE is active
633 """
634 return None
636 def get_code_challenge_method(self, code, request):
637 """Is called during the "token" request processing, when a
638 ``code_verifier`` and a ``code_challenge`` has been provided.
640 See ``.get_code_challenge``.
642 Must return ``plain`` or ``S256``. You can return a custom value if you have
643 implemented your own ``AuthorizationCodeGrant`` class.
645 :param code: Authorization code.
646 :param request: OAuthlib request.
647 :type request: oauthlib.common.Request
648 :rtype: code_challenge_method string
650 Method is used by:
651 - Authorization Code Grant - when PKCE is active
653 """
654 raise NotImplementedError('Subclasses must implement this method.')
656 def is_origin_allowed(self, client_id, origin, request, *args, **kwargs):
657 """Indicate if the given origin is allowed to access the token endpoint
658 via Cross-Origin Resource Sharing (CORS). CORS is used by browser-based
659 clients, such as Single-Page Applications, to perform the Authorization
660 Code Grant.
662 (Note: If performing Authorization Code Grant via a public client such
663 as a browser, you should use PKCE as well.)
665 If this method returns true, the appropriate CORS headers will be added
666 to the response. By default this method always returns False, meaning
667 CORS is disabled.
669 :param client_id: Unicode client identifier.
670 :param redirect_uri: Unicode origin.
671 :param request: OAuthlib request.
672 :type request: oauthlib.common.Request
673 :rtype: bool
675 Method is used by:
676 - Authorization Code Grant
677 - Refresh Token Grant
679 """
680 return False