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

Benjamin Mako Hill || Want to submit a patch?