|
|
|
"""
|
|
|
|
oauthlib.oauth2.rfc6749.request_validator
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
"""
|
|
|
|
import logging
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class RequestValidator:
|
|
|
|
|
|
|
|
def client_authentication_required(self, request, *args, **kwargs):
|
|
|
|
"""Determine if client authentication is required for current request.
|
|
|
|
|
|
|
|
According to the rfc6749, client authentication is required in the following cases:
|
|
|
|
- Resource Owner Password Credentials Grant, when Client type is Confidential or when
|
|
|
|
Client was issued client credentials or whenever Client provided client
|
|
|
|
authentication, see `Section 4.3.2`_.
|
|
|
|
- Authorization Code Grant, when Client type is Confidential or when Client was issued
|
|
|
|
client credentials or whenever Client provided client authentication,
|
|
|
|
see `Section 4.1.3`_.
|
|
|
|
- Refresh Token Grant, when Client type is Confidential or when Client was issued
|
|
|
|
client credentials or whenever Client provided client authentication, see
|
|
|
|
`Section 6`_
|
|
|
|
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Resource Owner Password Credentials Grant
|
|
|
|
- Refresh Token Grant
|
|
|
|
|
|
|
|
.. _`Section 4.3.2`: https://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
|
|
.. _`Section 4.1.3`: https://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
|
|
.. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6
|
|
|
|
"""
|
|
|
|
return True
|
|
|
|
|
|
|
|
def authenticate_client(self, request, *args, **kwargs):
|
|
|
|
"""Authenticate client through means outside the OAuth 2 spec.
|
|
|
|
|
|
|
|
Means of authentication is negotiated beforehand and may for example
|
|
|
|
be `HTTP Basic Authentication Scheme`_ which utilizes the Authorization
|
|
|
|
header.
|
|
|
|
|
|
|
|
Headers may be accesses through request.headers and parameters found in
|
|
|
|
both body and query can be obtained by direct attribute access, i.e.
|
|
|
|
request.client_id for client_id in the URL query.
|
|
|
|
|
|
|
|
The authentication process is required to contain the identification of
|
|
|
|
the client (i.e. search the database based on the client_id). In case the
|
|
|
|
client doesn't exist based on the received client_id, this method has to
|
|
|
|
return False and the HTTP response created by the library will contain
|
|
|
|
'invalid_client' message.
|
|
|
|
|
|
|
|
After the client identification succeeds, this method needs to set the
|
|
|
|
client on the request, i.e. request.client = client. A client object's
|
|
|
|
class must contain the 'client_id' attribute and the 'client_id' must have
|
|
|
|
a value.
|
|
|
|
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Resource Owner Password Credentials Grant (may be disabled)
|
|
|
|
- Client Credentials Grant
|
|
|
|
- Refresh Token Grant
|
|
|
|
|
|
|
|
.. _`HTTP Basic Authentication Scheme`: https://tools.ietf.org/html/rfc1945#section-11.1
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def authenticate_client_id(self, client_id, request, *args, **kwargs):
|
|
|
|
"""Ensure client_id belong to a non-confidential client.
|
|
|
|
|
|
|
|
A non-confidential client is one that is not required to authenticate
|
|
|
|
through other means, such as using HTTP Basic.
|
|
|
|
|
|
|
|
Note, while not strictly necessary it can often be very convenient
|
|
|
|
to set request.client to the client object associated with the
|
|
|
|
given client_id.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request,
|
|
|
|
*args, **kwargs):
|
|
|
|
"""Ensure that the authorization process represented by this authorization
|
|
|
|
code began with this 'redirect_uri'.
|
|
|
|
|
|
|
|
If the client specifies a redirect_uri when obtaining code then that
|
|
|
|
redirect URI must be bound to the code and verified equal in this
|
|
|
|
method, according to RFC 6749 section 4.1.3. Do not compare against
|
|
|
|
the client's allowed redirect URIs, but against the URI used when the
|
|
|
|
code was saved.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param code: Unicode authorization_code.
|
|
|
|
:param redirect_uri: Unicode absolute URI.
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant (during token request)
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def get_default_redirect_uri(self, client_id, request, *args, **kwargs):
|
|
|
|
"""Get the default redirect URI for the client.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: The default redirect URI for the client
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def get_default_scopes(self, client_id, request, *args, **kwargs):
|
|
|
|
"""Get the default scopes for the client.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: List of default scopes
|
|
|
|
|
|
|
|
Method is used by all core grant types:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
- Resource Owner Password Credentials Grant
|
|
|
|
- Client Credentials grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def get_original_scopes(self, refresh_token, request, *args, **kwargs):
|
|
|
|
"""Get the list of scopes associated with the refresh token.
|
|
|
|
|
|
|
|
:param refresh_token: Unicode refresh token.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: List of scopes.
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Refresh token grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def is_within_original_scope(self, request_scopes, refresh_token, request, *args, **kwargs):
|
|
|
|
"""Check if requested scopes are within a scope of the refresh token.
|
|
|
|
|
|
|
|
When access tokens are refreshed the scope of the new token
|
|
|
|
needs to be within the scope of the original token. This is
|
|
|
|
ensured by checking that all requested scopes strings are on
|
|
|
|
the list returned by the get_original_scopes. If this check
|
|
|
|
fails, is_within_original_scope is called. The method can be
|
|
|
|
used in situations where returning all valid scopes from the
|
|
|
|
get_original_scopes is not practical.
|
|
|
|
|
|
|
|
:param request_scopes: A list of scopes that were requested by client.
|
|
|
|
:param refresh_token: Unicode refresh_token.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Refresh token grant
|
|
|
|
"""
|
|
|
|
return False
|
|
|
|
|
|
|
|
def introspect_token(self, token, token_type_hint, request, *args, **kwargs):
|
|
|
|
"""Introspect an access or refresh token.
|
|
|
|
|
|
|
|
Called once the introspect request is validated. This method should
|
|
|
|
verify the *token* and either return a dictionary with the list of
|
|
|
|
claims associated, or `None` in case the token is unknown.
|
|
|
|
|
|
|
|
Below the list of registered claims you should be interested in:
|
|
|
|
|
|
|
|
- scope : space-separated list of scopes
|
|
|
|
- client_id : client identifier
|
|
|
|
- username : human-readable identifier for the resource owner
|
|
|
|
- token_type : type of the token
|
|
|
|
- exp : integer timestamp indicating when this token will expire
|
|
|
|
- iat : integer timestamp indicating when this token was issued
|
|
|
|
- nbf : integer timestamp indicating when it can be "not-before" used
|
|
|
|
- sub : subject of the token - identifier of the resource owner
|
|
|
|
- aud : list of string identifiers representing the intended audience
|
|
|
|
- iss : string representing issuer of this token
|
|
|
|
- jti : string identifier for the token
|
|
|
|
|
|
|
|
Note that most of them are coming directly from JWT RFC. More details
|
|
|
|
can be found in `Introspect Claims`_ or `JWT Claims`_.
|
|
|
|
|
|
|
|
The implementation can use *token_type_hint* to improve lookup
|
|
|
|
efficiency, but must fallback to other types to be compliant with RFC.
|
|
|
|
|
|
|
|
The dict of claims is added to request.token after this method.
|
|
|
|
|
|
|
|
:param token: The token string.
|
|
|
|
:param token_type_hint: access_token or refresh_token.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Introspect Endpoint (all grants are compatible)
|
|
|
|
|
|
|
|
.. _`Introspect Claims`: https://tools.ietf.org/html/rfc7662#section-2.2
|
|
|
|
.. _`JWT Claims`: https://tools.ietf.org/html/rfc7519#section-4
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs):
|
|
|
|
"""Invalidate an authorization code after use.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param code: The authorization code grant (request.code).
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def revoke_token(self, token, token_type_hint, request, *args, **kwargs):
|
|
|
|
"""Revoke an access or refresh token.
|
|
|
|
|
|
|
|
:param token: The token string.
|
|
|
|
:param token_type_hint: access_token or refresh_token.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Revocation Endpoint
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def rotate_refresh_token(self, request):
|
|
|
|
"""Determine whether to rotate the refresh token. Default, yes.
|
|
|
|
|
|
|
|
When access tokens are refreshed the old refresh token can be kept
|
|
|
|
or replaced with a new one (rotated). Return True to rotate and
|
|
|
|
and False for keeping original.
|
|
|
|
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Refresh Token Grant
|
|
|
|
"""
|
|
|
|
return True
|
|
|
|
|
|
|
|
def save_authorization_code(self, client_id, code, request, *args, **kwargs):
|
|
|
|
"""Persist the authorization_code.
|
|
|
|
|
|
|
|
The code should at minimum be stored with:
|
|
|
|
- the client_id (``client_id``)
|
|
|
|
- the redirect URI used (``request.redirect_uri``)
|
|
|
|
- a resource owner / user (``request.user``)
|
|
|
|
- the authorized scopes (``request.scopes``)
|
|
|
|
|
|
|
|
To support PKCE, you MUST associate the code with:
|
|
|
|
- Code Challenge (``request.code_challenge``) and
|
|
|
|
- Code Challenge Method (``request.code_challenge_method``)
|
|
|
|
|
|
|
|
To support OIDC, you MUST associate the code with:
|
|
|
|
- nonce, if present (``code["nonce"]``)
|
|
|
|
|
|
|
|
The ``code`` argument is actually a dictionary, containing at least a
|
|
|
|
``code`` key with the actual authorization code:
|
|
|
|
|
|
|
|
``{'code': 'sdf345jsdf0934f'}``
|
|
|
|
|
|
|
|
It may also have a ``claims`` parameter which, when present, will be a dict
|
|
|
|
deserialized from JSON as described at
|
|
|
|
http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
|
|
|
|
This value should be saved in this method and used again in ``.validate_code``.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param code: A dict of the authorization code grant and, optionally, state.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def save_token(self, token, request, *args, **kwargs):
|
|
|
|
"""Persist the token with a token type specific method.
|
|
|
|
|
|
|
|
Currently, only save_bearer_token is supported.
|
|
|
|
|
|
|
|
:param token: A (Bearer) token dict.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
"""
|
|
|
|
return self.save_bearer_token(token, request, *args, **kwargs)
|
|
|
|
|
|
|
|
def save_bearer_token(self, token, request, *args, **kwargs):
|
|
|
|
"""Persist the Bearer token.
|
|
|
|
|
|
|
|
The Bearer token should at minimum be associated with:
|
|
|
|
- a client and it's client_id, if available
|
|
|
|
- a resource owner / user (request.user)
|
|
|
|
- authorized scopes (request.scopes)
|
|
|
|
- an expiration time
|
|
|
|
- a refresh token, if issued
|
|
|
|
- a claims document, if present in request.claims
|
|
|
|
|
|
|
|
The Bearer token dict may hold a number of items::
|
|
|
|
|
|
|
|
{
|
|
|
|
'token_type': 'Bearer',
|
|
|
|
'access_token': 'askfjh234as9sd8',
|
|
|
|
'expires_in': 3600,
|
|
|
|
'scope': 'string of space separated authorized scopes',
|
|
|
|
'refresh_token': '23sdf876234', # if issued
|
|
|
|
'state': 'given_by_client', # if supplied by client (implicit ONLY)
|
|
|
|
}
|
|
|
|
|
|
|
|
Note that while "scope" is a string-separated list of authorized scopes,
|
|
|
|
the original list is still available in request.scopes.
|
|
|
|
|
|
|
|
The token dict is passed as a reference so any changes made to the dictionary
|
|
|
|
will go back to the user. If additional information must return to the client
|
|
|
|
user, and it is only possible to get this information after writing the token
|
|
|
|
to storage, it should be added to the token dictionary. If the token
|
|
|
|
dictionary must be modified but the changes should not go back to the user,
|
|
|
|
a copy of the dictionary must be made before making the changes.
|
|
|
|
|
|
|
|
Also note that if an Authorization Code grant request included a valid claims
|
|
|
|
parameter (for OpenID Connect) then the request.claims property will contain
|
|
|
|
the claims dict, which should be saved for later use when generating the
|
|
|
|
id_token and/or UserInfo response content.
|
|
|
|
|
|
|
|
:param token: A Bearer token dict.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: The default redirect URI for the client
|
|
|
|
|
|
|
|
Method is used by all core grant types issuing Bearer tokens:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
- Resource Owner Password Credentials Grant (might not associate a client)
|
|
|
|
- Client Credentials grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_bearer_token(self, token, scopes, request):
|
|
|
|
"""Ensure the Bearer token is valid and authorized access to scopes.
|
|
|
|
|
|
|
|
:param token: A string of random characters.
|
|
|
|
:param scopes: A list of scopes associated with the protected resource.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
|
|
|
|
A key to OAuth 2 security and restricting impact of leaked tokens is
|
|
|
|
the short expiration time of tokens, *always ensure the token has not
|
|
|
|
expired!*.
|
|
|
|
|
|
|
|
Two different approaches to scope validation:
|
|
|
|
|
|
|
|
1) all(scopes). The token must be authorized access to all scopes
|
|
|
|
associated with the resource. For example, the
|
|
|
|
token has access to ``read-only`` and ``images``,
|
|
|
|
thus the client can view images but not upload new.
|
|
|
|
Allows for fine grained access control through
|
|
|
|
combining various scopes.
|
|
|
|
|
|
|
|
2) any(scopes). The token must be authorized access to one of the
|
|
|
|
scopes associated with the resource. For example,
|
|
|
|
token has access to ``read-only-images``.
|
|
|
|
Allows for fine grained, although arguably less
|
|
|
|
convenient, access control.
|
|
|
|
|
|
|
|
A powerful way to use scopes would mimic UNIX ACLs and see a scope
|
|
|
|
as a group with certain privileges. For a restful API these might
|
|
|
|
map to HTTP verbs instead of read, write and execute.
|
|
|
|
|
|
|
|
Note, the request.user attribute can be set to the resource owner
|
|
|
|
associated with this token. Similarly the request.client and
|
|
|
|
request.scopes attribute can be set to associated client object
|
|
|
|
and authorized scopes. If you then use a decorator such as the
|
|
|
|
one provided for django these attributes will be made available
|
|
|
|
in all protected views as keyword arguments.
|
|
|
|
|
|
|
|
:param token: Unicode Bearer token
|
|
|
|
:param scopes: List of scopes (defined by you)
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is indirectly used by all core Bearer token issuing grant types:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
- Resource Owner Password Credentials Grant
|
|
|
|
- Client Credentials Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_client_id(self, client_id, request, *args, **kwargs):
|
|
|
|
"""Ensure client_id belong to a valid and active client.
|
|
|
|
|
|
|
|
Note, while not strictly necessary it can often be very convenient
|
|
|
|
to set request.client to the client object associated with the
|
|
|
|
given client_id.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_code(self, client_id, code, client, request, *args, **kwargs):
|
|
|
|
"""Verify that the authorization_code is valid and assigned to the given
|
|
|
|
client.
|
|
|
|
|
|
|
|
Before returning true, set the following based on the information stored
|
|
|
|
with the code in 'save_authorization_code':
|
|
|
|
|
|
|
|
- request.user
|
|
|
|
- request.scopes
|
|
|
|
- request.claims (if given)
|
|
|
|
|
|
|
|
OBS! The request.user attribute should be set to the resource owner
|
|
|
|
associated with this authorization code. Similarly request.scopes
|
|
|
|
must also be set.
|
|
|
|
|
|
|
|
The request.claims property, if it was given, should assigned a dict.
|
|
|
|
|
|
|
|
If PKCE is enabled (see 'is_pkce_required' and 'save_authorization_code')
|
|
|
|
you MUST set the following based on the information stored:
|
|
|
|
|
|
|
|
- request.code_challenge
|
|
|
|
- request.code_challenge_method
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param code: Unicode authorization code.
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs):
|
|
|
|
"""Ensure client is authorized to use the grant_type requested.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param grant_type: Unicode grant type, i.e. authorization_code, password.
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Resource Owner Password Credentials Grant
|
|
|
|
- Client Credentials Grant
|
|
|
|
- Refresh Token Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs):
|
|
|
|
"""Ensure client is authorized to redirect to the redirect_uri requested.
|
|
|
|
|
|
|
|
All clients should register the absolute URIs of all URIs they intend
|
|
|
|
to redirect to. The registration is outside of the scope of oauthlib.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param redirect_uri: Unicode absolute URI.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs):
|
|
|
|
"""Ensure the Bearer token is valid and authorized access to scopes.
|
|
|
|
|
|
|
|
OBS! The request.user attribute should be set to the resource owner
|
|
|
|
associated with this refresh token.
|
|
|
|
|
|
|
|
:param refresh_token: Unicode refresh token.
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant (indirectly by issuing refresh tokens)
|
|
|
|
- Resource Owner Password Credentials Grant (also indirectly)
|
|
|
|
- Refresh Token Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_response_type(self, client_id, response_type, client, request, *args, **kwargs):
|
|
|
|
"""Ensure client is authorized to use the response_type requested.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param response_type: Unicode response type, i.e. code, token.
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
|
|
|
|
"""Ensure the client is authorized access to requested scopes.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param scopes: List of scopes (defined by you).
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by all core grant types:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Implicit Grant
|
|
|
|
- Resource Owner Password Credentials Grant
|
|
|
|
- Client Credentials Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def validate_user(self, username, password, client, request, *args, **kwargs):
|
|
|
|
"""Ensure the username and password is valid.
|
|
|
|
|
|
|
|
OBS! The validation should also set the user attribute of the request
|
|
|
|
to a valid resource owner, i.e. request.user = username or similar. If
|
|
|
|
not set you will be unable to associate a token with a user in the
|
|
|
|
persistence method used (commonly, save_bearer_token).
|
|
|
|
|
|
|
|
:param username: Unicode username.
|
|
|
|
:param password: Unicode password.
|
|
|
|
:param client: Client object set by you, see ``.authenticate_client``.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Resource Owner Password Credentials Grant
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def is_pkce_required(self, client_id, request):
|
|
|
|
"""Determine if current request requires PKCE. Default, False.
|
|
|
|
This is called for both "authorization" and "token" requests.
|
|
|
|
|
|
|
|
Override this method by ``return True`` to enable PKCE for everyone.
|
|
|
|
You might want to enable it only for public clients.
|
|
|
|
Note that PKCE can also be used in addition of a client authentication.
|
|
|
|
|
|
|
|
OAuth 2.0 public clients utilizing the Authorization Code Grant are
|
|
|
|
susceptible to the authorization code interception attack. This
|
|
|
|
specification describes the attack as well as a technique to mitigate
|
|
|
|
against the threat through the use of Proof Key for Code Exchange
|
|
|
|
(PKCE, pronounced "pixy"). See `RFC7636`_.
|
|
|
|
|
|
|
|
:param client_id: Client identifier.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: True or False
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
|
|
|
|
.. _`RFC7636`: https://tools.ietf.org/html/rfc7636
|
|
|
|
"""
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_code_challenge(self, code, request):
|
|
|
|
"""Is called for every "token" requests.
|
|
|
|
|
|
|
|
When the server issues the authorization code in the authorization
|
|
|
|
response, it MUST associate the ``code_challenge`` and
|
|
|
|
``code_challenge_method`` values with the authorization code so it can
|
|
|
|
be verified later.
|
|
|
|
|
|
|
|
Typically, the ``code_challenge`` and ``code_challenge_method`` values
|
|
|
|
are stored in encrypted form in the ``code`` itself but could
|
|
|
|
alternatively be stored on the server associated with the code. The
|
|
|
|
server MUST NOT include the ``code_challenge`` value in client requests
|
|
|
|
in a form that other entities can extract.
|
|
|
|
|
|
|
|
Return the ``code_challenge`` associated to the code.
|
|
|
|
If ``None`` is returned, code is considered to not be associated to any
|
|
|
|
challenges.
|
|
|
|
|
|
|
|
:param code: Authorization code.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: code_challenge string
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant - when PKCE is active
|
|
|
|
|
|
|
|
"""
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_code_challenge_method(self, code, request):
|
|
|
|
"""Is called during the "token" request processing, when a
|
|
|
|
``code_verifier`` and a ``code_challenge`` has been provided.
|
|
|
|
|
|
|
|
See ``.get_code_challenge``.
|
|
|
|
|
|
|
|
Must return ``plain`` or ``S256``. You can return a custom value if you have
|
|
|
|
implemented your own ``AuthorizationCodeGrant`` class.
|
|
|
|
|
|
|
|
:param code: Authorization code.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: code_challenge_method string
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant - when PKCE is active
|
|
|
|
|
|
|
|
"""
|
|
|
|
raise NotImplementedError('Subclasses must implement this method.')
|
|
|
|
|
|
|
|
def is_origin_allowed(self, client_id, origin, request, *args, **kwargs):
|
|
|
|
"""Indicate if the given origin is allowed to access the token endpoint
|
|
|
|
via Cross-Origin Resource Sharing (CORS). CORS is used by browser-based
|
|
|
|
clients, such as Single-Page Applications, to perform the Authorization
|
|
|
|
Code Grant.
|
|
|
|
|
|
|
|
(Note: If performing Authorization Code Grant via a public client such
|
|
|
|
as a browser, you should use PKCE as well.)
|
|
|
|
|
|
|
|
If this method returns true, the appropriate CORS headers will be added
|
|
|
|
to the response. By default this method always returns False, meaning
|
|
|
|
CORS is disabled.
|
|
|
|
|
|
|
|
:param client_id: Unicode client identifier.
|
|
|
|
:param redirect_uri: Unicode origin.
|
|
|
|
:param request: OAuthlib request.
|
|
|
|
:type request: oauthlib.common.Request
|
|
|
|
:rtype: bool
|
|
|
|
|
|
|
|
Method is used by:
|
|
|
|
- Authorization Code Grant
|
|
|
|
- Refresh Token Grant
|
|
|
|
|
|
|
|
"""
|
|
|
|
return False
|