Revised the decorator. Now all the parameters can be configured via the decorator.
There are sensible defaults for everything but the decorator can override them.
diff --git a/contrib/buzz/buzz_appengine.py b/contrib/buzz/buzz_appengine.py
index 68a514b..f8fc9d4 100644
--- a/contrib/buzz/buzz_appengine.py
+++ b/contrib/buzz/buzz_appengine.py
@@ -17,7 +17,6 @@
import apiclient.ext.appengine
import logging
-import settings
import simple_buzz_wrapper
@@ -29,81 +28,101 @@
credentials = apiclient.ext.appengine.OAuthCredentialsProperty()
-def oauth_required(handler_method):
- """A decorator to require that a user has gone through the OAuth dance before accessing a handler.
+class oauth_required(object):
+ def __init__(self, *decorator_args, **decorator_kwargs):
+ """A decorator to require that a user has gone through the OAuth dance before accessing a handler.
- To use it, decorate your get() method like this:
- @oauth_required
- def get(self):
- buzz_wrapper = oauth_handlers.build_buzz_wrapper_for_current_user()
- user_profile_data = buzz_wrapper.get_profile()
- self.response.out.write('Hello, ' + user_profile_data.displayName)
+ To use it, decorate your get() method like this:
+ @oauth_required
+ def get(self):
+ buzz_wrapper = oauth_handlers.build_buzz_wrapper_for_current_user()
+ user_profile_data = buzz_wrapper.get_profile()
+ self.response.out.write('Hello, ' + user_profile_data.displayName)
- We will redirect the user to the OAuth endpoint and afterwards the OAuth
- will send the user back to the DanceFinishingHandler that you have configured.
- This should only used for GET requests since any payload in a POST request
- will be lost. Any parameters in the original URL will be preserved.
- """
- def check_oauth_credentials(self, *args):
- if self.request.method != 'GET':
- raise webapp.Error('The check_oauth decorator can only be used for GET '
- 'requests')
+ We will redirect the user to the OAuth endpoint and afterwards the OAuth
+ will send the user back to the DanceFinishingHandler that you have configured.
+
+ This should only used for GET requests since any payload in a POST request
+ will be lost. Any parameters in the original URL will be preserved.
+ """
+ self.decorator_args = decorator_args
+ self.decorator_kwargs = decorator_kwargs
+
+ def __call__(self, handler_method):
+ def check_oauth_credentials_wrapper(*args, **kwargs):
+ handler_instance = args[0]
+ # TODO(ade) Add support for POST requests
+ if handler_instance.request.method != 'GET':
+ raise webapp.Error('The check_oauth decorator can only be used for GET '
+ 'requests')
- # Is this a request from the OAuth system after finishing the OAuth dance?
- if self.request.get('oauth_verifier'):
- user = users.get_current_user()
- logging.debug('Finished OAuth dance for: %s' % user.email())
+ # Is this a request from the OAuth system after finishing the OAuth dance?
+ if handler_instance.request.get('oauth_verifier'):
+ user = users.get_current_user()
+ logging.debug('Finished OAuth dance for: %s' % user.email())
- f = Flow.get_by_key_name(user.user_id())
- if f:
- credentials = f.flow.step2_exchange(self.request.params)
- c = Credentials(key_name=user.user_id(), credentials=credentials)
- c.put()
+ f = Flow.get_by_key_name(user.user_id())
+ if f:
+ credentials = f.flow.step2_exchange(handler_instance.request.params)
+ c = Credentials(key_name=user.user_id(), credentials=credentials)
+ c.put()
- # We delete the flow so that a malicious actor can't pretend to be the OAuth service
- # and replace a valid token with an invalid token
- f.delete()
- handler_method(self, *args)
- return
+ # We delete the flow so that a malicious actor can't pretend to be the OAuth service
+ # and replace a valid token with an invalid token
+ f.delete()
+
+ handler_method(*args)
+ return
- # Find out who the user is. If we don't know who you are then we can't
- # look up your OAuth credentials thus we must ensure the user is logged in.
- user = users.get_current_user()
- if not user:
- self.redirect(users.create_login_url(self.request.uri))
- return
+ # Find out who the user is. If we don't know who you are then we can't
+ # look up your OAuth credentials thus we must ensure the user is logged in.
+ user = users.get_current_user()
+ if not user:
+ handler_instance.redirect(users.create_login_url(handler_instance.request.uri))
+ return
- # Now that we know who the user is look up their OAuth credentials
- # if we don't find the credentials then send them through the OAuth dance
- if not Credentials.get_by_key_name(user.user_id()):
- # TODO(ade) make this more configurable using settings.py
- # Domain, and scope should be configurable
- p = apiclient.discovery.build("buzz", "v1")
- flow = apiclient.oauth.FlowThreeLegged(p.auth_discovery(),
- consumer_key=settings.CONSUMER_KEY,
- consumer_secret=settings.CONSUMER_SECRET,
- user_agent='google-api-client-python-buzz-webapp/1.0',
- domain='anonymous',
- scope='https://www.googleapis.com/auth/buzz',
- xoauth_displayname=settings.DISPLAY_NAME)
+ # Now that we know who the user is look up their OAuth credentials
+ # if we don't find the credentials then send them through the OAuth dance
+ if not Credentials.get_by_key_name(user.user_id()):
+
+ # Set up the default arguments and override them with whatever values have been given to the decorator
+ flow_settings = {
+ 'consumer_key' : 'anonymous',
+ 'consumer_secret' : 'anonymous',
+ 'user_agent' : 'google-api-client-python-buzz-webapp/1.0',
+ 'domain' : 'anonymous',
+ 'scope' : 'https://www.googleapis.com/auth/buzz',
+ 'xoauth_display_name' : 'Default Display Name For OAuth Application'
+ }
+
+ flow_settings.update(self.decorator_kwargs)
+
+ p = apiclient.discovery.build("buzz", "v1")
+ flow = apiclient.oauth.FlowThreeLegged(p.auth_discovery(),
+ consumer_key=flow_settings['consumer_key'],
+ consumer_secret=flow_settings['consumer_secret'],
+ user_agent=flow_settings['user_agent'],
+ domain=flow_settings['domain'],
+ scope=flow_settings['scope'],
+ xoauth_displayname=flow_settings['xoauth_display_name'])
- # The OAuth system needs to send the user right back here so that they
- # get to the page they originally intended to visit.
- oauth_return_url = self.request.uri
- authorize_url = flow.step1_get_authorize_url(oauth_return_url)
+ # The OAuth system needs to send the user right back here so that they
+ # get to the page they originally intended to visit.
+ oauth_return_url = handler_instance.request.uri
+ authorize_url = flow.step1_get_authorize_url(oauth_return_url)
- f = Flow(key_name=user.user_id(), flow=flow)
- f.put()
+ f = Flow(key_name=user.user_id(), flow=flow)
+ f.put()
- self.redirect(authorize_url)
- return
+ handler_instance.redirect(authorize_url)
+ return
- # If the user already has a token then call the wrapped handler
- handler_method(self, *args)
- return check_oauth_credentials
+ # If the user already has a token then call the wrapped handler
+ handler_method(*args)
+ return check_oauth_credentials_wrapper
-def build_buzz_wrapper_for_current_user():
+def build_buzz_wrapper_for_current_user(api_key):
user = users.get_current_user()
credentials = Credentials.get_by_key_name(user.user_id()).credentials
- return simple_buzz_wrapper.SimpleBuzzWrapper(api_key=settings.API_KEY,
+ return simple_buzz_wrapper.SimpleBuzzWrapper(api_key=api_key,
credentials=credentials)
\ No newline at end of file