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