From 23a0d2f54c7090211cc772cf8e1f020a8d86fe83 Mon Sep 17 00:00:00 2001 From: Rob Kinyon Date: Fri, 25 Jan 2013 13:19:02 -0800 Subject: [PATCH 1/5] Remove usage of httplib2 constant in signature of Client.request() --- oauth2/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oauth2/__init__.py b/oauth2/__init__.py index 835270e3..6bb1fdfd 100644 --- a/oauth2/__init__.py +++ b/oauth2/__init__.py @@ -637,7 +637,7 @@ def set_signature_method(self, method): self.method = method def request(self, uri, method="GET", body='', headers=None, - redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None): + connection_type=None, **kwargs): DEFAULT_POST_CONTENT_TYPE = 'application/x-www-form-urlencoded' if not isinstance(headers, dict): @@ -677,9 +677,9 @@ def request(self, uri, method="GET", body='', headers=None, else: headers.update(req.to_header(realm=realm)) + kwargs['redirections'] = kwargs.get('redirections', httplib2.DEFAULT_MAX_REDIRECTS) return httplib2.Http.request(self, uri, method=method, body=body, - headers=headers, redirections=redirections, - connection_type=connection_type) + headers=headers, connection_type=connection_type, **kwargs) class Server(object): From 8c8ef7fc58ee6f87ea9fd56cc5cb4d3169e99510 Mon Sep 17 00:00:00 2001 From: Rob Kinyon Date: Fri, 25 Jan 2013 13:29:30 -0800 Subject: [PATCH 2/5] Broke out the signer code from the client code so that it can be reused more easily --- oauth2/__init__.py | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/oauth2/__init__.py b/oauth2/__init__.py index 6bb1fdfd..f411b048 100644 --- a/oauth2/__init__.py +++ b/oauth2/__init__.py @@ -618,6 +618,30 @@ class Client(httplib2.Http): def __init__(self, consumer, token=None, cache=None, timeout=None, proxy_info=None): + self.signer = Signer(consumer, token) + httplib2.Http.__init__(self, cache=cache, timeout=timeout, proxy_info=proxy_info) + + def set_signature_method(self, method): + self.signer.set_signature_method(method) + + def request(self, uri, method="GET", body='', headers=None, **kwargs): + ( method, uri, headers, body ) = self.signer.create_request( + uri, method=method, headers=headers, body=body, + ) + + # These are pass-through parameters that the old implementation defaulted + # to these values. + kwargs['redirections'] = kwargs.get('redirections', httplib2.DEFAULT_MAX_REDIRECTS) + kwargs['connection_type'] = kwargs.get('connection_type') + + return httplib2.Http.request( + self, uri, method=method, body=body, headers=headers, **kwargs + ) + +class Signer(object): + """Signer is the thing that converts the data into a sendable request.""" + + def __init__(self, consumer, token=None): if consumer is not None and not isinstance(consumer, Consumer): raise ValueError("Invalid consumer.") @@ -628,27 +652,24 @@ def __init__(self, consumer, token=None, cache=None, timeout=None, self.token = token self.method = SignatureMethod_HMAC_SHA1() - httplib2.Http.__init__(self, cache=cache, timeout=timeout, proxy_info=proxy_info) - def set_signature_method(self, method): if not isinstance(method, SignatureMethod): raise ValueError("Invalid signature method.") self.method = method - def request(self, uri, method="GET", body='', headers=None, - connection_type=None, **kwargs): - DEFAULT_POST_CONTENT_TYPE = 'application/x-www-form-urlencoded' + def create_request(self, uri, method="GET", headers=None, body=""): + DEFAULT_POST_CONTENT_TYPE = "application/x-www-form-urlencoded" if not isinstance(headers, dict): headers = {} if method == "POST": - headers['Content-Type'] = headers.get('Content-Type', - DEFAULT_POST_CONTENT_TYPE) + headers["Content-Type"] = headers.get( + "Content-Type", DEFAULT_POST_CONTENT_TYPE + ) - is_form_encoded = \ - headers.get('Content-Type') == 'application/x-www-form-urlencoded' + is_form_encoded = headers.get("Content-Type") == DEFAULT_POST_CONTENT_TYPE if is_form_encoded and body: parameters = parse_qs(body) @@ -677,10 +698,7 @@ def request(self, uri, method="GET", body='', headers=None, else: headers.update(req.to_header(realm=realm)) - kwargs['redirections'] = kwargs.get('redirections', httplib2.DEFAULT_MAX_REDIRECTS) - return httplib2.Http.request(self, uri, method=method, body=body, - headers=headers, connection_type=connection_type, **kwargs) - + return ( method, uri, headers, body ) class Server(object): """A skeletal implementation of a service provider, providing protected From 69fe654c7624f7dc0d9dc52c97ce9d63f4f83f45 Mon Sep 17 00:00:00 2001 From: Rob Kinyon Date: Fri, 25 Jan 2013 13:31:19 -0800 Subject: [PATCH 3/5] Minor cleanup --- oauth2/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/oauth2/__init__.py b/oauth2/__init__.py index f411b048..2a00dbcc 100644 --- a/oauth2/__init__.py +++ b/oauth2/__init__.py @@ -625,14 +625,14 @@ def set_signature_method(self, method): self.signer.set_signature_method(method) def request(self, uri, method="GET", body='', headers=None, **kwargs): - ( method, uri, headers, body ) = self.signer.create_request( + (method, uri, headers, body) = self.signer.create_request( uri, method=method, headers=headers, body=body, ) # These are pass-through parameters that the old implementation defaulted # to these values. kwargs['redirections'] = kwargs.get('redirections', httplib2.DEFAULT_MAX_REDIRECTS) - kwargs['connection_type'] = kwargs.get('connection_type') + kwargs['connection_type'] = kwargs.get('connection_type', None) return httplib2.Http.request( self, uri, method=method, body=body, headers=headers, **kwargs @@ -698,7 +698,8 @@ def create_request(self, uri, method="GET", headers=None, body=""): else: headers.update(req.to_header(realm=realm)) - return ( method, uri, headers, body ) + return (method, uri, headers, body) + class Server(object): """A skeletal implementation of a service provider, providing protected From d1b02a3f0f4ac40a70f06354035b6d3aecae48f8 Mon Sep 17 00:00:00 2001 From: Rob Kinyon Date: Fri, 25 Jan 2013 19:45:52 -0500 Subject: [PATCH 4/5] Refactored the Signer class out of the Client class so that it can be reused in Twisted and/or Tornado. --- oauth2/__init__.py | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/oauth2/__init__.py b/oauth2/__init__.py index 835270e3..2a00dbcc 100644 --- a/oauth2/__init__.py +++ b/oauth2/__init__.py @@ -618,6 +618,30 @@ class Client(httplib2.Http): def __init__(self, consumer, token=None, cache=None, timeout=None, proxy_info=None): + self.signer = Signer(consumer, token) + httplib2.Http.__init__(self, cache=cache, timeout=timeout, proxy_info=proxy_info) + + def set_signature_method(self, method): + self.signer.set_signature_method(method) + + def request(self, uri, method="GET", body='', headers=None, **kwargs): + (method, uri, headers, body) = self.signer.create_request( + uri, method=method, headers=headers, body=body, + ) + + # These are pass-through parameters that the old implementation defaulted + # to these values. + kwargs['redirections'] = kwargs.get('redirections', httplib2.DEFAULT_MAX_REDIRECTS) + kwargs['connection_type'] = kwargs.get('connection_type', None) + + return httplib2.Http.request( + self, uri, method=method, body=body, headers=headers, **kwargs + ) + +class Signer(object): + """Signer is the thing that converts the data into a sendable request.""" + + def __init__(self, consumer, token=None): if consumer is not None and not isinstance(consumer, Consumer): raise ValueError("Invalid consumer.") @@ -628,27 +652,24 @@ def __init__(self, consumer, token=None, cache=None, timeout=None, self.token = token self.method = SignatureMethod_HMAC_SHA1() - httplib2.Http.__init__(self, cache=cache, timeout=timeout, proxy_info=proxy_info) - def set_signature_method(self, method): if not isinstance(method, SignatureMethod): raise ValueError("Invalid signature method.") self.method = method - def request(self, uri, method="GET", body='', headers=None, - redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None): - DEFAULT_POST_CONTENT_TYPE = 'application/x-www-form-urlencoded' + def create_request(self, uri, method="GET", headers=None, body=""): + DEFAULT_POST_CONTENT_TYPE = "application/x-www-form-urlencoded" if not isinstance(headers, dict): headers = {} if method == "POST": - headers['Content-Type'] = headers.get('Content-Type', - DEFAULT_POST_CONTENT_TYPE) + headers["Content-Type"] = headers.get( + "Content-Type", DEFAULT_POST_CONTENT_TYPE + ) - is_form_encoded = \ - headers.get('Content-Type') == 'application/x-www-form-urlencoded' + is_form_encoded = headers.get("Content-Type") == DEFAULT_POST_CONTENT_TYPE if is_form_encoded and body: parameters = parse_qs(body) @@ -677,9 +698,7 @@ def request(self, uri, method="GET", body='', headers=None, else: headers.update(req.to_header(realm=realm)) - return httplib2.Http.request(self, uri, method=method, body=body, - headers=headers, redirections=redirections, - connection_type=connection_type) + return (method, uri, headers, body) class Server(object): From 7c1111d223dcbfe34ddd5bb2c7272f6575f768ff Mon Sep 17 00:00:00 2001 From: Rob Kinyon Date: Mon, 28 Jan 2013 14:47:33 -0800 Subject: [PATCH 5/5] Parameters are now lists as required by twisted and Signer.create_request() now accepts a parameter list --- oauth2/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/oauth2/__init__.py b/oauth2/__init__.py index 2a00dbcc..db6dd162 100644 --- a/oauth2/__init__.py +++ b/oauth2/__init__.py @@ -397,7 +397,7 @@ def to_header(self, realm=''): if params_header: auth_header = "%s, %s" % (auth_header, params_header) - return {'Authorization': auth_header} + return {'Authorization': [auth_header]} def to_postdata(self): """Serialize as post data for a POST request.""" @@ -658,23 +658,21 @@ def set_signature_method(self, method): self.method = method - def create_request(self, uri, method="GET", headers=None, body=""): + def create_request(self, uri, method="GET", headers=None, body="", parameters=None): DEFAULT_POST_CONTENT_TYPE = "application/x-www-form-urlencoded" if not isinstance(headers, dict): headers = {} if method == "POST": - headers["Content-Type"] = headers.get( + headers["Content-Type"] = [ headers.get( "Content-Type", DEFAULT_POST_CONTENT_TYPE - ) + ) ] - is_form_encoded = headers.get("Content-Type") == DEFAULT_POST_CONTENT_TYPE + is_form_encoded = headers.get("Content-Type") == [ DEFAULT_POST_CONTENT_TYPE ] if is_form_encoded and body: parameters = parse_qs(body) - else: - parameters = None req = Request.from_consumer_and_token(self.consumer, token=self.token, http_method=method, http_url=uri,