blob: 68a514b9c26ccb52dc97261145feb915b6e50422 [file] [log] [blame]
ade@google.com60a53c02011-01-10 02:33:17 +00001# Copyright (C) 2010 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from google.appengine.api import users
16from google.appengine.ext import db
17
18import apiclient.ext.appengine
19import logging
20import settings
21import simple_buzz_wrapper
22
23
24class Flow(db.Model):
25 flow = apiclient.ext.appengine.FlowThreeLeggedProperty()
26
27
28class Credentials(db.Model):
29 credentials = apiclient.ext.appengine.OAuthCredentialsProperty()
30
31
32def oauth_required(handler_method):
33 """A decorator to require that a user has gone through the OAuth dance before accessing a handler.
34
35 To use it, decorate your get() method like this:
36 @oauth_required
37 def get(self):
38 buzz_wrapper = oauth_handlers.build_buzz_wrapper_for_current_user()
39 user_profile_data = buzz_wrapper.get_profile()
40 self.response.out.write('Hello, ' + user_profile_data.displayName)
41
42 We will redirect the user to the OAuth endpoint and afterwards the OAuth
43 will send the user back to the DanceFinishingHandler that you have configured.
44 This should only used for GET requests since any payload in a POST request
45 will be lost. Any parameters in the original URL will be preserved.
46 """
47 def check_oauth_credentials(self, *args):
48 if self.request.method != 'GET':
49 raise webapp.Error('The check_oauth decorator can only be used for GET '
50 'requests')
51
52 # Is this a request from the OAuth system after finishing the OAuth dance?
53 if self.request.get('oauth_verifier'):
54 user = users.get_current_user()
55 logging.debug('Finished OAuth dance for: %s' % user.email())
56
57 f = Flow.get_by_key_name(user.user_id())
58 if f:
59 credentials = f.flow.step2_exchange(self.request.params)
60 c = Credentials(key_name=user.user_id(), credentials=credentials)
61 c.put()
62
63 # We delete the flow so that a malicious actor can't pretend to be the OAuth service
64 # and replace a valid token with an invalid token
65 f.delete()
66 handler_method(self, *args)
67 return
68
69 # Find out who the user is. If we don't know who you are then we can't
70 # look up your OAuth credentials thus we must ensure the user is logged in.
71 user = users.get_current_user()
72 if not user:
73 self.redirect(users.create_login_url(self.request.uri))
74 return
75
76 # Now that we know who the user is look up their OAuth credentials
77 # if we don't find the credentials then send them through the OAuth dance
78 if not Credentials.get_by_key_name(user.user_id()):
79 # TODO(ade) make this more configurable using settings.py
80 # Domain, and scope should be configurable
81 p = apiclient.discovery.build("buzz", "v1")
82 flow = apiclient.oauth.FlowThreeLegged(p.auth_discovery(),
83 consumer_key=settings.CONSUMER_KEY,
84 consumer_secret=settings.CONSUMER_SECRET,
85 user_agent='google-api-client-python-buzz-webapp/1.0',
86 domain='anonymous',
87 scope='https://www.googleapis.com/auth/buzz',
88 xoauth_displayname=settings.DISPLAY_NAME)
89
90 # The OAuth system needs to send the user right back here so that they
91 # get to the page they originally intended to visit.
92 oauth_return_url = self.request.uri
93 authorize_url = flow.step1_get_authorize_url(oauth_return_url)
94
95 f = Flow(key_name=user.user_id(), flow=flow)
96 f.put()
97
98 self.redirect(authorize_url)
99 return
100
101 # If the user already has a token then call the wrapped handler
102 handler_method(self, *args)
103 return check_oauth_credentials
104
105def build_buzz_wrapper_for_current_user():
106 user = users.get_current_user()
107 credentials = Credentials.get_by_key_name(user.user_id()).credentials
108 return simple_buzz_wrapper.SimpleBuzzWrapper(api_key=settings.API_KEY,
109 credentials=credentials)