Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(533)

Side by Side Diff: remoting/client/appengine/auth.py

Issue 7054029: Add in support for connecting with just the OAuth2 token. Default to OAuth2. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address Jamie's comments Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/client/appengine/api.py ('k') | remoting/client/appengine/chromoting_session.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Provides authentcation related utilities and endpoint handlers. 7 """Provides authentcation related utilities and endpoint handlers.
8 8
9 All authentication code for the webapp should go through this module. In 9 All authentication code for the webapp should go through this module. In
10 general, credentials should be used server-side. The URL endpoints are for 10 general, credentials should be used server-side. The URL endpoints are for
(...skipping 25 matching lines...) Expand all
36 CLIENT_ID = ('440925447803-d9u05st5jjm3gbe865l0jeaujqfrufrn.' 36 CLIENT_ID = ('440925447803-d9u05st5jjm3gbe865l0jeaujqfrufrn.'
37 'apps.googleusercontent.com') 37 'apps.googleusercontent.com')
38 CLIENT_SECRET = 'Nl4vSQEgDpPMP-1rDEsgs3V7' 38 CLIENT_SECRET = 'Nl4vSQEgDpPMP-1rDEsgs3V7'
39 39
40 40
41 class NotAuthenticated(Exception): 41 class NotAuthenticated(Exception):
42 """API requiring authentication is called with credentials.""" 42 """API requiring authentication is called with credentials."""
43 pass 43 pass
44 44
45 45
46 class XmppToken(db.Model): 46 class ClientLoginToken(db.Model):
47 auth_token = db.StringProperty() 47 auth_token = db.StringProperty()
48 48
49 49
50 class OAuth2Tokens(db.Model): 50 class OAuth2Tokens(db.Model):
51 """Stores the Refresh and Access token information for OAuth2.""" 51 """Stores the Refresh and Access token information for OAuth2."""
52 refresh_token = db.StringProperty() 52 refresh_token = db.StringProperty()
53 access_token = db.StringProperty() 53 access_token = db.StringProperty()
54 access_token_expiration = db.IntegerProperty() 54 access_token_expiration = db.IntegerProperty()
55 55
56 56
57 def HasOAuth2Tokens(throws=True): 57 def HasOAuth2Tokens(throws=True):
58 oauth2_tokens = OAuth2Tokens.get_or_insert(GetUserId()) 58 oauth2_tokens = OAuth2Tokens.get_or_insert(GetUserId())
59 if oauth2_tokens.refresh_token: 59 if oauth2_tokens.refresh_token:
60 return True; 60 return True;
61 return False; 61 return False;
62 62
63 63
64 def GetAccessToken(throws=True): 64 def GetOAuth2AccessToken(throws=True):
65 oauth2_tokens = OAuth2Tokens.get_or_insert(GetUserId()) 65 oauth2_tokens = OAuth2Tokens.get_or_insert(GetUserId())
66 66
67 if not oauth2_tokens.refresh_token: 67 if not oauth2_tokens.refresh_token:
68 raise NotAuthenticated() 68 raise NotAuthenticated()
69 69
70 if time.time() > oauth2_tokens.access_token_expiration: 70 if time.time() > oauth2_tokens.access_token_expiration:
71 form_fields = { 71 form_fields = {
72 'client_id' : CLIENT_ID, 72 'client_id' : CLIENT_ID,
73 'client_secret' : CLIENT_SECRET, 73 'client_secret' : CLIENT_SECRET,
74 'refresh_token' : oauth2_tokens.refresh_token, 74 'refresh_token' : oauth2_tokens.refresh_token,
(...skipping 11 matching lines...) Expand all
86 oauth_json = json.loads(result.content) 86 oauth_json = json.loads(result.content)
87 oauth2_tokens.access_token = oauth_json['access_token'] 87 oauth2_tokens.access_token = oauth_json['access_token']
88 # Give us 30 second buffer to hackily account for RTT on network request. 88 # Give us 30 second buffer to hackily account for RTT on network request.
89 oauth2_tokens.access_token_expiration = ( 89 oauth2_tokens.access_token_expiration = (
90 int(oauth_json['expires_in'] + time.time() - 30)) 90 int(oauth_json['expires_in'] + time.time() - 30))
91 oauth2_tokens.put() 91 oauth2_tokens.put()
92 92
93 return oauth2_tokens.access_token 93 return oauth2_tokens.access_token
94 94
95 95
96 def GetXmppToken(throws=True): 96 def GetClientLoginToken(throws=True):
97 """Retrieves the XMPP for Chromoting. 97 """Retrieves the ClientLogin for Chromoting.
98 98
99 Args: 99 Args:
100 throws: bool (optional) Default is True. Throws if no token. 100 throws: bool (optional) Default is True. Throws if no token.
101 101
102 Returns: 102 Returns:
103 The auth token for the current user. 103 The auth token for the current user.
104 """ 104 """
105 xmpp_token = XmppToken.get_or_insert(GetUserId()) 105 clientlogin_token = ClientLoginToken.get_or_insert(GetUserId())
106 if throws and not xmpp_token.auth_token: 106 if throws and not clientlogin_token.auth_token:
107 raise NotAuthenticated() 107 raise NotAuthenticated()
108 return xmpp_token.auth_token 108 return clientlogin_token.auth_token
109 109
110 110
111 def ClearXmppToken(): 111 def ClearClientLoginToken():
112 """Clears all Chromoting ClientLogin token state from the datastore.""" 112 """Clears all Chromoting ClientLogin token state from the datastore."""
113 db.delete(db.Key.from_path('XmppToken', GetUserId())) 113 db.delete(db.Key.from_path('ClientLoginToken', GetUserId()))
114 114
115 115
116 def ClearOAuth2Token(): 116 def ClearOAuth2Token():
117 """Clears all Chromoting ClientLogin token state from the datastore.""" 117 """Clears all Chromoting ClientLogin token state from the datastore."""
118 db.delete(db.Key.from_path('OAuth2Tokens', GetUserId())) 118 db.delete(db.Key.from_path('OAuth2Tokens', GetUserId()))
119 119
120 120
121 def GetUserId(): 121 def GetUserId():
122 """Retrieves the user id for the current user. 122 """Retrieves the user id for the current user.
123 123
124 Returns: 124 Returns:
125 A string with the user id of the logged in user. 125 A string with the user id of the logged in user.
126 126
127 Raises: 127 Raises:
128 NotAuthenticated if the user is not logged in, or missing an id. 128 NotAuthenticated if the user is not logged in, or missing an id.
129 """ 129 """
130 user = users.get_current_user() 130 user = users.get_current_user()
131 if not user: 131 if not user:
132 raise NotAuthenticated() 132 raise NotAuthenticated()
133 133
134 if not user.user_id(): 134 if not user.user_id():
135 raise NotAuthenticated('no e-mail with google account!') 135 raise NotAuthenticated('no e-mail with google account!')
136 136
137 return user.user_id() 137 return user.user_id()
138 138
139 139
140 class XmppAuthHandler(webapp.RequestHandler): 140 class ClientLoginAuthHandler(webapp.RequestHandler):
141 """Prompts Google Accounts credentials and retrieves a ClientLogin token. 141 """Prompts Google Accounts credentials and retrieves a ClientLogin token.
142 142
143 This class takes the user's plaintext username and password, and then 143 This class takes the user's plaintext username and password, and then
144 posts a request to ClientLogin to get the access token. 144 posts a request to ClientLogin to get the access token.
145 145
146 THIS CLASS SHOULD NOT EXIST. 146 THIS CLASS SHOULD NOT EXIST.
147 147
148 We should NOT be taking a user's Google Accounts credentials in our webapp. 148 We should NOT be taking a user's Google Accounts credentials in our webapp.
149 However, we need a ClientLogin token for jingle, and this is currently the 149 However, we need a ClientLogin token for jingle, and this is currently the
150 only known workaround. 150 only known workaround.
151 """ 151 """
152 @login_required 152 @login_required
153 def get(self): 153 def get(self):
154 ClearXmppToken() 154 ClearClientLoginToken()
155 path = os.path.join(os.path.dirname(__file__), 'client_login.html') 155 path = os.path.join(os.path.dirname(__file__), 'client_login.html')
156 self.response.out.write(template.render(path, {})) 156 self.response.out.write(template.render(path, {}))
157 157
158 def post(self): 158 def post(self):
159 email = self.request.get('username') 159 email = self.request.get('username')
160 password = self.request.get('password') 160 password = self.request.get('password')
161 form_fields = { 161 form_fields = {
162 'accountType' : 'HOSTED_OR_GOOGLE', 162 'accountType' : 'HOSTED_OR_GOOGLE',
163 'Email' : self.request.get('username'), 163 'Email' : self.request.get('username'),
164 'Passwd' : self.request.get('password'), 164 'Passwd' : self.request.get('password'),
165 'service' : 'chromiumsync', 165 'service' : 'chromiumsync',
166 'source' : 'chromoplex' 166 'source' : 'chromoplex'
167 } 167 }
168 form_data = urllib.urlencode(form_fields) 168 form_data = urllib.urlencode(form_fields)
169 result = urlfetch.fetch( 169 result = urlfetch.fetch(
170 url = 'https://www.google.com/accounts/ClientLogin', 170 url = 'https://www.google.com/accounts/ClientLogin',
171 payload = form_data, 171 payload = form_data,
172 method = urlfetch.POST, 172 method = urlfetch.POST,
173 headers = {'Content-Type': 'application/x-www-form-urlencoded'}) 173 headers = {'Content-Type': 'application/x-www-form-urlencoded'})
174 if result.status_code != 200: 174 if result.status_code != 200:
175 self.response.out.write(result.content) 175 self.response.out.write(result.content)
176 for i in result.headers: 176 for i in result.headers:
177 self.response.headers[i] = result.headers[i] 177 self.response.headers[i] = result.headers[i]
178 self.response.set_status(result.status_code) 178 self.response.set_status(result.status_code)
179 return 179 return
180 180
181 xmpp_token = XmppToken(key_name = GetUserId()) 181 clientlogin_token = ClientLoginToken(key_name = GetUserId())
182 xmpp_token.auth_token = re.search("Auth=(.*)", result.content).group(1) 182 clientlogin_token.auth_token = re.search(
183 xmpp_token.put() 183 "Auth=(.*)", result.content).group(1)
184 clientlogin_token.put()
184 self.redirect('/') 185 self.redirect('/')
185 186
186 187
187 class ClearXmppTokenHandler(webapp.RequestHandler): 188 class ClearClientLoginTokenHandler(webapp.RequestHandler):
188 """Endpoint for dropping the user's Xmpp token.""" 189 """Endpoint for dropping the user's ClientLogin token."""
189 @login_required 190 @login_required
190 def get(self): 191 def get(self):
191 ClearXmppToken() 192 ClearClientLoginToken()
192 self.redirect('/') 193 self.redirect('/')
193 194
194 195
195 class ClearOAuth2TokenHandler(webapp.RequestHandler): 196 class ClearOAuth2TokenHandler(webapp.RequestHandler):
196 """Endpoint for dropping the user's OAuth2 token.""" 197 """Endpoint for dropping the user's OAuth2 token."""
197 @login_required 198 @login_required
198 def get(self): 199 def get(self):
199 ClearOAuth2Token() 200 ClearOAuth2Token()
200 self.redirect('/') 201 self.redirect('/')
201 202
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 242
242 if state: 243 if state:
243 self.redirect(state) 244 self.redirect(state)
244 else: 245 else:
245 self.redirect('/') 246 self.redirect('/')
246 247
247 248
248 def main(): 249 def main():
249 application = webapp.WSGIApplication( 250 application = webapp.WSGIApplication(
250 [ 251 [
251 ('/auth/xmpp_auth', XmppAuthHandler), 252 ('/auth/clientlogin_auth', ClientLoginAuthHandler),
252 ('/auth/clear_xmpp_token', ClearXmppTokenHandler), 253 ('/auth/clear_clientlogin_token', ClearClientLoginTokenHandler),
253 ('/auth/clear_oauth2_token', ClearOAuth2TokenHandler), 254 ('/auth/clear_oauth2_token', ClearOAuth2TokenHandler),
254 ('/auth/oauth2_return', OAuth2ReturnHandler) 255 ('/auth/oauth2_return', OAuth2ReturnHandler)
255 ], 256 ],
256 debug=True) 257 debug=True)
257 util.run_wsgi_app(application) 258 util.run_wsgi_app(application)
258 259
259 260
260 if __name__ == '__main__': 261 if __name__ == '__main__':
261 main() 262 main()
OLDNEW
« no previous file with comments | « remoting/client/appengine/api.py ('k') | remoting/client/appengine/chromoting_session.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698