Skip to content

Commit 8b4d4b8

Browse files
committed
Removed the deprecated cgi.parse_qs() in favor of urlparse.parse_qs(). Added Consumer.__str__(). Added a working Client class built on top of httplib2.Http. Added initial tests for Client. Removed untested BC code. Added checks in Request.sign_request() for parameters oauth_consumer_key and oauth_token. Verify scheme is http or https.
1 parent 65c1ca0 commit 8b4d4b8

File tree

2 files changed

+120
-33
lines changed

2 files changed

+120
-33
lines changed

oauth/__init__.py

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222
THE SOFTWARE.
2323
"""
2424

25-
import cgi
2625
import urllib
2726
import time
2827
import random
2928
import urlparse
3029
import hmac
3130
import binascii
31+
import httplib2
3232

3333

3434
VERSION = '1.0' # Hi Blaine!
@@ -108,6 +108,14 @@ def __init__(self, key, secret):
108108
if self.key is None or self.secret is None:
109109
raise ValueError("Key and secret must be set.")
110110

111+
def __str__(self):
112+
data = {
113+
'oauth_consumer_key': self.key,
114+
'oauth_consumer_secret': self.secret
115+
}
116+
117+
return urllib.urlencode(data)
118+
111119

112120
class Token(object):
113121
"""An OAuth credential used to request authorization or a protected
@@ -184,7 +192,7 @@ def from_string(s):
184192
if not len(s):
185193
raise ValueError("Invalid parameter string.")
186194

187-
params = cgi.parse_qs(s, keep_blank_values=False)
195+
params = urlparse.parse_qs(s, keep_blank_values=False)
188196
if not len(params):
189197
raise ValueError("Invalid parameter string.")
190198

@@ -255,11 +263,16 @@ def __init__(self, method=HTTP_METHOD, url=None, parameters=None):
255263
def url(self, value):
256264
parts = urlparse.urlparse(value)
257265
scheme, netloc, path = parts[:3]
266+
258267
# Exclude default port numbers.
259268
if scheme == 'http' and netloc[-3:] == ':80':
260269
netloc = netloc[:-3]
261270
elif scheme == 'https' and netloc[-4:] == ':443':
262271
netloc = netloc[:-4]
272+
273+
if scheme != 'http' and scheme != 'https':
274+
raise ValueError("Unsupported URL %s (%s)." % (value, scheme))
275+
263276
value = '%s://%s%s' % (scheme, netloc, path)
264277
self.__dict__['url'] = value
265278

@@ -311,6 +324,13 @@ def get_normalized_parameters(self):
311324

312325
def sign_request(self, signature_method, consumer, token):
313326
"""Set the signature parameter to the result of sign."""
327+
328+
if 'oauth_consumer_key' not in self:
329+
self['oauth_consumer_key'] = consumer.key
330+
331+
if token and 'oauth_token' not in self:
332+
self['oauth_token'] = token.key
333+
314334
self['oauth_signature_method'] = signature_method.name
315335
self['oauth_signature'] = signature_method.sign(self, consumer, token)
316336

@@ -415,7 +435,7 @@ def _split_header(header):
415435
@staticmethod
416436
def _split_url_string(param_str):
417437
"""Turn URL string into parameters."""
418-
parameters = cgi.parse_qs(param_str, keep_blank_values=False)
438+
parameters = urlparse.parse_qs(param_str, keep_blank_values=False)
419439
for k, v in parameters.iteritems():
420440
parameters[k] = urllib.unquote(v[0])
421441
return parameters
@@ -515,32 +535,60 @@ def _check_timestamp(self, timestamp):
515535
'greater difference than threshold %d' % (timestamp, now, self.timestamp_threshold))
516536

517537

518-
class Client(object):
538+
class Client(httplib2.Http):
519539
"""OAuthClient is a worker to attempt to execute a request."""
520-
consumer = None
521-
token = None
522540

523-
def __init__(self, oauth_consumer, oauth_token):
524-
self.consumer = oauth_consumer
525-
self.token = oauth_token
541+
def __init__(self, consumer, token=None, cache=None, timeout=None,
542+
proxy_info=None):
526543

527-
def get_consumer(self):
528-
return self.consumer
544+
if consumer is not None and not isinstance(consumer, Consumer):
545+
raise ValueError("Invalid consumer.")
529546

530-
def get_token(self):
531-
return self.token
547+
if token is not None and not isinstance(token, Token):
548+
raise ValueError("Invalid token.")
532549

533-
def fetch_request_token(self, request):
534-
"""-> OAuthToken."""
535-
raise NotImplementedError
550+
self.consumer = consumer
551+
self.token = token
552+
self.method = SignatureMethod_HMAC_SHA1()
536553

537-
def fetch_access_token(self, request):
538-
"""-> OAuthToken."""
539-
raise NotImplementedError
554+
httplib2.Http.__init__(self, cache=cache, timeout=timeout,
555+
proxy_info=proxy_info)
540556

541-
def access_resource(self, request):
542-
"""-> Some protected resource."""
543-
raise NotImplementedError
557+
def set_signature_method(method):
558+
if not isinstance(method, SignatureMethod):
559+
raise ValueError("Invalid signature method.")
560+
561+
self.method = method
562+
563+
def request(self, uri, method="GET", body=None, headers=None,
564+
redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None):
565+
566+
if body and method == "POST":
567+
parameters = urlparse.parse_qs(body)
568+
elif method == "GET":
569+
parsed = urlparse.urlparse(uri)
570+
parameters = urlparse.parse_qs(parsed.query)
571+
else:
572+
parameters = None
573+
574+
req = Request.from_consumer_and_token(self.consumer, token=self.token,
575+
http_method=method, http_url=uri, parameters=parameters)
576+
577+
req.sign_request(self.method, self.consumer, self.token)
578+
579+
if method == "POST":
580+
body = req.to_postdata()
581+
elif method == "GET":
582+
uri = req.to_url()
583+
else:
584+
if headers is None:
585+
headers = {}
586+
587+
headers.update(req.to_header())
588+
589+
return httplib2.Http.request(self, uri, method=method, body=body,
590+
headers=headers, redirections=redirections,
591+
connection_type=connection_type)
544592

545593

546594
class SignatureMethod(object):
@@ -626,13 +674,3 @@ def sign(self, request, consumer, token):
626674
key, raw = self.signing_base(request, consumer, token)
627675
return raw
628676

629-
# Backwards compatibility
630-
OAuthError = Error
631-
OAuthToken = Token
632-
OAuthConsumer = Consumer
633-
OAuthRequest = Request
634-
OAuthServer = Server
635-
OAuthClient = Client
636-
OAuthSignatureMethod = SignatureMethod
637-
OAuthSignatureMethod_HMAC_SHA1 = SignatureMethod_HMAC_SHA1
638-
OAuthSignatureMethod_PLAINTEXT = SignatureMethod_PLAINTEXT

tests/test_oauth.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,55 @@ def test_missing_signature(self):
644644
request, consumer, token)
645645

646646

647+
# Request Token: http://oauth-sandbox.sevengoslings.net/request_token
648+
# Auth: http://oauth-sandbox.sevengoslings.net/authorize
649+
# Access Token: http://oauth-sandbox.sevengoslings.net/access_token
650+
# Two-legged: http://oauth-sandbox.sevengoslings.net/two_legged
651+
# Three-legged: http://oauth-sandbox.sevengoslings.net/three_legged
652+
# Key: bd37aed57e15df53
653+
# Secret: 0e9e6413a9ef49510a4f68ed02cd
647654
class TestClient(unittest.TestCase):
648-
pass
655+
# oauth_uris = {
656+
# 'request_token': '/request_token.php',
657+
# 'access_token': '/access_token.php'
658+
# }
659+
660+
oauth_uris = {
661+
'request_token': '/request_token',
662+
'authorize': '/authorize',
663+
'access_token': '/access_token',
664+
'two_legged': '/two_legged',
665+
'three_legged': '/three_legged'
666+
}
667+
668+
consumer_key = 'bd37aed57e15df53'
669+
consumer_secret = '0e9e6413a9ef49510a4f68ed02cd'
670+
host = 'http://oauth-sandbox.sevengoslings.net'
671+
672+
# host = "http://term.ie/oauth/example"
673+
# consumer_key = 'key'
674+
# consumer_secret = 'secret'
675+
676+
def setUp(self):
677+
self.consumer = oauth.Consumer(key=self.consumer_key,
678+
secret=self.consumer_secret)
679+
680+
def _uri(self, type):
681+
uri = self.oauth_uris.get(type)
682+
if uri is None:
683+
raise KeyError("%s is not a valid OAuth URI type." % type)
684+
685+
return "%s%s" % (self.host, uri)
686+
687+
def test_get_access_token(self):
688+
client = oauth.Client(self.consumer, None)
689+
resp, content = client.request(self._uri('request_token'), "GET")
690+
691+
self.assertEquals(int(resp['status']), 200)
692+
693+
def test_get_access_token(self):
694+
client = oauth.Client(self.consumer, None)
695+
resp, content = client.request(self._uri('request_token'), "POST")
696+
697+
self.assertEquals(int(resp['status']), 200)
649698

0 commit comments

Comments
 (0)