blob: 3c1bee9ac8f12ca046e01c234958dcb243bd4ac8 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""Classes to hold information parsed from a request.
7"""
8from __future__ import print_function
9from __future__ import division
10from __future__ import absolute_import
11
12from google.appengine.api import users
13
14from proto import user_pb2
15from framework import framework_bizobj
16from framework import framework_views
17
18
19class AuthData(object):
20 """This object holds authentication data about a user.
21
22 This is used by MonorailRequest as it determines which user the
23 requester is authenticated as and fetches the user's data. It can
24 also be used to lookup perms for user IDs specified in issue fields.
25
26 Attributes:
27 user_id: The user ID of the user (or 0 if not signed in).
28 effective_ids: A set of user IDs that includes the signed in user's
29 direct user ID and the user IDs of all their user groups.
30 This set will be empty for anonymous users.
31 user_view: UserView object for the signed-in user.
32 user_pb: User object for the signed-in user.
33 email: email address for the user, or None.
34 """
35
36 def __init__(self, user_id=0, email=None):
37 self.user_id = user_id
38 self.effective_ids = {user_id} if user_id else set()
39 self.user_view = None
40 self.user_pb = user_pb2.MakeUser(user_id)
41 self.email = email
42
43 @classmethod
44 def FromRequest(cls, cnxn, services):
45 """Determine auth information from the request and fetches user data.
46
47 If everything works and the user is signed in, then all of the public
48 attributes of the AuthData instance will be filled in appropriately.
49
50 Args:
51 cnxn: connection to the SQL database.
52 services: Interface to all persistence storage backends.
53
54 Returns:
55 A new AuthData object.
56 """
57 user = users.get_current_user()
58 if user is None:
59 return cls()
60 else:
61 # We create a User row for each user who visits the site.
62 # TODO(jrobbins): we should really only do it when they take action.
63 return cls.FromEmail(cnxn, user.email(), services, autocreate=True)
64
65 @classmethod
66 def FromEmail(cls, cnxn, email, services, autocreate=False):
67 """Determine auth information for the given user email address.
68
69 Args:
70 cnxn: monorail connection to the database.
71 email: string email address of the user.
72 services: connections to backend servers.
73 autocreate: set to True to create a new row in the Users table if needed.
74
75 Returns:
76 A new AuthData object.
77
78 Raises:
79 execptions.NoSuchUserException: If the user of the email does not exist.
80 """
81 auth = cls()
82 auth.email = email
83 if email:
84 auth.user_id = services.user.LookupUserID(
85 cnxn, email, autocreate=autocreate)
86 assert auth.user_id
87 cls._FinishInitialization(cnxn, auth, services, user_pb=None)
88
89 return auth
90
91 @classmethod
92 def FromUserID(cls, cnxn, user_id, services):
93 """Determine auth information for the given user ID.
94
95 Args:
96 cnxn: monorail connection to the database.
97 user_id: int user ID of the user.
98 services: connections to backend servers.
99
100 Returns:
101 A new AuthData object.
102 """
103 auth = cls()
104 auth.user_id = user_id
105 if auth.user_id:
106 auth.email = services.user.LookupUserEmail(cnxn, user_id)
107 cls._FinishInitialization(cnxn, auth, services, user_pb=None)
108
109 return auth
110
111 @classmethod
112 def FromUser(cls, cnxn, user, services):
113 """Determine auth information for the given user.
114
115 Args:
116 cnxn: monorail connection to the database.
117 user: user protobuf.
118 services: connections to backend servers.
119
120 Returns:
121 A new AuthData object.
122 """
123 auth = cls()
124 auth.user_id = user.user_id
125 if auth.user_id:
126 auth.email = user.email
127 cls._FinishInitialization(cnxn, auth, services, user)
128
129 return auth
130
131
132 @classmethod
133 def _FinishInitialization(cls, cnxn, auth, services, user_pb=None):
134 """Fill in the test of the fields based on the user_id."""
135 effective_ids_dict = framework_bizobj.GetEffectiveIds(
136 cnxn, services, [auth.user_id])
137 auth.effective_ids = effective_ids_dict[auth.user_id]
138 auth.user_pb = user_pb or services.user.GetUser(cnxn, auth.user_id)
139 if auth.user_pb:
140 auth.user_view = framework_views.UserView(auth.user_pb)
141
142 def __repr__(self):
143 """Return a string more useful for debugging."""
144 return 'AuthData(email=%r, user_id=%r, effective_ids=%r)' % (
145 self.email, self.user_id, self.effective_ids)