Update oauthlib-3.1.1

This commit is contained in:
JonnyWong16 2021-10-14 22:34:45 -07:00
parent e58aa40099
commit d76838a607
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
64 changed files with 4329 additions and 1421 deletions

View file

@ -1,28 +1,25 @@
# -*- coding: utf-8 -*-
"""
oauthlib.oauth2.rfc6749.parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module contains methods related to `Section 4`_ of the OAuth 2 RFC.
.. _`Section 4`: http://tools.ietf.org/html/rfc6749#section-4
.. _`Section 4`: https://tools.ietf.org/html/rfc6749#section-4
"""
from __future__ import absolute_import, unicode_literals
import json
import os
import time
try:
import urlparse
except ImportError:
import urllib.parse as urlparse
from oauthlib.common import add_params_to_uri, add_params_to_qs, unicode_type
import urllib.parse as urlparse
from oauthlib.common import add_params_to_qs, add_params_to_uri
from oauthlib.signals import scope_changed
from .errors import raise_from_error, MissingTokenError, MissingTokenTypeError
from .errors import MismatchingStateError, MissingCodeError
from .errors import InsecureTransportError
from .errors import (
InsecureTransportError, MismatchingStateError, MissingCodeError,
MissingTokenError, MissingTokenTypeError, raise_from_error,
)
from .tokens import OAuth2Token
from .utils import list_to_scope, scope_to_list, is_secure_transport
from .utils import is_secure_transport, list_to_scope, scope_to_list
def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
@ -34,14 +31,14 @@ def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
using the ``application/x-www-form-urlencoded`` format as defined by
[`W3C.REC-html401-19991224`_]:
:param uri:
:param client_id: The client identifier as described in `Section 2.2`_.
:param response_type: To indicate which OAuth 2 grant/flow is required,
"code" and "token".
:param client_id: The client identifier as described in `Section 2.2`_.
:param redirect_uri: The client provided URI to redirect back to after
authorization as described in `Section 3.1.2`_.
:param scope: The scope of the access request as described by
`Section 3.3`_.
:param state: An opaque value used by the client to maintain
state between the request and callback. The authorization
server includes this value when redirecting the user-agent
@ -58,11 +55,11 @@ def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
.. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/rfc6749#ref-W3C.REC-html401-19991224
.. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
.. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
.. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
.. _`section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
.. _`W3C.REC-html401-19991224`: https://tools.ietf.org/html/rfc6749#ref-W3C.REC-html401-19991224
.. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
.. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
.. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
.. _`section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
"""
if not is_secure_transport(uri):
raise InsecureTransportError()
@ -79,12 +76,12 @@ def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
for k in kwargs:
if kwargs[k]:
params.append((unicode_type(k), kwargs[k]))
params.append((str(k), kwargs[k]))
return add_params_to_uri(uri, params)
def prepare_token_request(grant_type, body='', **kwargs):
def prepare_token_request(grant_type, body='', include_client_id=True, **kwargs):
"""Prepare the access token request.
The client makes a request to the token endpoint by adding the
@ -92,15 +89,39 @@ def prepare_token_request(grant_type, body='', **kwargs):
format in the HTTP request entity-body:
:param grant_type: To indicate grant type being used, i.e. "password",
"authorization_code" or "client_credentials".
:param body: Existing request body to embed parameters in.
:param code: If using authorization code grant, pass the previously
obtained authorization code as the ``code`` argument.
"authorization_code" or "client_credentials".
:param body: Existing request body (URL encoded string) to embed parameters
into. This may contain extra parameters. Default ''.
:param include_client_id: `True` (default) to send the `client_id` in the
body of the upstream request. This is required
if the client is not authenticating with the
authorization server as described in
`Section 3.2.1`_.
:type include_client_id: Boolean
:param client_id: Unicode client identifier. Will only appear if
`include_client_id` is True. *
:param client_secret: Unicode client secret. Will only appear if set to a
value that is not `None`. Invoking this function with
an empty string will send an empty `client_secret`
value to the server. *
:param code: If using authorization_code grant, pass the previously
obtained authorization code as the ``code`` argument. *
:param redirect_uri: If the "redirect_uri" parameter was included in the
authorization request as described in
`Section 4.1.1`_, and their values MUST be identical.
`Section 4.1.1`_, and their values MUST be identical. *
:param kwargs: Extra arguments to embed in the request body.
Parameters marked with a `*` above are not explicit arguments in the
function signature, but are specially documented arguments for items
appearing in the generic `**kwargs` keyworded input.
An example of an authorization code token request body:
.. code-block:: http
@ -108,16 +129,29 @@ def prepare_token_request(grant_type, body='', **kwargs):
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
.. _`Section 4.1.1`: http://tools.ietf.org/html/rfc6749#section-4.1.1
.. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1
"""
params = [('grant_type', grant_type)]
if 'scope' in kwargs:
kwargs['scope'] = list_to_scope(kwargs['scope'])
# pull the `client_id` out of the kwargs.
client_id = kwargs.pop('client_id', None)
if include_client_id:
if client_id is not None:
params.append(('client_id', client_id))
# the kwargs iteration below only supports including boolean truth (truthy)
# values, but some servers may require an empty string for `client_secret`
client_secret = kwargs.pop('client_secret', None)
if client_secret is not None:
params.append(('client_secret', client_secret))
# this handles: `code`, `redirect_uri`, and other undocumented params
for k in kwargs:
if kwargs[k]:
params.append((unicode_type(k), kwargs[k]))
params.append((str(k), kwargs[k]))
return add_params_to_qs(body, params)
@ -127,18 +161,22 @@ def prepare_token_revocation_request(url, token, token_type_hint="access_token",
"""Prepare a token revocation request.
The client constructs the request by including the following parameters
using the "application/x-www-form-urlencoded" format in the HTTP request
using the ``application/x-www-form-urlencoded`` format in the HTTP request
entity-body:
token REQUIRED. The token that the client wants to get revoked.
:param token: REQUIRED. The token that the client wants to get revoked.
token_type_hint OPTIONAL. A hint about the type of the token submitted
for revocation. Clients MAY pass this parameter in order to help the
authorization server to optimize the token lookup. If the server is unable
to locate the token using the given hint, it MUST extend its search across
all of its supported token types. An authorization server MAY ignore this
parameter, particularly if it is able to detect the token type
automatically. This specification defines two such values:
:param token_type_hint: OPTIONAL. A hint about the type of the token
submitted for revocation. Clients MAY pass this
parameter in order to help the authorization server
to optimize the token lookup. If the server is
unable to locate the token using the given hint, it
MUST extend its search across all of its supported
token types. An authorization server MAY ignore
this parameter, particularly if it is able to detect
the token type automatically.
This specification defines two values for `token_type_hint`:
* access_token: An access token as defined in [RFC6749],
`Section 1.4`_
@ -150,9 +188,9 @@ def prepare_token_revocation_request(url, token, token_type_hint="access_token",
specification MAY define other values for this parameter using the
registry defined in `Section 4.1.2`_.
.. _`Section 1.4`: http://tools.ietf.org/html/rfc6749#section-1.4
.. _`Section 1.5`: http://tools.ietf.org/html/rfc6749#section-1.5
.. _`Section 4.1.2`: http://tools.ietf.org/html/rfc7009#section-4.1.2
.. _`Section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4
.. _`Section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5
.. _`Section 4.1.2`: https://tools.ietf.org/html/rfc7009#section-4.1.2
"""
if not is_secure_transport(url):
@ -165,7 +203,7 @@ def prepare_token_revocation_request(url, token, token_type_hint="access_token",
for k in kwargs:
if kwargs[k]:
params.append((unicode_type(k), kwargs[k]))
params.append((str(k), kwargs[k]))
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
@ -220,12 +258,15 @@ def parse_authorization_code_response(uri, state=None):
query = urlparse.urlparse(uri).query
params = dict(urlparse.parse_qsl(query))
if not 'code' in params:
raise MissingCodeError("Missing code parameter in response.")
if state and params.get('state', None) != state:
raise MismatchingStateError()
if 'error' in params:
raise_from_error(params.get('error'), params)
if not 'code' in params:
raise MissingCodeError("Missing code parameter in response.")
return params
@ -261,6 +302,10 @@ def parse_implicit_response(uri, state=None, scope=None):
authorization request. The exact value received from the
client.
:param uri:
:param state:
:param scope:
Similar to the authorization code response, but with a full token provided
in the URL fragment:
@ -276,6 +321,10 @@ def parse_implicit_response(uri, state=None, scope=None):
fragment = urlparse.urlparse(uri).fragment
params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True))
for key in ('expires_in',):
if key in params: # cast things to int
params[key] = int(params[key])
if 'scope' in params:
params['scope'] = scope_to_list(params['scope'])
@ -345,10 +394,10 @@ def parse_token_response(body, scope=None):
"example_parameter":"example_value"
}
.. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
.. _`Section 6`: http://tools.ietf.org/html/rfc6749#section-6
.. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
.. _`RFC4627`: http://tools.ietf.org/html/rfc4627
.. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
.. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6
.. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
.. _`RFC4627`: https://tools.ietf.org/html/rfc4627
"""
try:
params = json.loads(body)
@ -356,21 +405,21 @@ def parse_token_response(body, scope=None):
# Fall back to URL-encoded string, to support old implementations,
# including (at time of writing) Facebook. See:
# https://github.com/idan/oauthlib/issues/267
# https://github.com/oauthlib/oauthlib/issues/267
params = dict(urlparse.parse_qsl(body))
for key in ('expires_in', 'expires'):
if key in params: # cast a couple things to int
for key in ('expires_in',):
if key in params: # cast things to int
params[key] = int(params[key])
if 'scope' in params:
params['scope'] = scope_to_list(params['scope'])
if 'expires' in params:
params['expires_in'] = params.pop('expires')
if 'expires_in' in params:
params['expires_at'] = time.time() + int(params['expires_in'])
if params['expires_in'] is None:
params.pop('expires_in')
else:
params['expires_at'] = time.time() + int(params['expires_in'])
params = OAuth2Token(params, old_scope=scope)
validate_token_parameters(params)
@ -378,7 +427,7 @@ def parse_token_response(body, scope=None):
def validate_token_parameters(params):
"""Ensures token precence, token type, expiration and scope in params."""
"""Ensures token presence, token type, expiration and scope in params."""
if 'error' in params:
raise_from_error(params.get('error'), params)
@ -392,7 +441,7 @@ def validate_token_parameters(params):
# If the issued access token scope is different from the one requested by
# the client, the authorization server MUST include the "scope" response
# parameter to inform the client of the actual scope granted.
# http://tools.ietf.org/html/rfc6749#section-3.3
# https://tools.ietf.org/html/rfc6749#section-3.3
if params.scope_changed:
message = 'Scope has changed from "{old}" to "{new}".'.format(
old=params.old_scope, new=params.scope,