Initial implementation of OAuth1 request signing with OAuthLib
authorIdan Gazit <idan@gazit.me>
Thu, 12 Apr 2012 14:40:04 +0000 (17:40 +0300)
committerDonald Stufft <donald.stufft@gmail.com>
Tue, 1 May 2012 10:20:52 +0000 (06:20 -0400)
requests/auth.py
setup.py

index 353180a..f4a885a 100644 (file)
@@ -11,11 +11,13 @@ import time
 import hashlib
 
 from base64 import b64encode
+from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_RSA,
+    SIGNATURE_PLAINTEXT, SIGNATURE_TYPE_AUTH_HEADER, SIGNATURE_TYPE_QUERY,
+    SIGNATURE_TYPE_BODY)
 from .compat import urlparse, str
 from .utils import randombytes, parse_dict_header
 
 
-
 def _basic_auth_str(username, password):
     """Returns a Basic Auth string."""
 
@@ -29,6 +31,47 @@ class AuthBase(object):
         raise NotImplementedError('Auth hooks must be callable.')
 
 
+class OAuth1(AuthBase):
+    """Signs the request using OAuth 1 (RFC5849)"""
+    def __init__(self, client_key,
+            client_secret=None,
+            resource_owner_key=None,
+            resource_owner_secret=None,
+            callback_uri=None,
+            signature_method=SIGNATURE_HMAC,
+            signature_type=SIGNATURE_TYPE_AUTH_HEADER,
+            rsa_key=None, verifier=None):
+        self.client = Client(client_key, client_secret, resource_owner_key,
+            resource_owner_secret, callback_uri, signature_method,
+            signature_type, rsa_key, verifier)
+
+    def __call__(self, r):
+        if (r.files or
+            r.headers['Content-Type'] != 'application/x-www-form-urlencoded'):
+
+            # XXX TODO can we use body signatures with a non formencoded body?
+            if self.client.signature_type == SIGNATURE_TYPE_BODY:
+                raise ValueError('Body signatures may not be used with non-form-urlencoded content')
+
+            # Spec only specifies signing of application/x-www-form-urlencoded
+            # params. Files don't get signed either.
+            body = u''
+            alter_body = False  # we shouldn't touch the body
+        else:
+            body = r.data  # OAuthLib is cool with both strings and dicts.
+            if isinstance(str, body):
+                # XXX gross hack. We must pass unicode...
+                body = unicode(body, 'utf-8')
+            alter_body = True
+
+        full_url, new_body, headers = self.client.sign(r.url, unicode(r.method), body, r.headers)
+        r.url = full_url
+        if alter_body:
+            r.data = new_body
+        r.headers = headers
+        return r
+
+
 class HTTPBasicAuth(AuthBase):
     """Attaches HTTP Basic Authentication to the given Request object."""
     def __init__(self, username, password):
index 3133a97..b9a2565 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ if sys.argv[-1] == 'test':
     os.system('python tests/test_requests.py')
     sys.exit()
 
-required = ['certifi>=0.0.7',]
+required = ['certifi>=0.0.7','oauthlib']
 packages = [
     'requests',
     'requests.packages',