oauth1_auth.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. # -*- coding: utf-8 -*-
  2. import logging
  3. from oauthlib.common import extract_params
  4. from oauthlib.oauth1 import Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER
  5. from oauthlib.oauth1 import SIGNATURE_TYPE_BODY
  6. from requests.utils import to_native_string
  7. from requests.auth import AuthBase
  8. CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded"
  9. CONTENT_TYPE_MULTI_PART = "multipart/form-data"
  10. log = logging.getLogger(__name__)
  11. # OBS!: Correct signing of requests are conditional on invoking OAuth1
  12. # as the last step of preparing a request, or at least having the
  13. # content-type set properly.
  14. class OAuth1(AuthBase):
  15. """Signs the request using OAuth 1 (RFC5849)"""
  16. client_class = Client
  17. def __init__(
  18. self,
  19. client_key,
  20. client_secret=None,
  21. resource_owner_key=None,
  22. resource_owner_secret=None,
  23. callback_uri=None,
  24. signature_method=SIGNATURE_HMAC,
  25. signature_type=SIGNATURE_TYPE_AUTH_HEADER,
  26. rsa_key=None,
  27. verifier=None,
  28. decoding="utf-8",
  29. client_class=None,
  30. force_include_body=False,
  31. **kwargs
  32. ):
  33. try:
  34. signature_type = signature_type.upper()
  35. except AttributeError:
  36. pass
  37. client_class = client_class or self.client_class
  38. self.force_include_body = force_include_body
  39. self.client = client_class(
  40. client_key,
  41. client_secret,
  42. resource_owner_key,
  43. resource_owner_secret,
  44. callback_uri,
  45. signature_method,
  46. signature_type,
  47. rsa_key,
  48. verifier,
  49. decoding=decoding,
  50. **kwargs
  51. )
  52. def __call__(self, r):
  53. """Add OAuth parameters to the request.
  54. Parameters may be included from the body if the content-type is
  55. urlencoded, if no content type is set a guess is made.
  56. """
  57. # Overwriting url is safe here as request will not modify it past
  58. # this point.
  59. log.debug("Signing request %s using client %s", r, self.client)
  60. content_type = r.headers.get("Content-Type", "")
  61. if (
  62. not content_type
  63. and extract_params(r.body)
  64. or self.client.signature_type == SIGNATURE_TYPE_BODY
  65. ):
  66. content_type = CONTENT_TYPE_FORM_URLENCODED
  67. if not isinstance(content_type, str):
  68. content_type = content_type.decode("utf-8")
  69. is_form_encoded = CONTENT_TYPE_FORM_URLENCODED in content_type
  70. log.debug(
  71. "Including body in call to sign: %s",
  72. is_form_encoded or self.force_include_body,
  73. )
  74. if is_form_encoded:
  75. r.headers["Content-Type"] = CONTENT_TYPE_FORM_URLENCODED
  76. r.url, headers, r.body = self.client.sign(
  77. str(r.url), str(r.method), r.body or "", r.headers
  78. )
  79. elif self.force_include_body:
  80. # To allow custom clients to work on non form encoded bodies.
  81. r.url, headers, r.body = self.client.sign(
  82. str(r.url), str(r.method), r.body or "", r.headers
  83. )
  84. else:
  85. # Omit body data in the signing of non form-encoded requests
  86. r.url, headers, _ = self.client.sign(
  87. str(r.url), str(r.method), None, r.headers
  88. )
  89. r.prepare_headers(headers)
  90. r.url = to_native_string(r.url)
  91. log.debug("Updated url: %s", r.url)
  92. log.debug("Updated headers: %s", headers)
  93. log.debug("Updated body: %r", r.body)
  94. return r