oauth1_auth.py 3.6 KB

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