signature_only.py 3.0 KB

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