@@ -116,7 +116,7 @@ async def get_mxid_from_sso(
116116 user_agent : str ,
117117 ip_address : str ,
118118 sso_to_matrix_id_mapper : Callable [[int ], Awaitable [UserAttributes ]],
119- allow_existing_users : bool = False ,
119+ grandfather_existing_users : Optional [ Callable [[], Awaitable [ Optional [ str ]]]] ,
120120 ) -> str :
121121 """
122122 Given an SSO ID, retrieve the user ID for it and possibly register the user.
@@ -125,24 +125,17 @@ async def get_mxid_from_sso(
125125 if it has that matrix ID is returned regardless of the current mapping
126126 logic.
127127
128+ If a callable is provided for grandfathering users, it is called and can
129+ potentially return a matrix ID to use. If it does, the SSO ID is linked to
130+ this matrix ID for subsequent calls.
131+
128132 The mapping function is called (potentially multiple times) to generate
129133 a localpart for the user.
130134
131135 If an unused localpart is generated, the user is registered from the
132136 given user-agent and IP address and the SSO ID is linked to this matrix
133137 ID for subsequent calls.
134138
135- If allow_existing_users is true the mapping function is only called once
136- and results in:
137-
138- 1. The use of a previously registered matrix ID. In this case, the
139- SSO ID is linked to the matrix ID. (Note it is possible that
140- other SSO IDs are linked to the same matrix ID.)
141- 2. An unused localpart, in which case the user is registered (as
142- discussed above).
143- 3. An error if the generated localpart matches multiple pre-existing
144- matrix IDs. Generally this should not happen.
145-
146139 Args:
147140 auth_provider_id: A unique identifier for this SSO provider, e.g.
148141 "oidc" or "saml".
@@ -152,8 +145,9 @@ async def get_mxid_from_sso(
152145 sso_to_matrix_id_mapper: A callable to generate the user attributes.
153146 The only parameter is an integer which represents the amount of
154147 times the returned mxid localpart mapping has failed.
155- allow_existing_users: True if the localpart returned from the
156- mapping provider can be linked to an existing matrix ID.
148+ grandfather_existing_users: A callable which can return an previously
149+ existing matrix ID. The SSO ID is then linked to the returned
150+ matrix ID.
157151
158152 Returns:
159153 The user ID associated with the SSO response.
@@ -171,6 +165,16 @@ async def get_mxid_from_sso(
171165 if previously_registered_user_id :
172166 return previously_registered_user_id
173167
168+ # Check for grandfathering of users.
169+ if grandfather_existing_users :
170+ previously_registered_user_id = await grandfather_existing_users ()
171+ if previously_registered_user_id :
172+ # Future logins should also match this user ID.
173+ await self .store .record_user_external_id (
174+ auth_provider_id , remote_user_id , previously_registered_user_id
175+ )
176+ return previously_registered_user_id
177+
174178 # Otherwise, generate a new user.
175179 for i in range (self ._MAP_USERNAME_RETRIES ):
176180 try :
@@ -194,33 +198,7 @@ async def get_mxid_from_sso(
194198
195199 # Check if this mxid already exists
196200 user_id = UserID (attributes .localpart , self .server_name ).to_string ()
197- users = await self .store .get_users_by_id_case_insensitive (user_id )
198- # Note, if allow_existing_users is true then the loop is guaranteed
199- # to end on the first iteration: either by matching an existing user,
200- # raising an error, or registering a new user. See the docstring for
201- # more in-depth an explanation.
202- if users and allow_existing_users :
203- # If an existing matrix ID is returned, then use it.
204- if len (users ) == 1 :
205- previously_registered_user_id = next (iter (users ))
206- elif user_id in users :
207- previously_registered_user_id = user_id
208- else :
209- # Do not attempt to continue generating Matrix IDs.
210- raise MappingException (
211- "Attempted to login as '{}' but it matches more than one user inexactly: {}" .format (
212- user_id , users
213- )
214- )
215-
216- # Future logins should also match this user ID.
217- await self .store .record_user_external_id (
218- auth_provider_id , remote_user_id , previously_registered_user_id
219- )
220-
221- return previously_registered_user_id
222-
223- elif not users :
201+ if not await self .store .get_users_by_id_case_insensitive (user_id ):
224202 # This mxid is free
225203 break
226204 else :
0 commit comments