OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Utilities for generating and verifying user authentication.""" | |
6 | |
7 __author__ = 'agable@google.com (Aaron Gable)' | |
8 | |
9 | |
10 import functools | |
11 import logging | |
12 | |
13 from google.appengine.api import users | |
14 from google.appengine.ext import ndb | |
15 | |
16 import constants | |
17 import model | |
18 | |
19 | |
20 def CheckUserAuth(handler): | |
21 """Decorator for webapp2 request handler methods. | |
22 | |
23 Only use on webapp2.RequestHandler methods (e.g. get, post, put). | |
24 | |
25 Checks to see if the user is logged in, and if they are | |
26 * If they are an administrator of the app, or | |
27 * If their email appears in the list of allowed addresses | |
28 | |
29 Sets request.authenticated to 'user' if successful. Otherwise, None. | |
30 """ | |
31 @functools.wraps(handler) | |
32 def wrapper(self, *args, **kwargs): | |
33 """Does the real legwork and calls the wrapped handler.""" | |
34 def abort_auth(log_msg): | |
35 """Helper method to be an exit hatch when authentication fails.""" | |
36 logging.warning(log_msg) | |
37 self.request.authenticated = None | |
38 handler(self, *args, **kwargs) | |
39 | |
40 def finish_auth(log_msg): | |
41 """Helper method to be an exit hatch when authentication succeeds.""" | |
42 logging.info(log_msg) | |
43 self.request.authenticated = 'user' | |
44 handler(self, *args, **kwargs) | |
iannucci
2013/10/09 18:57:30
Should these return the value of handler (and we s
agable
2013/10/09 19:12:31
webapp2 doesn't require or even want handlers to r
| |
45 | |
46 if getattr(self.request, 'authenticated', None): | |
47 finish_auth('Already authenticated.') | |
48 return | |
iannucci
2013/10/09 18:57:30
I would just make the else: on here set authentica
agable
2013/10/09 19:12:31
Not sure I agree with this. I think the current st
| |
49 | |
50 user = users.get_current_user() | |
51 if not user: | |
52 abort_auth('No logged in user.') | |
53 return | |
54 | |
55 if users.is_current_user_admin(): | |
56 finish_auth('User is admin.') | |
57 return | |
58 | |
59 email = user.email() | |
60 email_list = ndb.Key(model.EmailList, constants.LIST).get() | |
61 allowed_emails = email_list.emails if email_list else [] | |
62 | |
63 if email in allowed_emails: | |
64 finish_auth('User in allowed email list.') | |
65 return | |
66 | |
67 if (email.endswith('@google.com') and | |
68 email.replace('@google.com', '@chromium.org') in allowed_emails): | |
69 finish_auth('User in allowed email list via google -> chromium map.') | |
iannucci
2013/10/09 18:57:30
:(... this is teh hax... Can we at least have this
agable
2013/10/09 19:12:31
I believe this is the best way to do this. Later w
| |
70 return | |
71 | |
72 abort_auth('User not in allowed email list.') | |
73 | |
74 return wrapper | |
75 | |
76 | |
77 def RequireAuth(handler): | |
78 """Decorator for webapp2 request handler methods. | |
79 | |
80 Only use on webapp2.RequestHandler methods (e.g. get, post, put), | |
81 and only after using a 'Check____Auth' decorator. | |
82 | |
83 Expects the handler's self.request.authenticated to be not-None. | |
84 If it doesn't exist or evaluates to False, 403s. Otherwise, passes | |
85 control to the wrapped handler. | |
86 """ | |
87 @functools.wraps(handler) | |
88 def wrapper(self, *args, **kwargs): | |
89 """Does the real legwork and calls the wrapped handler.""" | |
90 if not getattr(self.request, 'authenticated', None): | |
iannucci
2013/10/09 18:57:30
either this should be checking is not None, or the
agable
2013/10/09 19:12:31
SG, will be done in patchset 6 (after you finish r
| |
91 self.abort(403) | |
92 else: | |
93 handler(self, *args, **kwargs) | |
94 | |
95 return wrapper | |
OLD | NEW |