Permalink
Browse files

adding a LinkedIn example app, fixes #11

This updates rauth to v0.4.1 and fixes a bug wherein POSTing to a given
endpoint could not contain the oauth_verifier parameter. Now instead of
keeping a record of the verifier on the token object we assign it as a
property of the hook. This property is populated automatically: in the scope
of the hook's `__call__` method we introspect URL parameters and data, if we
find `oauth_verifier` in either this value is assigned to our hook instance
as a property. Otherwise this can be manually overridden by explicit
assignment.
  • Loading branch information...
1 parent e605bea commit f023e33db1a715d4a1194a19c0e30eec7e47f918 @maxcountryman maxcountryman committed May 9, 2012
Showing with 82 additions and 19 deletions.
  1. +48 −0 examples/linkedin-updates.py
  2. +1 −1 rauth/__init__.py
  3. +26 −9 rauth/hook.py
  4. +0 −2 rauth/oauth.py
  5. +7 −7 tests/test_hook.py
@@ -0,0 +1,48 @@
+from rauth.service import OAuth1Service
+
+LINKEDIN_API_BASE = 'http://api.linkedin.com/v1/'
+
+
+linkedin = OAuth1Service(
+ name='linkedin',
+ consumer_key='tjm826j6uzio',
+ consumer_secret='1XbHsC7UxtC6EzqW',
+ request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken',
+ authorize_url = 'https://api.linkedin.com/uas/oauth/authorize',
+ access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken')
+
+request_token, request_token_secret = \
+ linkedin.get_request_token(method='GET')
+
+authorize_url = linkedin.get_authorize_url(request_token)
+
+print 'Visit this URL in your browser: ' + authorize_url
+pin = raw_input('Enter PIN from browser: ')
+
+response = linkedin.get_access_token('POST',
+ request_token=request_token,
+ request_token_secret=request_token_secret,
+ data={'oauth_verifier': pin})
+
+data = response.content
+
+access_token = data['oauth_token']
+access_token_secret = data['oauth_token_secret']
+
+response = linkedin.get(
+ LINKEDIN_API_BASE + 'people/~/network/updates',
+ params={'type': 'SHAR',
+ 'format': 'json'},
+ access_token=access_token,
+ access_token_secret=access_token_secret)
+
+updates = response.content
+
+for i, update in enumerate(updates['values'], 1):
+ current_share = update['updateContent']['person']['currentShare']
+ person = current_share['author']['firstName'] + ' '
+ person += current_share['author']['lastName']
+ comment = current_share.get('comment', '')
+ if not comment:
+ comment = current_share['content']['description']
+ print '{0}. {1} - {2}'.format(i, person, comment)
View
@@ -6,4 +6,4 @@
'''
-__version__ = '0.4.0'
+__version__ = '0.4.1'
View
@@ -10,8 +10,8 @@
import random
from hashlib import sha1
+from urlparse import parse_qsl, urlsplit, urlunsplit
from urllib import quote
-from urlparse import urlsplit, urlunsplit
from rauth.oauth import HmacSha1Signature, Token, Consumer
@@ -63,6 +63,7 @@ class OAuth1Hook(object):
default.
'''
OAUTH_VERSION = '1.0'
+ verifier = None
def __init__(self, consumer_key, consumer_secret, access_token=None,
access_token_secret=None, header_auth=False, signature=None):
@@ -88,16 +89,31 @@ def __call__(self, request):
if isinstance(request.data, list):
request.data = dict(request.data)
+ # ad hoc determination of parameters datatype: we need to convert to a
+ # dict when dealing with proper querystrings
+ str_or_bytes = map(lambda x: type(x) in (str, bytes),
+ [request.params, request.data])
+ is_querystring = False not in str_or_bytes
+
+ # prepare a dictionary of both params and data
+ if is_querystring:
+ params_and_data = \
+ parse_qsl(request.params) + parse_qsl(request.data)
+ params_and_data = dict(params_and_data)
+ else:
+ params_and_data = dict(request.params, **request.data)
+
+ # set the verifier if we've been provided one
+ if 'oauth_verifier' in params_and_data.keys():
+ self.verifier = params_and_data['oauth_verifier']
+
# generate the necessary request params
request.oauth_params = self.oauth_params
# here we append an oauth_callback parameter if any
- if 'oauth_callback' in request.data:
+ if 'oauth_callback' in params_and_data.keys():
request.oauth_params['oauth_callback'] = \
- request.data.pop('oauth_callback')
- if 'oauth_callback' in request.params:
- request.oauth_params['oauth_callback'] = \
- request.params.pop('oauth_callback')
+ params_and_data['oauth_callback']
# this is used in the Normalize Request Parameters step
request.params_and_data = request.oauth_params.copy()
@@ -139,10 +155,11 @@ def oauth_params(self):
oauth_params['oauth_nonce'] = sha1(str(random.random())).hexdigest()
oauth_params['oauth_version'] = self.OAUTH_VERSION
- if self.token:
+ if self.token is not None:
oauth_params['oauth_token'] = self.token.key
- # this must be set upon recieving a verifier
- oauth_params['oauth_verifier'] = self.token.verifier or ''
+
+ if self.verifier is not None:
+ oauth_params['oauth_verifier'] = self.verifier
oauth_params['oauth_signature_method'] = self.signature.NAME
return oauth_params
View
@@ -15,8 +15,6 @@
class OAuthObject(object):
'''A base class for OAuth token objects.'''
- verifier = None
-
def __init__(self, key, secret):
self.key = key
self.secret = secret
View
@@ -102,13 +102,6 @@ def test_oauth_with_token(self):
self.assertTrue(oauth.token.key is not None)
self.assertTrue('oauth_token' in full_url)
self.assertEqual('321', self.request.oauth_params['oauth_token'])
- self.assertTrue('oauth_verifier' in full_url)
- self.assertEqual('', self.request.oauth_params['oauth_verifier'])
-
- # test with a verifier
- oauth.token.verifier = '4242'
- oauth(self.request)
- self.assertEqual('4242', self.request.oauth_params['oauth_verifier'])
def test_unique_nonce(self):
oauth = OAuth1Hook('123', '345')
@@ -173,3 +166,10 @@ def test_authorization_realm(self):
oauth(self.request)
self.assertTrue('OAuth realm="http://example.com/' in
self.request.headers['Authorization'])
+
+ def test_oauth_verifier(self):
+ oauth = OAuth1Hook('123', '345', '321', '654')
+ self.request.params = {'oauth_verifier': 'fake_verifier'}
+ oauth(self.request)
+ self.assertEqual(oauth.verifier, 'fake_verifier')
+ self.assertTrue('oauth_verifier' in self.request.full_url)

0 comments on commit f023e33

Please sign in to comment.