Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 1 | # 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. |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 4 | |
| 5 | """Classes to hold information parsed from a request. |
| 6 | """ |
| 7 | from __future__ import print_function |
| 8 | from __future__ import division |
| 9 | from __future__ import absolute_import |
| 10 | |
| 11 | from google.appengine.api import users |
| 12 | |
Adrià Vilanova Martínez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 13 | from mrproto import user_pb2 |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 14 | from framework import framework_bizobj |
| 15 | from framework import framework_views |
| 16 | |
| 17 | |
| 18 | class 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) |