signature_only.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. # -*- coding: utf-8 -*-
  2. """
  3. oauthlib.oauth1.rfc5849.endpoints.signature_only
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. This module is an implementation of the signing logic of OAuth 1.0 RFC 5849.
  6. """
  7. import logging
  8. from .. import errors
  9. from .base import BaseEndpoint
  10. log = logging.getLogger(__name__)
  11. class SignatureOnlyEndpoint(BaseEndpoint):
  12. """An endpoint only responsible for verifying an oauth signature."""
  13. def validate_request(self, uri, http_method='GET',
  14. body=None, headers=None):
  15. """Validate a signed OAuth request.
  16. :param uri: The full URI of the token request.
  17. :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
  18. :param body: The request body as a string.
  19. :param headers: The request headers as a dict.
  20. :returns: A tuple of 2 elements.
  21. 1. True if valid, False otherwise.
  22. 2. An oauthlib.common.Request object.
  23. """
  24. try:
  25. request = self._create_request(uri, http_method, body, headers)
  26. except errors.OAuth1Error as err:
  27. log.info(
  28. 'Exception caught while validating request, %s.' % err)
  29. return False, None
  30. try:
  31. self._check_transport_security(request)
  32. self._check_mandatory_parameters(request)
  33. except errors.OAuth1Error as err:
  34. log.info(
  35. 'Exception caught while validating request, %s.' % err)
  36. return False, request
  37. if not self.request_validator.validate_timestamp_and_nonce(
  38. request.client_key, request.timestamp, request.nonce, request):
  39. log.debug('[Failure] verification failed: timestamp/nonce')
  40. return False, request
  41. # The server SHOULD return a 401 (Unauthorized) status code when
  42. # receiving a request with invalid client credentials.
  43. # Note: This is postponed in order to avoid timing attacks, instead
  44. # a dummy client is assigned and used to maintain near constant
  45. # time request verification.
  46. #
  47. # Note that early exit would enable client enumeration
  48. valid_client = self.request_validator.validate_client_key(
  49. request.client_key, request)
  50. if not valid_client:
  51. request.client_key = self.request_validator.dummy_client
  52. valid_signature = self._check_signature(request)
  53. # log the results to the validator_log
  54. # this lets us handle internal reporting and analysis
  55. request.validator_log['client'] = valid_client
  56. request.validator_log['signature'] = valid_signature
  57. # We delay checking validity until the very end, using dummy values for
  58. # calculations and fetching secrets/keys to ensure the flow of every
  59. # request remains almost identical regardless of whether valid values
  60. # have been supplied. This ensures near constant time execution and
  61. # prevents malicious users from guessing sensitive information
  62. v = all((valid_client, valid_signature))
  63. if not v:
  64. log.info("[Failure] request verification failed.")
  65. log.info("Valid client: %s", valid_client)
  66. log.info("Valid signature: %s", valid_signature)
  67. return v, request