Moving over OAuth 1.0 to use Storage, and updating samples to handle token revocation.
This commit is contained in:
@@ -10,8 +10,10 @@ __author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||
|
||||
import pickle
|
||||
|
||||
from apiclient.oauth import Storage as BaseStorage
|
||||
|
||||
class Storage(object):
|
||||
|
||||
class Storage(BaseStorage):
|
||||
"""Store and retrieve a single credential to and from a file."""
|
||||
|
||||
def __init__(self, filename):
|
||||
@@ -29,6 +31,7 @@ class Storage(object):
|
||||
f.close()
|
||||
except:
|
||||
credentials = None
|
||||
credentials.set_store(self.put)
|
||||
|
||||
return credentials
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@ Utilities for making it easier to work with OAuth.
|
||||
|
||||
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||
|
||||
|
||||
import copy
|
||||
import httplib2
|
||||
import logging
|
||||
import oauth2 as oauth
|
||||
import urllib
|
||||
import urlparse
|
||||
|
||||
from anyjson import simplejson
|
||||
|
||||
try:
|
||||
@@ -36,6 +36,10 @@ class MissingParameter(Error):
|
||||
pass
|
||||
|
||||
|
||||
class CredentialsInvalidError(Error):
|
||||
pass
|
||||
|
||||
|
||||
def _abstract():
|
||||
raise NotImplementedError('You need to override this function')
|
||||
|
||||
@@ -84,6 +88,29 @@ class Flow(object):
|
||||
pass
|
||||
|
||||
|
||||
class Storage(object):
|
||||
"""Base class for all Storage objects.
|
||||
|
||||
Store and retrieve a single credential.
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
"""Retrieve credential.
|
||||
|
||||
Returns:
|
||||
apiclient.oauth.Credentials
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
def put(self, credentials):
|
||||
"""Write a credential.
|
||||
|
||||
Args:
|
||||
credentials: Credentials, the credentials to store.
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
|
||||
class OAuthCredentials(Credentials):
|
||||
"""Credentials object for OAuth 1.0a
|
||||
"""
|
||||
@@ -98,6 +125,39 @@ class OAuthCredentials(Credentials):
|
||||
self.consumer = consumer
|
||||
self.token = token
|
||||
self.user_agent = user_agent
|
||||
self.store = None
|
||||
|
||||
# True if the credentials have been revoked
|
||||
self._invalid = False
|
||||
|
||||
@property
|
||||
def invalid(self):
|
||||
"""True if the credentials are invalid, such as being revoked."""
|
||||
return getattr(self, "_invalid", False)
|
||||
|
||||
def set_store(self, store):
|
||||
"""Set the storage for the credential.
|
||||
|
||||
Args:
|
||||
store: callable, a callable that when passed a Credential
|
||||
will store the credential back to where it came from.
|
||||
This is needed to store the latest access_token if it
|
||||
has been revoked.
|
||||
"""
|
||||
self.store = store
|
||||
|
||||
def __getstate__(self):
|
||||
"""Trim the state down to something that can be pickled.
|
||||
"""
|
||||
d = copy.copy(self.__dict__)
|
||||
del d['store']
|
||||
return d
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""Reconstitute the state of the object from being pickled.
|
||||
"""
|
||||
self.__dict__.update(state)
|
||||
self.store = None
|
||||
|
||||
def authorize(self, http):
|
||||
"""
|
||||
@@ -148,6 +208,15 @@ class OAuthCredentials(Credentials):
|
||||
response_code = resp.status
|
||||
if response_code in [301, 302]:
|
||||
uri = resp['location']
|
||||
|
||||
# Update the stored credential if it becomes invalid.
|
||||
if response_code == 401:
|
||||
logging.info('Access token no longer valid: %s' % content)
|
||||
self._invalid = True
|
||||
if self.store is not None:
|
||||
self.store(self)
|
||||
raise CredentialsInvalidError("Credentials are no longer valid.")
|
||||
|
||||
return resp, content
|
||||
|
||||
http.request = new_request
|
||||
|
||||
@@ -208,7 +208,8 @@ class OAuth2Credentials(Credentials):
|
||||
d = simplejson.loads(content)
|
||||
if 'error' in d:
|
||||
self._invalid = True
|
||||
self.store(self)
|
||||
if self.store is not None:
|
||||
self.store(self)
|
||||
except:
|
||||
pass
|
||||
logging.error('Failed to retrieve access token: %s' % content)
|
||||
|
||||
@@ -14,7 +14,8 @@ __author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
||||
from apiclient.discovery import build
|
||||
from apiclient.oauth import FlowThreeLegged
|
||||
from apiclient.ext.authtools import run
|
||||
|
||||
from apiclient.ext.file import Storage
|
||||
from apiclient.oauth import CredentialsInvalidError
|
||||
|
||||
import httplib2
|
||||
import pickle
|
||||
@@ -25,11 +26,8 @@ import pprint
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
f = open("buzz.dat", "r")
|
||||
credentials = pickle.loads(f.read())
|
||||
f.close()
|
||||
except:
|
||||
credentials = Storage('buzz.dat').get()
|
||||
if credentials is None or credentials.invalid == True:
|
||||
buzz_discovery = build("buzz", "v1").auth_discovery()
|
||||
|
||||
flow = FlowThreeLegged(buzz_discovery,
|
||||
@@ -49,43 +47,49 @@ def main():
|
||||
developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
|
||||
activities = p.activities()
|
||||
|
||||
# Retrieve the first two activities
|
||||
activitylist = activities.list(
|
||||
max_results='2', scope='@self', userId='@me').execute()
|
||||
print "Retrieved the first two activities"
|
||||
try:
|
||||
# Retrieve the first two activities
|
||||
activitylist = activities.list(
|
||||
max_results='2', scope='@self', userId='@me').execute()
|
||||
print "Retrieved the first two activities"
|
||||
|
||||
# Retrieve the next two activities
|
||||
if activitylist:
|
||||
activitylist = activities.list_next(activitylist).execute()
|
||||
print "Retrieved the next two activities"
|
||||
# Retrieve the next two activities
|
||||
if activitylist:
|
||||
activitylist = activities.list_next(activitylist).execute()
|
||||
print "Retrieved the next two activities"
|
||||
|
||||
# Add a new activity
|
||||
new_activity_body = {
|
||||
"data": {
|
||||
'title': 'Testing insert',
|
||||
'object': {
|
||||
'content': u'Just a short note to show that insert is working. ☄',
|
||||
'type': 'note'}
|
||||
}
|
||||
}
|
||||
activity = activities.insert(userId='@me', body=new_activity_body).execute()
|
||||
print "Added a new activity"
|
||||
|
||||
activitylist = activities.list(
|
||||
max_results='2', scope='@self', userId='@me').execute()
|
||||
|
||||
# Add a comment to that activity
|
||||
comment_body = {
|
||||
"data": {
|
||||
"content": "This is a comment"
|
||||
# Add a new activity
|
||||
new_activity_body = {
|
||||
"data": {
|
||||
'title': 'Testing insert',
|
||||
'object': {
|
||||
'content':
|
||||
u'Just a short note to show that insert is working. ☄',
|
||||
'type': 'note'}
|
||||
}
|
||||
}
|
||||
item = activitylist['items'][0]
|
||||
comment = p.comments().insert(
|
||||
userId=item['actor']['id'], postId=item['id'], body=comment_body
|
||||
).execute()
|
||||
print 'Added a comment to the new activity'
|
||||
pprint.pprint(comment)
|
||||
}
|
||||
activity = activities.insert(
|
||||
userId='@me', body=new_activity_body).execute()
|
||||
print "Added a new activity"
|
||||
|
||||
activitylist = activities.list(
|
||||
max_results='2', scope='@self', userId='@me').execute()
|
||||
|
||||
# Add a comment to that activity
|
||||
comment_body = {
|
||||
"data": {
|
||||
"content": "This is a comment"
|
||||
}
|
||||
}
|
||||
item = activitylist['items'][0]
|
||||
comment = p.comments().insert(
|
||||
userId=item['actor']['id'], postId=item['id'], body=comment_body
|
||||
).execute()
|
||||
print 'Added a comment to the new activity'
|
||||
pprint.pprint(comment)
|
||||
except CredentialsInvalidError:
|
||||
print 'Your credentials are no longer valid.'
|
||||
print 'Please re-run this application to re-authorize.'
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
@@ -28,7 +28,7 @@ from apiclient.ext.file import Storage
|
||||
|
||||
def main():
|
||||
credentials = Storage('latitude.dat').get()
|
||||
if credentials is None:
|
||||
if credentials is None or credentials.invalid == True:
|
||||
auth_discovery = build("latitude", "v1").auth_discovery()
|
||||
flow = FlowThreeLegged(auth_discovery,
|
||||
# You MUST have a consumer key and secret tied to a
|
||||
|
||||
@@ -17,15 +17,14 @@ from apiclient.discovery import build
|
||||
from oauth2client.file import Storage
|
||||
from oauth2client.client import OAuth2WebServerFlow
|
||||
from oauth2client.tools import run
|
||||
from apiclient.oauth import CredentialsInvalidError
|
||||
|
||||
# Uncomment to get detailed logging
|
||||
#httplib2.debuglevel = 4
|
||||
|
||||
|
||||
def main():
|
||||
storage = Storage('latitude.dat')
|
||||
credentials = storage.get()
|
||||
|
||||
credentials = Storage('latitude.dat').get()
|
||||
if credentials is None or credentials.invalid:
|
||||
flow = OAuth2WebServerFlow(
|
||||
client_id='433807057907.apps.googleusercontent.com',
|
||||
@@ -50,7 +49,11 @@ def main():
|
||||
"altitude": 35
|
||||
}
|
||||
}
|
||||
print p.currentLocation().insert(body=body).execute()
|
||||
try:
|
||||
print p.currentLocation().insert(body=body).execute()
|
||||
except CredentialsInvalidError:
|
||||
print 'Your credentials are no longer valid.'
|
||||
print 'Please re-run this application to re-authorize.'
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user