Cleaned up OAuth 2.0 support fully using Storage() and updating samples.
diff --git a/oauth2client/appengine.py b/oauth2client/appengine.py
index 80c6fab..f35da8f 100644
--- a/oauth2client/appengine.py
+++ b/oauth2client/appengine.py
@@ -25,6 +25,7 @@
from google.appengine.ext import db
from client import Credentials
from client import Flow
+from client import Storage
class FlowProperty(db.Property):
@@ -90,7 +91,7 @@
return not value
-class StorageByKeyName(object):
+class StorageByKeyName(Storage):
"""Store and retrieve a single credential to and from
the App Engine datastore.
diff --git a/oauth2client/client.py b/oauth2client/client.py
index eeaa453..5ba7af8 100644
--- a/oauth2client/client.py
+++ b/oauth2client/client.py
@@ -70,6 +70,30 @@
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 OAuth2Credentials(Credentials):
"""Credentials object for OAuth 2.0
diff --git a/oauth2client/django_orm.py b/oauth2client/django_orm.py
index 50b3dd6..b5e020e 100644
--- a/oauth2client/django_orm.py
+++ b/oauth2client/django_orm.py
@@ -1,5 +1,5 @@
from django.db import models
-
+from oauth2client.client import Storage as BaseStorage
class CredentialsField(models.Field):
@@ -36,3 +36,50 @@
def get_db_prep_value(self, value):
return base64.b64encode(pickle.dumps(value))
+
+
+class Storage(BaseStorage):
+ """Store and retrieve a single credential to and from
+ the datastore.
+
+ This Storage helper presumes the Credentials
+ have been stored as a CredenialsField
+ on a db model class.
+ """
+
+ def __init__(self, model_class, key_name, key_value, property_name):
+ """Constructor for Storage.
+
+ Args:
+ model: db.Model, model class
+ key_name: string, key name for the entity that has the credentials
+ key_value: string, key value for the entity that has the credentials
+ property_name: string, name of the property that is an CredentialsProperty
+ """
+ self.model_class = model_class
+ self.key_name = key_name
+ self.key_value = key_value
+ self.property_name = property_name
+
+ def get(self):
+ """Retrieve Credential from datastore.
+
+ Returns:
+ oauth2client.Credentials
+ """
+ query = {self.key_name: self.key_value}
+ entity = self.model_class.objects.filter(*query)[0]
+ credential = getattr(entity, self.property_name)
+ if credential and hasattr(credential, 'set_store'):
+ credential.set_store(self.put)
+ return credential
+
+ def put(self, credentials):
+ """Write a Credentials to the datastore.
+
+ Args:
+ credentials: Credentials, the credentials to store.
+ """
+ entity = self.model_class(self.key_name=self.key_value)
+ setattr(entity, self.property_name, credentials)
+ entity.save()
diff --git a/oauth2client/file.py b/oauth2client/file.py
index e0e3997..0bcab03 100644
--- a/oauth2client/file.py
+++ b/oauth2client/file.py
@@ -10,8 +10,10 @@
import pickle
+from client 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):
@@ -23,10 +25,13 @@
Returns:
apiclient.oauth.Credentials
"""
- f = open(self.filename, 'r')
- credentials = pickle.loads(f.read())
- f.close()
- credentials.set_store(self.put)
+ try:
+ f = open(self.filename, 'r')
+ credentials = pickle.loads(f.read())
+ f.close()
+ credentials.set_store(self.put)
+ except:
+ credentials = None
return credentials
def put(self, credentials):
@@ -38,5 +43,3 @@
f = open(self.filename, 'w')
f.write(pickle.dumps(credentials))
f.close()
-
-
diff --git a/oauth2client/tools.py b/oauth2client/tools.py
index d541eeb..644e72b 100644
--- a/oauth2client/tools.py
+++ b/oauth2client/tools.py
@@ -23,111 +23,16 @@
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
__all__ = ["run"]
-import socket
-import sys
-import BaseHTTPServer
-import logging
-from optparse import OptionParser
-from oauth2client.file import Storage
-
-try:
- from urlparse import parse_qsl
-except ImportError:
- from cgi import parse_qsl
-
-# TODO(jcgregorio)
-# - docs
-# - error handling
-
-HOST_NAME = 'localhost'
-PORT_NUMBERS = [8080, 8090]
-
-class ClientRedirectServer(BaseHTTPServer.HTTPServer):
- """A server to handle OAuth 2.0 redirects back to localhost.
-
- Waits for a single request and parses the query parameters
- into query_params and then stops serving.
- """
- query_params = {}
-
-class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- """A handler for OAuth 2.0 redirects back to localhost.
-
- Waits for a single request and parses the query parameters
- into the servers query_params and then stops serving.
- """
-
- def do_GET(s):
- """Handle a GET request
-
- Checks the query parameters and if an error
- occurred print a message of failure, otherwise
- indicate success.
- """
- s.send_response(200)
- s.send_header("Content-type", "text/html")
- s.end_headers()
- query = s.path.split('?', 1)[-1]
- query = dict(parse_qsl(query))
- s.server.query_params = query
- s.wfile.write("<html><head><title>Authentication Status</title></head>")
- if 'error' in query:
- s.wfile.write("<body><p>The authentication request failed.</p>")
- else:
- s.wfile.write("<body><p>You have successfully authenticated</p>")
- s.wfile.write("</body></html>")
-
- def log_message(self, format, *args):
- """Do not log messages to stdout while running as a command line program."""
- pass
-
-def run(flow, filename):
+def run(flow, storage):
"""Core code for a command-line application.
"""
- parser = OptionParser()
- parser.add_option("-f", "--file", dest="filename",
- default=filename, help="write credentials to FILE", metavar="FILE")
-
- # The support for localhost is a work in progress and does not
- # work at this point.
- #parser.add_option("-p", "--no_local_web_server", dest="localhost",
- # action="store_false",
- # default=True,
- # help="Do not run a web server on localhost to handle redirect URIs")
-
- (options, args) = parser.parse_args()
-
-#if options.localhost:
-# server_class = BaseHTTPServer.HTTPServer
-# try:
-# port_number = PORT_NUMBERS[0]
-# httpd = server_class((HOST_NAME, port_number), ClientRedirectHandler)
-# except socket.error:
-# port_number = PORT_NUMBERS[1]
-# try:
-# httpd = server_class((HOST_NAME, port_number), ClientRedirectHandler)
-# except socket.error:
-# options.localhost = False
-# redirect_uri = 'http://%s:%s/' % (HOST_NAME, port_number)
-#else:
-# redirect_uri = 'oob'
-
- redirect_uri = 'oob'
-
- authorize_url = flow.step1_get_authorize_url(redirect_uri)
+ authorize_url = flow.step1_get_authorize_url('oob')
print 'Go to the following link in your browser:'
print authorize_url
print
-#if options.localhost:
-# httpd.handle_request()
-# if 'error' in httpd.query_params:
-# sys.exit('Authentication request was rejected.')
-# if 'code' in httpd.query_params:
-# code = httpd.query_params['code']
-#else:
accepted = 'n'
while accepted.lower() == 'n':
accepted = raw_input('Have you authorized me? (y/n) ')
@@ -135,5 +40,9 @@
credentials = flow.step2_exchange(code)
- Storage(options.filename).put(credentials)
- print "You have successfully authenticated."
+ storage.put(credentials)
+ credentials.set_store(storage.put)
+
+ print 'You have successfully authenticated.'
+
+ return credentials