aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints')
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py8
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py215
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py158
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py244
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py14
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py209
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py163
-rw-r--r--.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py82
8 files changed, 1093 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py
new file mode 100644
index 00000000..9f30389f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/__init__.py
@@ -0,0 +1,8 @@
+from .access_token import AccessTokenEndpoint
+from .authorization import AuthorizationEndpoint
+from .base import BaseEndpoint
+from .request_token import RequestTokenEndpoint
+from .resource import ResourceEndpoint
+from .signature_only import SignatureOnlyEndpoint
+
+from .pre_configured import WebApplicationServer # isort:skip
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py
new file mode 100644
index 00000000..13665db0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/access_token.py
@@ -0,0 +1,215 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.access_token
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the access token provider logic of
+OAuth 1.0 RFC 5849. It validates the correctness of access token requests,
+creates and persists tokens as well as create the proper response to be
+returned to the client.
+"""
+import logging
+
+from oauthlib.common import urlencode
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class AccessTokenEndpoint(BaseEndpoint):
+
+ """An endpoint responsible for providing OAuth 1 access tokens.
+
+ Typical use is to instantiate with a request validator and invoke the
+ ``create_access_token_response`` from a view function. The tuple returned
+ has all information necessary (body, status, headers) to quickly form
+ and return a proper response. See :doc:`/oauth1/validator` for details on which
+ validator methods to implement for this endpoint.
+ """
+
+ def create_access_token(self, request, credentials):
+ """Create and save a new access token.
+
+ Similar to OAuth 2, indication of granted scopes will be included as a
+ space separated list in ``oauth_authorized_realms``.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :returns: The token as an urlencoded string.
+ """
+ request.realms = self.request_validator.get_realms(
+ request.resource_owner_key, request)
+ token = {
+ 'oauth_token': self.token_generator(),
+ 'oauth_token_secret': self.token_generator(),
+ # Backport the authorized scopes indication used in OAuth2
+ 'oauth_authorized_realms': ' '.join(request.realms)
+ }
+ token.update(credentials)
+ self.request_validator.save_access_token(token, request)
+ return urlencode(token.items())
+
+ def create_access_token_response(self, uri, http_method='GET', body=None,
+ headers=None, credentials=None):
+ """Create an access token response, with a new request token if valid.
+
+ :param uri: The full URI of the token request.
+ :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+ :param body: The request body as a string.
+ :param headers: The request headers as a dict.
+ :param credentials: A list of extra credentials to include in the token.
+ :returns: A tuple of 3 elements.
+ 1. A dict of headers to set on the response.
+ 2. The response body as a string.
+ 3. The response status code as an integer.
+
+ An example of a valid request::
+
+ >>> from your_validator import your_validator
+ >>> from oauthlib.oauth1 import AccessTokenEndpoint
+ >>> endpoint = AccessTokenEndpoint(your_validator)
+ >>> h, b, s = endpoint.create_access_token_response(
+ ... 'https://your.provider/access_token?foo=bar',
+ ... headers={
+ ... 'Authorization': 'OAuth oauth_token=234lsdkf....'
+ ... },
+ ... credentials={
+ ... 'my_specific': 'argument',
+ ... })
+ >>> h
+ {'Content-Type': 'application/x-www-form-urlencoded'}
+ >>> b
+ 'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_authorized_realms=movies+pics&my_specific=argument'
+ >>> s
+ 200
+
+ An response to invalid request would have a different body and status::
+
+ >>> b
+ 'error=invalid_request&description=missing+resource+owner+key'
+ >>> s
+ 400
+
+ The same goes for an an unauthorized request:
+
+ >>> b
+ ''
+ >>> s
+ 401
+ """
+ resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+ try:
+ request = self._create_request(uri, http_method, body, headers)
+ valid, processed_request = self.validate_access_token_request(
+ request)
+ if valid:
+ token = self.create_access_token(request, credentials or {})
+ self.request_validator.invalidate_request_token(
+ request.client_key,
+ request.resource_owner_key,
+ request)
+ return resp_headers, token, 200
+ else:
+ return {}, None, 401
+ except errors.OAuth1Error as e:
+ return resp_headers, e.urlencoded, e.status_code
+
+ def validate_access_token_request(self, request):
+ """Validate an access token request.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :raises: OAuth1Error if the request is invalid.
+ :returns: A tuple of 2 elements.
+ 1. The validation result (True or False).
+ 2. The request object.
+ """
+ self._check_transport_security(request)
+ self._check_mandatory_parameters(request)
+
+ if not request.resource_owner_key:
+ raise errors.InvalidRequestError(
+ description='Missing resource owner.')
+
+ if not self.request_validator.check_request_token(
+ request.resource_owner_key):
+ raise errors.InvalidRequestError(
+ description='Invalid resource owner key format.')
+
+ if not request.verifier:
+ raise errors.InvalidRequestError(
+ description='Missing verifier.')
+
+ if not self.request_validator.check_verifier(request.verifier):
+ raise errors.InvalidRequestError(
+ description='Invalid verifier format.')
+
+ if not self.request_validator.validate_timestamp_and_nonce(
+ request.client_key, request.timestamp, request.nonce, request,
+ request_token=request.resource_owner_key):
+ return False, request
+
+ # The server SHOULD return a 401 (Unauthorized) status code when
+ # receiving a request with invalid client credentials.
+ # Note: This is postponed in order to avoid timing attacks, instead
+ # a dummy client is assigned and used to maintain near constant
+ # time request verification.
+ #
+ # Note that early exit would enable client enumeration
+ valid_client = self.request_validator.validate_client_key(
+ request.client_key, request)
+ if not valid_client:
+ request.client_key = self.request_validator.dummy_client
+
+ # The server SHOULD return a 401 (Unauthorized) status code when
+ # receiving a request with invalid or expired token.
+ # Note: This is postponed in order to avoid timing attacks, instead
+ # a dummy token is assigned and used to maintain near constant
+ # time request verification.
+ #
+ # Note that early exit would enable resource owner enumeration
+ valid_resource_owner = self.request_validator.validate_request_token(
+ request.client_key, request.resource_owner_key, request)
+ if not valid_resource_owner:
+ request.resource_owner_key = self.request_validator.dummy_request_token
+
+ # The server MUST verify (Section 3.2) the validity of the request,
+ # ensure that the resource owner has authorized the provisioning of
+ # token credentials to the client, and ensure that the temporary
+ # credentials have not expired or been used before. The server MUST
+ # also verify the verification code received from the client.
+ # .. _`Section 3.2`: https://tools.ietf.org/html/rfc5849#section-3.2
+ #
+ # Note that early exit would enable resource owner authorization
+ # verifier enumertion.
+ valid_verifier = self.request_validator.validate_verifier(
+ request.client_key,
+ request.resource_owner_key,
+ request.verifier,
+ request)
+
+ valid_signature = self._check_signature(request, is_token_request=True)
+
+ # log the results to the validator_log
+ # this lets us handle internal reporting and analysis
+ request.validator_log['client'] = valid_client
+ request.validator_log['resource_owner'] = valid_resource_owner
+ request.validator_log['verifier'] = valid_verifier
+ request.validator_log['signature'] = valid_signature
+
+ # We delay checking validity until the very end, using dummy values for
+ # calculations and fetching secrets/keys to ensure the flow of every
+ # request remains almost identical regardless of whether valid values
+ # have been supplied. This ensures near constant time execution and
+ # prevents malicious users from guessing sensitive information
+ v = all((valid_client, valid_resource_owner, valid_verifier,
+ valid_signature))
+ if not v:
+ log.info("[Failure] request verification failed.")
+ log.info("Valid client:, %s", valid_client)
+ log.info("Valid token:, %s", valid_resource_owner)
+ log.info("Valid verifier:, %s", valid_verifier)
+ log.info("Valid signature:, %s", valid_signature)
+ return v, request
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py
new file mode 100644
index 00000000..00d9576b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/authorization.py
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.authorization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of various logic needed
+for signing and checking OAuth 1.0 RFC 5849 requests.
+"""
+from urllib.parse import urlencode
+
+from oauthlib.common import add_params_to_uri
+
+from .. import errors
+from .base import BaseEndpoint
+
+
+class AuthorizationEndpoint(BaseEndpoint):
+
+ """An endpoint responsible for letting authenticated users authorize access
+ to their protected resources to a client.
+
+ Typical use would be to have two views, one for displaying the authorization
+ form and one to process said form on submission.
+
+ The first view will want to utilize ``get_realms_and_credentials`` to fetch
+ requested realms and useful client credentials, such as name and
+ description, to be used when creating the authorization form.
+
+ During form processing you can use ``create_authorization_response`` to
+ validate the request, create a verifier as well as prepare the final
+ redirection URI used to send the user back to the client.
+
+ See :doc:`/oauth1/validator` for details on which validator methods to implement
+ for this endpoint.
+ """
+
+ def create_verifier(self, request, credentials):
+ """Create and save a new request token.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param credentials: A dict of extra token credentials.
+ :returns: The verifier as a dict.
+ """
+ verifier = {
+ 'oauth_token': request.resource_owner_key,
+ 'oauth_verifier': self.token_generator(),
+ }
+ verifier.update(credentials)
+ self.request_validator.save_verifier(
+ request.resource_owner_key, verifier, request)
+ return verifier
+
+ def create_authorization_response(self, uri, http_method='GET', body=None,
+ headers=None, realms=None, credentials=None):
+ """Create an authorization response, with a new request token if valid.
+
+ :param uri: The full URI of the token request.
+ :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+ :param body: The request body as a string.
+ :param headers: The request headers as a dict.
+ :param credentials: A list of credentials to include in the verifier.
+ :returns: A tuple of 3 elements.
+ 1. A dict of headers to set on the response.
+ 2. The response body as a string.
+ 3. The response status code as an integer.
+
+ If the callback URI tied to the current token is "oob", a response with
+ a 200 status code will be returned. In this case, it may be desirable to
+ modify the response to better display the verifier to the client.
+
+ An example of an authorization request::
+
+ >>> from your_validator import your_validator
+ >>> from oauthlib.oauth1 import AuthorizationEndpoint
+ >>> endpoint = AuthorizationEndpoint(your_validator)
+ >>> h, b, s = endpoint.create_authorization_response(
+ ... 'https://your.provider/authorize?oauth_token=...',
+ ... credentials={
+ ... 'extra': 'argument',
+ ... })
+ >>> h
+ {'Location': 'https://the.client/callback?oauth_verifier=...&extra=argument'}
+ >>> b
+ None
+ >>> s
+ 302
+
+ An example of a request with an "oob" callback::
+
+ >>> from your_validator import your_validator
+ >>> from oauthlib.oauth1 import AuthorizationEndpoint
+ >>> endpoint = AuthorizationEndpoint(your_validator)
+ >>> h, b, s = endpoint.create_authorization_response(
+ ... 'https://your.provider/authorize?foo=bar',
+ ... credentials={
+ ... 'extra': 'argument',
+ ... })
+ >>> h
+ {'Content-Type': 'application/x-www-form-urlencoded'}
+ >>> b
+ 'oauth_verifier=...&extra=argument'
+ >>> s
+ 200
+ """
+ request = self._create_request(uri, http_method=http_method, body=body,
+ headers=headers)
+
+ if not request.resource_owner_key:
+ raise errors.InvalidRequestError(
+ 'Missing mandatory parameter oauth_token.')
+ if not self.request_validator.verify_request_token(
+ request.resource_owner_key, request):
+ raise errors.InvalidClientError()
+
+ request.realms = realms
+ if (request.realms and not self.request_validator.verify_realms(
+ request.resource_owner_key, request.realms, request)):
+ raise errors.InvalidRequestError(
+ description=('User granted access to realms outside of '
+ 'what the client may request.'))
+
+ verifier = self.create_verifier(request, credentials or {})
+ redirect_uri = self.request_validator.get_redirect_uri(
+ request.resource_owner_key, request)
+ if redirect_uri == 'oob':
+ response_headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded'}
+ response_body = urlencode(verifier)
+ return response_headers, response_body, 200
+ else:
+ populated_redirect = add_params_to_uri(
+ redirect_uri, verifier.items())
+ return {'Location': populated_redirect}, None, 302
+
+ def get_realms_and_credentials(self, uri, http_method='GET', body=None,
+ headers=None):
+ """Fetch realms and credentials for the presented request token.
+
+ :param uri: The full URI of the token request.
+ :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+ :param body: The request body as a string.
+ :param headers: The request headers as a dict.
+ :returns: A tuple of 2 elements.
+ 1. A list of request realms.
+ 2. A dict of credentials which may be useful in creating the
+ authorization form.
+ """
+ request = self._create_request(uri, http_method=http_method, body=body,
+ headers=headers)
+
+ if not self.request_validator.verify_request_token(
+ request.resource_owner_key, request):
+ raise errors.InvalidClientError()
+
+ realms = self.request_validator.get_realms(
+ request.resource_owner_key, request)
+ return realms, {'resource_owner_key': request.resource_owner_key}
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py
new file mode 100644
index 00000000..7831be7c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/base.py
@@ -0,0 +1,244 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.base
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of various logic needed
+for signing and checking OAuth 1.0 RFC 5849 requests.
+"""
+import time
+
+from oauthlib.common import CaseInsensitiveDict, Request, generate_token
+
+from .. import (
+ CONTENT_TYPE_FORM_URLENCODED, SIGNATURE_HMAC_SHA1, SIGNATURE_HMAC_SHA256,
+ SIGNATURE_HMAC_SHA512, SIGNATURE_PLAINTEXT, SIGNATURE_RSA_SHA1,
+ SIGNATURE_RSA_SHA256, SIGNATURE_RSA_SHA512, SIGNATURE_TYPE_AUTH_HEADER,
+ SIGNATURE_TYPE_BODY, SIGNATURE_TYPE_QUERY, errors, signature, utils,
+)
+
+
+class BaseEndpoint:
+
+ def __init__(self, request_validator, token_generator=None):
+ self.request_validator = request_validator
+ self.token_generator = token_generator or generate_token
+
+ def _get_signature_type_and_params(self, request):
+ """Extracts parameters from query, headers and body. Signature type
+ is set to the source in which parameters were found.
+ """
+ # Per RFC5849, only the Authorization header may contain the 'realm'
+ # optional parameter.
+ header_params = signature.collect_parameters(headers=request.headers,
+ exclude_oauth_signature=False, with_realm=True)
+ body_params = signature.collect_parameters(body=request.body,
+ exclude_oauth_signature=False)
+ query_params = signature.collect_parameters(uri_query=request.uri_query,
+ exclude_oauth_signature=False)
+
+ params = []
+ params.extend(header_params)
+ params.extend(body_params)
+ params.extend(query_params)
+ signature_types_with_oauth_params = list(filter(lambda s: s[2], (
+ (SIGNATURE_TYPE_AUTH_HEADER, params,
+ utils.filter_oauth_params(header_params)),
+ (SIGNATURE_TYPE_BODY, params,
+ utils.filter_oauth_params(body_params)),
+ (SIGNATURE_TYPE_QUERY, params,
+ utils.filter_oauth_params(query_params))
+ )))
+
+ if len(signature_types_with_oauth_params) > 1:
+ found_types = [s[0] for s in signature_types_with_oauth_params]
+ raise errors.InvalidRequestError(
+ description=('oauth_ params must come from only 1 signature'
+ 'type but were found in %s',
+ ', '.join(found_types)))
+
+ try:
+ signature_type, params, oauth_params = signature_types_with_oauth_params[
+ 0]
+ except IndexError:
+ raise errors.InvalidRequestError(
+ description='Missing mandatory OAuth parameters.')
+
+ return signature_type, params, oauth_params
+
+ def _create_request(self, uri, http_method, body, headers):
+ # Only include body data from x-www-form-urlencoded requests
+ headers = CaseInsensitiveDict(headers or {})
+ if ("Content-Type" in headers and
+ CONTENT_TYPE_FORM_URLENCODED in headers["Content-Type"]):
+ request = Request(uri, http_method, body, headers)
+ else:
+ request = Request(uri, http_method, '', headers)
+
+ signature_type, params, oauth_params = (
+ self._get_signature_type_and_params(request))
+
+ # The server SHOULD return a 400 (Bad Request) status code when
+ # receiving a request with duplicated protocol parameters.
+ if len(dict(oauth_params)) != len(oauth_params):
+ raise errors.InvalidRequestError(
+ description='Duplicate OAuth1 entries.')
+
+ oauth_params = dict(oauth_params)
+ request.signature = oauth_params.get('oauth_signature')
+ request.client_key = oauth_params.get('oauth_consumer_key')
+ request.resource_owner_key = oauth_params.get('oauth_token')
+ request.nonce = oauth_params.get('oauth_nonce')
+ request.timestamp = oauth_params.get('oauth_timestamp')
+ request.redirect_uri = oauth_params.get('oauth_callback')
+ request.verifier = oauth_params.get('oauth_verifier')
+ request.signature_method = oauth_params.get('oauth_signature_method')
+ request.realm = dict(params).get('realm')
+ request.oauth_params = oauth_params
+
+ # Parameters to Client depend on signature method which may vary
+ # for each request. Note that HMAC-SHA1 and PLAINTEXT share parameters
+ request.params = [(k, v) for k, v in params if k != "oauth_signature"]
+
+ if 'realm' in request.headers.get('Authorization', ''):
+ request.params = [(k, v)
+ for k, v in request.params if k != "realm"]
+
+ return request
+
+ def _check_transport_security(self, request):
+ # TODO: move into oauthlib.common from oauth2.utils
+ if (self.request_validator.enforce_ssl and
+ not request.uri.lower().startswith("https://")):
+ raise errors.InsecureTransportError()
+
+ def _check_mandatory_parameters(self, request):
+ # The server SHOULD return a 400 (Bad Request) status code when
+ # receiving a request with missing parameters.
+ if not all((request.signature, request.client_key,
+ request.nonce, request.timestamp,
+ request.signature_method)):
+ raise errors.InvalidRequestError(
+ description='Missing mandatory OAuth parameters.')
+
+ # OAuth does not mandate a particular signature method, as each
+ # implementation can have its own unique requirements. Servers are
+ # free to implement and document their own custom methods.
+ # Recommending any particular method is beyond the scope of this
+ # specification. Implementers should review the Security
+ # Considerations section (`Section 4`_) before deciding on which
+ # method to support.
+ # .. _`Section 4`: https://tools.ietf.org/html/rfc5849#section-4
+ if (not request.signature_method in
+ self.request_validator.allowed_signature_methods):
+ raise errors.InvalidSignatureMethodError(
+ description="Invalid signature, {} not in {!r}.".format(
+ request.signature_method,
+ self.request_validator.allowed_signature_methods))
+
+ # Servers receiving an authenticated request MUST validate it by:
+ # If the "oauth_version" parameter is present, ensuring its value is
+ # "1.0".
+ if ('oauth_version' in request.oauth_params and
+ request.oauth_params['oauth_version'] != '1.0'):
+ raise errors.InvalidRequestError(
+ description='Invalid OAuth version.')
+
+ # The timestamp value MUST be a positive integer. Unless otherwise
+ # specified by the server's documentation, the timestamp is expressed
+ # in the number of seconds since January 1, 1970 00:00:00 GMT.
+ if len(request.timestamp) != 10:
+ raise errors.InvalidRequestError(
+ description='Invalid timestamp size')
+
+ try:
+ ts = int(request.timestamp)
+
+ except ValueError:
+ raise errors.InvalidRequestError(
+ description='Timestamp must be an integer.')
+
+ else:
+ # To avoid the need to retain an infinite number of nonce values for
+ # future checks, servers MAY choose to restrict the time period after
+ # which a request with an old timestamp is rejected.
+ if abs(time.time() - ts) > self.request_validator.timestamp_lifetime:
+ raise errors.InvalidRequestError(
+ description=('Timestamp given is invalid, differ from '
+ 'allowed by over %s seconds.' % (
+ self.request_validator.timestamp_lifetime)))
+
+ # Provider specific validation of parameters, used to enforce
+ # restrictions such as character set and length.
+ if not self.request_validator.check_client_key(request.client_key):
+ raise errors.InvalidRequestError(
+ description='Invalid client key format.')
+
+ if not self.request_validator.check_nonce(request.nonce):
+ raise errors.InvalidRequestError(
+ description='Invalid nonce format.')
+
+ def _check_signature(self, request, is_token_request=False):
+ # ---- RSA Signature verification ----
+ if request.signature_method == SIGNATURE_RSA_SHA1 or \
+ request.signature_method == SIGNATURE_RSA_SHA256 or \
+ request.signature_method == SIGNATURE_RSA_SHA512:
+ # RSA-based signature method
+
+ # The server verifies the signature per `[RFC3447] section 8.2.2`_
+ # .. _`[RFC3447] section 8.2.2`: https://tools.ietf.org/html/rfc3447#section-8.2.1
+
+ rsa_key = self.request_validator.get_rsa_key(
+ request.client_key, request)
+
+ if request.signature_method == SIGNATURE_RSA_SHA1:
+ valid_signature = signature.verify_rsa_sha1(request, rsa_key)
+ elif request.signature_method == SIGNATURE_RSA_SHA256:
+ valid_signature = signature.verify_rsa_sha256(request, rsa_key)
+ elif request.signature_method == SIGNATURE_RSA_SHA512:
+ valid_signature = signature.verify_rsa_sha512(request, rsa_key)
+ else:
+ valid_signature = False
+
+ # ---- HMAC or Plaintext Signature verification ----
+ else:
+ # Non-RSA based signature method
+
+ # Servers receiving an authenticated request MUST validate it by:
+ # Recalculating the request signature independently as described in
+ # `Section 3.4`_ and comparing it to the value received from the
+ # client via the "oauth_signature" parameter.
+ # .. _`Section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4
+
+ client_secret = self.request_validator.get_client_secret(
+ request.client_key, request)
+
+ resource_owner_secret = None
+ if request.resource_owner_key:
+ if is_token_request:
+ resource_owner_secret = \
+ self.request_validator.get_request_token_secret(
+ request.client_key, request.resource_owner_key,
+ request)
+ else:
+ resource_owner_secret = \
+ self.request_validator.get_access_token_secret(
+ request.client_key, request.resource_owner_key,
+ request)
+
+ if request.signature_method == SIGNATURE_HMAC_SHA1:
+ valid_signature = signature.verify_hmac_sha1(
+ request, client_secret, resource_owner_secret)
+ elif request.signature_method == SIGNATURE_HMAC_SHA256:
+ valid_signature = signature.verify_hmac_sha256(
+ request, client_secret, resource_owner_secret)
+ elif request.signature_method == SIGNATURE_HMAC_SHA512:
+ valid_signature = signature.verify_hmac_sha512(
+ request, client_secret, resource_owner_secret)
+ elif request.signature_method == SIGNATURE_PLAINTEXT:
+ valid_signature = signature.verify_plaintext(
+ request, client_secret, resource_owner_secret)
+ else:
+ valid_signature = False
+
+ return valid_signature
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py
new file mode 100644
index 00000000..23e3cfc8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/pre_configured.py
@@ -0,0 +1,14 @@
+from . import (
+ AccessTokenEndpoint, AuthorizationEndpoint, RequestTokenEndpoint,
+ ResourceEndpoint,
+)
+
+
+class WebApplicationServer(RequestTokenEndpoint, AuthorizationEndpoint,
+ AccessTokenEndpoint, ResourceEndpoint):
+
+ def __init__(self, request_validator):
+ RequestTokenEndpoint.__init__(self, request_validator)
+ AuthorizationEndpoint.__init__(self, request_validator)
+ AccessTokenEndpoint.__init__(self, request_validator)
+ ResourceEndpoint.__init__(self, request_validator)
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py
new file mode 100644
index 00000000..0323cfb8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/request_token.py
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.request_token
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the request token provider logic of
+OAuth 1.0 RFC 5849. It validates the correctness of request token requests,
+creates and persists tokens as well as create the proper response to be
+returned to the client.
+"""
+import logging
+
+from oauthlib.common import urlencode
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class RequestTokenEndpoint(BaseEndpoint):
+
+ """An endpoint responsible for providing OAuth 1 request tokens.
+
+ Typical use is to instantiate with a request validator and invoke the
+ ``create_request_token_response`` from a view function. The tuple returned
+ has all information necessary (body, status, headers) to quickly form
+ and return a proper response. See :doc:`/oauth1/validator` for details on which
+ validator methods to implement for this endpoint.
+ """
+
+ def create_request_token(self, request, credentials):
+ """Create and save a new request token.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :param credentials: A dict of extra token credentials.
+ :returns: The token as an urlencoded string.
+ """
+ token = {
+ 'oauth_token': self.token_generator(),
+ 'oauth_token_secret': self.token_generator(),
+ 'oauth_callback_confirmed': 'true'
+ }
+ token.update(credentials)
+ self.request_validator.save_request_token(token, request)
+ return urlencode(token.items())
+
+ def create_request_token_response(self, uri, http_method='GET', body=None,
+ headers=None, credentials=None):
+ """Create a request token response, with a new request token if valid.
+
+ :param uri: The full URI of the token request.
+ :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+ :param body: The request body as a string.
+ :param headers: The request headers as a dict.
+ :param credentials: A list of extra credentials to include in the token.
+ :returns: A tuple of 3 elements.
+ 1. A dict of headers to set on the response.
+ 2. The response body as a string.
+ 3. The response status code as an integer.
+
+ An example of a valid request::
+
+ >>> from your_validator import your_validator
+ >>> from oauthlib.oauth1 import RequestTokenEndpoint
+ >>> endpoint = RequestTokenEndpoint(your_validator)
+ >>> h, b, s = endpoint.create_request_token_response(
+ ... 'https://your.provider/request_token?foo=bar',
+ ... headers={
+ ... 'Authorization': 'OAuth realm=movies user, oauth_....'
+ ... },
+ ... credentials={
+ ... 'my_specific': 'argument',
+ ... })
+ >>> h
+ {'Content-Type': 'application/x-www-form-urlencoded'}
+ >>> b
+ 'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_callback_confirmed=true&my_specific=argument'
+ >>> s
+ 200
+
+ An response to invalid request would have a different body and status::
+
+ >>> b
+ 'error=invalid_request&description=missing+callback+uri'
+ >>> s
+ 400
+
+ The same goes for an an unauthorized request:
+
+ >>> b
+ ''
+ >>> s
+ 401
+ """
+ resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
+ try:
+ request = self._create_request(uri, http_method, body, headers)
+ valid, processed_request = self.validate_request_token_request(
+ request)
+ if valid:
+ token = self.create_request_token(request, credentials or {})
+ return resp_headers, token, 200
+ else:
+ return {}, None, 401
+ except errors.OAuth1Error as e:
+ return resp_headers, e.urlencoded, e.status_code
+
+ def validate_request_token_request(self, request):
+ """Validate a request token request.
+
+ :param request: OAuthlib request.
+ :type request: oauthlib.common.Request
+ :raises: OAuth1Error if the request is invalid.
+ :returns: A tuple of 2 elements.
+ 1. The validation result (True or False).
+ 2. The request object.
+ """
+ self._check_transport_security(request)
+ self._check_mandatory_parameters(request)
+
+ if request.realm:
+ request.realms = request.realm.split(' ')
+ else:
+ request.realms = self.request_validator.get_default_realms(
+ request.client_key, request)
+ if not self.request_validator.check_realms(request.realms):
+ raise errors.InvalidRequestError(
+ description='Invalid realm {}. Allowed are {!r}.'.format(
+ request.realms, self.request_validator.realms))
+
+ if not request.redirect_uri:
+ raise errors.InvalidRequestError(
+ description='Missing callback URI.')
+
+ if not self.request_validator.validate_timestamp_and_nonce(
+ request.client_key, request.timestamp, request.nonce, request,
+ request_token=request.resource_owner_key):
+ return False, request
+
+ # The server SHOULD return a 401 (Unauthorized) status code when
+ # receiving a request with invalid client credentials.
+ # Note: This is postponed in order to avoid timing attacks, instead
+ # a dummy client is assigned and used to maintain near constant
+ # time request verification.
+ #
+ # Note that early exit would enable client enumeration
+ valid_client = self.request_validator.validate_client_key(
+ request.client_key, request)
+ if not valid_client:
+ request.client_key = self.request_validator.dummy_client
+
+ # Note that `realm`_ is only used in authorization headers and how
+ # it should be interpreted is not included in the OAuth spec.
+ # However they could be seen as a scope or realm to which the
+ # client has access and as such every client should be checked
+ # to ensure it is authorized access to that scope or realm.
+ # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2
+ #
+ # Note that early exit would enable client realm access enumeration.
+ #
+ # The require_realm indicates this is the first step in the OAuth
+ # workflow where a client requests access to a specific realm.
+ # This first step (obtaining request token) need not require a realm
+ # and can then be identified by checking the require_resource_owner
+ # flag and absence of realm.
+ #
+ # Clients obtaining an access token will not supply a realm and it will
+ # not be checked. Instead the previously requested realm should be
+ # transferred from the request token to the access token.
+ #
+ # Access to protected resources will always validate the realm but note
+ # that the realm is now tied to the access token and not provided by
+ # the client.
+ valid_realm = self.request_validator.validate_requested_realms(
+ request.client_key, request.realms, request)
+
+ # Callback is normally never required, except for requests for
+ # a Temporary Credential as described in `Section 2.1`_
+ # .._`Section 2.1`: https://tools.ietf.org/html/rfc5849#section-2.1
+ valid_redirect = self.request_validator.validate_redirect_uri(
+ request.client_key, request.redirect_uri, request)
+ if not request.redirect_uri:
+ raise NotImplementedError('Redirect URI must either be provided '
+ 'or set to a default during validation.')
+
+ valid_signature = self._check_signature(request)
+
+ # log the results to the validator_log
+ # this lets us handle internal reporting and analysis
+ request.validator_log['client'] = valid_client
+ request.validator_log['realm'] = valid_realm
+ request.validator_log['callback'] = valid_redirect
+ request.validator_log['signature'] = valid_signature
+
+ # We delay checking validity until the very end, using dummy values for
+ # calculations and fetching secrets/keys to ensure the flow of every
+ # request remains almost identical regardless of whether valid values
+ # have been supplied. This ensures near constant time execution and
+ # prevents malicious users from guessing sensitive information
+ v = all((valid_client, valid_realm, valid_redirect, valid_signature))
+ if not v:
+ log.info("[Failure] request verification failed.")
+ log.info("Valid client: %s.", valid_client)
+ log.info("Valid realm: %s.", valid_realm)
+ log.info("Valid callback: %s.", valid_redirect)
+ log.info("Valid signature: %s.", valid_signature)
+ return v, request
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py
new file mode 100644
index 00000000..8641152e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py
@@ -0,0 +1,163 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.resource
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the resource protection provider logic of
+OAuth 1.0 RFC 5849.
+"""
+import logging
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class ResourceEndpoint(BaseEndpoint):
+
+ """An endpoint responsible for protecting resources.
+
+ Typical use is to instantiate with a request validator and invoke the
+ ``validate_protected_resource_request`` in a decorator around a view
+ function. If the request is valid, invoke and return the response of the
+ view. If invalid create and return an error response directly from the
+ decorator.
+
+ See :doc:`/oauth1/validator` for details on which validator methods to implement
+ for this endpoint.
+
+ An example decorator::
+
+ from functools import wraps
+ from your_validator import your_validator
+ from oauthlib.oauth1 import ResourceEndpoint
+ endpoint = ResourceEndpoint(your_validator)
+
+ def require_oauth(realms=None):
+ def decorator(f):
+ @wraps(f)
+ def wrapper(request, *args, **kwargs):
+ v, r = provider.validate_protected_resource_request(
+ request.url,
+ http_method=request.method,
+ body=request.data,
+ headers=request.headers,
+ realms=realms or [])
+ if v:
+ return f(*args, **kwargs)
+ else:
+ return abort(403)
+ """
+
+ def validate_protected_resource_request(self, uri, http_method='GET',
+ body=None, headers=None, realms=None):
+ """Create a request token response, with a new request token if valid.
+
+ :param uri: The full URI of the token request.
+ :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+ :param body: The request body as a string.
+ :param headers: The request headers as a dict.
+ :param realms: A list of realms the resource is protected under.
+ This will be supplied to the ``validate_realms``
+ method of the request validator.
+ :returns: A tuple of 2 elements.
+ 1. True if valid, False otherwise.
+ 2. An oauthlib.common.Request object.
+ """
+ try:
+ request = self._create_request(uri, http_method, body, headers)
+ except errors.OAuth1Error:
+ return False, None
+
+ try:
+ self._check_transport_security(request)
+ self._check_mandatory_parameters(request)
+ except errors.OAuth1Error:
+ return False, request
+
+ if not request.resource_owner_key:
+ return False, request
+
+ if not self.request_validator.check_access_token(
+ request.resource_owner_key):
+ return False, request
+
+ if not self.request_validator.validate_timestamp_and_nonce(
+ request.client_key, request.timestamp, request.nonce, request,
+ access_token=request.resource_owner_key):
+ return False, request
+
+ # The server SHOULD return a 401 (Unauthorized) status code when
+ # receiving a request with invalid client credentials.
+ # Note: This is postponed in order to avoid timing attacks, instead
+ # a dummy client is assigned and used to maintain near constant
+ # time request verification.
+ #
+ # Note that early exit would enable client enumeration
+ valid_client = self.request_validator.validate_client_key(
+ request.client_key, request)
+ if not valid_client:
+ request.client_key = self.request_validator.dummy_client
+
+ # The server SHOULD return a 401 (Unauthorized) status code when
+ # receiving a request with invalid or expired token.
+ # Note: This is postponed in order to avoid timing attacks, instead
+ # a dummy token is assigned and used to maintain near constant
+ # time request verification.
+ #
+ # Note that early exit would enable resource owner enumeration
+ valid_resource_owner = self.request_validator.validate_access_token(
+ request.client_key, request.resource_owner_key, request)
+ if not valid_resource_owner:
+ request.resource_owner_key = self.request_validator.dummy_access_token
+
+ # Note that `realm`_ is only used in authorization headers and how
+ # it should be interpreted is not included in the OAuth spec.
+ # However they could be seen as a scope or realm to which the
+ # client has access and as such every client should be checked
+ # to ensure it is authorized access to that scope or realm.
+ # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2
+ #
+ # Note that early exit would enable client realm access enumeration.
+ #
+ # The require_realm indicates this is the first step in the OAuth
+ # workflow where a client requests access to a specific realm.
+ # This first step (obtaining request token) need not require a realm
+ # and can then be identified by checking the require_resource_owner
+ # flag and absence of realm.
+ #
+ # Clients obtaining an access token will not supply a realm and it will
+ # not be checked. Instead the previously requested realm should be
+ # transferred from the request token to the access token.
+ #
+ # Access to protected resources will always validate the realm but note
+ # that the realm is now tied to the access token and not provided by
+ # the client.
+ valid_realm = self.request_validator.validate_realms(request.client_key,
+ request.resource_owner_key, request, uri=request.uri,
+ realms=realms)
+
+ valid_signature = self._check_signature(request)
+
+ # log the results to the validator_log
+ # this lets us handle internal reporting and analysis
+ request.validator_log['client'] = valid_client
+ request.validator_log['resource_owner'] = valid_resource_owner
+ request.validator_log['realm'] = valid_realm
+ request.validator_log['signature'] = valid_signature
+
+ # We delay checking validity until the very end, using dummy values for
+ # calculations and fetching secrets/keys to ensure the flow of every
+ # request remains almost identical regardless of whether valid values
+ # have been supplied. This ensures near constant time execution and
+ # prevents malicious users from guessing sensitive information
+ v = all((valid_client, valid_resource_owner, valid_realm,
+ valid_signature))
+ if not v:
+ log.info("[Failure] request verification failed.")
+ log.info("Valid client: %s", valid_client)
+ log.info("Valid token: %s", valid_resource_owner)
+ log.info("Valid realm: %s", valid_realm)
+ log.info("Valid signature: %s", valid_signature)
+ return v, request
diff --git a/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py
new file mode 100644
index 00000000..d693ccb7
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/oauthlib/oauth1/rfc5849/endpoints/signature_only.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth1.rfc5849.endpoints.signature_only
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of the signing logic of OAuth 1.0 RFC 5849.
+"""
+
+import logging
+
+from .. import errors
+from .base import BaseEndpoint
+
+log = logging.getLogger(__name__)
+
+
+class SignatureOnlyEndpoint(BaseEndpoint):
+
+ """An endpoint only responsible for verifying an oauth signature."""
+
+ def validate_request(self, uri, http_method='GET',
+ body=None, headers=None):
+ """Validate a signed OAuth request.
+
+ :param uri: The full URI of the token request.
+ :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
+ :param body: The request body as a string.
+ :param headers: The request headers as a dict.
+ :returns: A tuple of 2 elements.
+ 1. True if valid, False otherwise.
+ 2. An oauthlib.common.Request object.
+ """
+ try:
+ request = self._create_request(uri, http_method, body, headers)
+ except errors.OAuth1Error as err:
+ log.info(
+ 'Exception caught while validating request, %s.' % err)
+ return False, None
+
+ try:
+ self._check_transport_security(request)
+ self._check_mandatory_parameters(request)
+ except errors.OAuth1Error as err:
+ log.info(
+ 'Exception caught while validating request, %s.' % err)
+ return False, request
+
+ if not self.request_validator.validate_timestamp_and_nonce(
+ request.client_key, request.timestamp, request.nonce, request):
+ log.debug('[Failure] verification failed: timestamp/nonce')
+ return False, request
+
+ # The server SHOULD return a 401 (Unauthorized) status code when
+ # receiving a request with invalid client credentials.
+ # Note: This is postponed in order to avoid timing attacks, instead
+ # a dummy client is assigned and used to maintain near constant
+ # time request verification.
+ #
+ # Note that early exit would enable client enumeration
+ valid_client = self.request_validator.validate_client_key(
+ request.client_key, request)
+ if not valid_client:
+ request.client_key = self.request_validator.dummy_client
+
+ valid_signature = self._check_signature(request)
+
+ # log the results to the validator_log
+ # this lets us handle internal reporting and analysis
+ request.validator_log['client'] = valid_client
+ request.validator_log['signature'] = valid_signature
+
+ # We delay checking validity until the very end, using dummy values for
+ # calculations and fetching secrets/keys to ensure the flow of every
+ # request remains almost identical regardless of whether valid values
+ # have been supplied. This ensures near constant time execution and
+ # prevents malicious users from guessing sensitive information
+ v = all((valid_client, valid_signature))
+ if not v:
+ log.info("[Failure] request verification failed.")
+ log.info("Valid client: %s", valid_client)
+ log.info("Valid signature: %s", valid_signature)
+ return v, request