register.py 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. # Copyright 2014 - 2016 OpenMarket Ltd
  2. # Copyright 2021 The Matrix.org Foundation C.I.C.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """Contains functions for registering clients."""
  16. import logging
  17. from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple
  18. from prometheus_client import Counter
  19. from typing_extensions import TypedDict
  20. from synapse import types
  21. from synapse.api.constants import (
  22. MAX_USERID_LENGTH,
  23. EventContentFields,
  24. EventTypes,
  25. JoinRules,
  26. LoginType,
  27. )
  28. from synapse.api.errors import AuthError, Codes, ConsentNotGivenError, SynapseError
  29. from synapse.appservice import ApplicationService
  30. from synapse.config.server import is_threepid_reserved
  31. from synapse.http.servlet import assert_params_in_dict
  32. from synapse.replication.http.login import RegisterDeviceReplicationServlet
  33. from synapse.replication.http.register import (
  34. ReplicationPostRegisterActionsServlet,
  35. ReplicationRegisterServlet,
  36. )
  37. from synapse.spam_checker_api import RegistrationBehaviour
  38. from synapse.storage.state import StateFilter
  39. from synapse.types import RoomAlias, UserID, create_requester
  40. if TYPE_CHECKING:
  41. from synapse.server import HomeServer
  42. logger = logging.getLogger(__name__)
  43. registration_counter = Counter(
  44. "synapse_user_registrations_total",
  45. "Number of new users registered (since restart)",
  46. ["guest", "shadow_banned", "auth_provider"],
  47. )
  48. login_counter = Counter(
  49. "synapse_user_logins_total",
  50. "Number of user logins (since restart)",
  51. ["guest", "auth_provider"],
  52. )
  53. def init_counters_for_auth_provider(auth_provider_id: str) -> None:
  54. """Ensure the prometheus counters for the given auth provider are initialised
  55. This fixes a problem where the counters are not reported for a given auth provider
  56. until the user first logs in/registers.
  57. """
  58. for is_guest in (True, False):
  59. login_counter.labels(guest=is_guest, auth_provider=auth_provider_id)
  60. for shadow_banned in (True, False):
  61. registration_counter.labels(
  62. guest=is_guest,
  63. shadow_banned=shadow_banned,
  64. auth_provider=auth_provider_id,
  65. )
  66. class LoginDict(TypedDict):
  67. device_id: str
  68. access_token: str
  69. valid_until_ms: Optional[int]
  70. refresh_token: Optional[str]
  71. class RegistrationHandler:
  72. def __init__(self, hs: "HomeServer"):
  73. self.store = hs.get_datastores().main
  74. self.clock = hs.get_clock()
  75. self.hs = hs
  76. self.auth = hs.get_auth()
  77. self._auth_handler = hs.get_auth_handler()
  78. self.profile_handler = hs.get_profile_handler()
  79. self.user_directory_handler = hs.get_user_directory_handler()
  80. self.identity_handler = self.hs.get_identity_handler()
  81. self.ratelimiter = hs.get_registration_ratelimiter()
  82. self.macaroon_gen = hs.get_macaroon_generator()
  83. self._account_validity_handler = hs.get_account_validity_handler()
  84. self._user_consent_version = self.hs.config.consent.user_consent_version
  85. self._server_notices_mxid = hs.config.servernotices.server_notices_mxid
  86. self._server_name = hs.hostname
  87. self.spam_checker = hs.get_spam_checker()
  88. if hs.config.worker.worker_app:
  89. self._register_client = ReplicationRegisterServlet.make_client(hs)
  90. self._register_device_client = RegisterDeviceReplicationServlet.make_client(
  91. hs
  92. )
  93. self._post_registration_client = (
  94. ReplicationPostRegisterActionsServlet.make_client(hs)
  95. )
  96. else:
  97. self.device_handler = hs.get_device_handler()
  98. self._register_device_client = self.register_device_inner
  99. self.pusher_pool = hs.get_pusherpool()
  100. self.session_lifetime = hs.config.registration.session_lifetime
  101. self.nonrefreshable_access_token_lifetime = (
  102. hs.config.registration.nonrefreshable_access_token_lifetime
  103. )
  104. self.refreshable_access_token_lifetime = (
  105. hs.config.registration.refreshable_access_token_lifetime
  106. )
  107. self.refresh_token_lifetime = hs.config.registration.refresh_token_lifetime
  108. init_counters_for_auth_provider("")
  109. async def check_username(
  110. self,
  111. localpart: str,
  112. guest_access_token: Optional[str] = None,
  113. assigned_user_id: Optional[str] = None,
  114. inhibit_user_in_use_error: bool = False,
  115. ) -> None:
  116. if types.contains_invalid_mxid_characters(localpart):
  117. raise SynapseError(
  118. 400,
  119. "User ID can only contain characters a-z, 0-9, or '=_-./'",
  120. Codes.INVALID_USERNAME,
  121. )
  122. if not localpart:
  123. raise SynapseError(400, "User ID cannot be empty", Codes.INVALID_USERNAME)
  124. if localpart[0] == "_":
  125. raise SynapseError(
  126. 400, "User ID may not begin with _", Codes.INVALID_USERNAME
  127. )
  128. user = UserID(localpart, self.hs.hostname)
  129. user_id = user.to_string()
  130. if assigned_user_id:
  131. if user_id == assigned_user_id:
  132. return
  133. else:
  134. raise SynapseError(
  135. 400,
  136. "A different user ID has already been registered for this session",
  137. )
  138. self.check_user_id_not_appservice_exclusive(user_id)
  139. if len(user_id) > MAX_USERID_LENGTH:
  140. raise SynapseError(
  141. 400,
  142. "User ID may not be longer than %s characters" % (MAX_USERID_LENGTH,),
  143. Codes.INVALID_USERNAME,
  144. )
  145. users = await self.store.get_users_by_id_case_insensitive(user_id)
  146. if users:
  147. if not inhibit_user_in_use_error and not guest_access_token:
  148. raise SynapseError(
  149. 400, "User ID already taken.", errcode=Codes.USER_IN_USE
  150. )
  151. if guest_access_token:
  152. user_data = await self.auth.get_user_by_access_token(guest_access_token)
  153. if (
  154. not user_data.is_guest
  155. or UserID.from_string(user_data.user_id).localpart != localpart
  156. ):
  157. raise AuthError(
  158. 403,
  159. "Cannot register taken user ID without valid guest "
  160. "credentials for that user.",
  161. errcode=Codes.FORBIDDEN,
  162. )
  163. if guest_access_token is None:
  164. try:
  165. int(localpart)
  166. raise SynapseError(
  167. 400,
  168. "Numeric user IDs are reserved for guest users.",
  169. errcode=Codes.INVALID_USERNAME,
  170. )
  171. except ValueError:
  172. pass
  173. async def register_user(
  174. self,
  175. localpart: Optional[str] = None,
  176. password_hash: Optional[str] = None,
  177. guest_access_token: Optional[str] = None,
  178. make_guest: bool = False,
  179. admin: bool = False,
  180. threepid: Optional[dict] = None,
  181. user_type: Optional[str] = None,
  182. default_display_name: Optional[str] = None,
  183. address: Optional[str] = None,
  184. bind_emails: Optional[Iterable[str]] = None,
  185. by_admin: bool = False,
  186. user_agent_ips: Optional[List[Tuple[str, str]]] = None,
  187. auth_provider_id: Optional[str] = None,
  188. ) -> str:
  189. """Registers a new client on the server.
  190. Args:
  191. localpart: The local part of the user ID to register. If None,
  192. one will be generated.
  193. password_hash: The hashed password to assign to this user so they can
  194. login again. This can be None which means they cannot login again
  195. via a password (e.g. the user is an application service user).
  196. guest_access_token: The access token used when this was a guest
  197. account.
  198. make_guest: True if the the new user should be guest,
  199. false to add a regular user account.
  200. admin: True if the user should be registered as a server admin.
  201. threepid: The threepid used for registering, if any.
  202. user_type: type of user. One of the values from
  203. api.constants.UserTypes, or None for a normal user.
  204. default_display_name: if set, the new user's displayname
  205. will be set to this. Defaults to 'localpart'.
  206. address: the IP address used to perform the registration.
  207. bind_emails: list of emails to bind to this account.
  208. by_admin: True if this registration is being made via the
  209. admin api, otherwise False.
  210. user_agent_ips: Tuples of user-agents and IP addresses used
  211. during the registration process.
  212. auth_provider_id: The SSO IdP the user used, if any.
  213. Returns:
  214. The registered user_id.
  215. Raises:
  216. SynapseError if there was a problem registering.
  217. """
  218. bind_emails = bind_emails or []
  219. await self.check_registration_ratelimit(address)
  220. result = await self.spam_checker.check_registration_for_spam(
  221. threepid,
  222. localpart,
  223. user_agent_ips or [],
  224. auth_provider_id=auth_provider_id,
  225. )
  226. if result == RegistrationBehaviour.DENY:
  227. logger.info(
  228. "Blocked registration of %r",
  229. localpart,
  230. )
  231. # We return a 429 to make it not obvious that they've been
  232. # denied.
  233. raise SynapseError(429, "Rate limited")
  234. shadow_banned = result == RegistrationBehaviour.SHADOW_BAN
  235. if shadow_banned:
  236. logger.info(
  237. "Shadow banning registration of %r",
  238. localpart,
  239. )
  240. # do not check_auth_blocking if the call is coming through the Admin API
  241. if not by_admin:
  242. await self.auth.check_auth_blocking(threepid=threepid)
  243. if localpart is not None:
  244. await self.check_username(localpart, guest_access_token=guest_access_token)
  245. was_guest = guest_access_token is not None
  246. user = UserID(localpart, self.hs.hostname)
  247. user_id = user.to_string()
  248. if was_guest:
  249. # If the user was a guest then they already have a profile
  250. default_display_name = None
  251. elif default_display_name is None:
  252. default_display_name = localpart
  253. await self.register_with_store(
  254. user_id=user_id,
  255. password_hash=password_hash,
  256. was_guest=was_guest,
  257. make_guest=make_guest,
  258. create_profile_with_displayname=default_display_name,
  259. admin=admin,
  260. user_type=user_type,
  261. address=address,
  262. shadow_banned=shadow_banned,
  263. )
  264. profile = await self.store.get_profileinfo(localpart)
  265. await self.user_directory_handler.handle_local_profile_change(
  266. user_id, profile
  267. )
  268. else:
  269. # autogen a sequential user ID
  270. fail_count = 0
  271. # If a default display name is not given, generate one.
  272. generate_display_name = default_display_name is None
  273. # This breaks on successful registration *or* errors after 10 failures.
  274. while True:
  275. # Fail after being unable to find a suitable ID a few times
  276. if fail_count > 10:
  277. raise SynapseError(500, "Unable to find a suitable guest user ID")
  278. generated_localpart = await self.store.generate_user_id()
  279. user = UserID(generated_localpart, self.hs.hostname)
  280. user_id = user.to_string()
  281. self.check_user_id_not_appservice_exclusive(user_id)
  282. if generate_display_name:
  283. default_display_name = generated_localpart
  284. try:
  285. await self.register_with_store(
  286. user_id=user_id,
  287. password_hash=password_hash,
  288. make_guest=make_guest,
  289. create_profile_with_displayname=default_display_name,
  290. address=address,
  291. shadow_banned=shadow_banned,
  292. )
  293. # Successfully registered
  294. break
  295. except SynapseError:
  296. # if user id is taken, just generate another
  297. fail_count += 1
  298. registration_counter.labels(
  299. guest=make_guest,
  300. shadow_banned=shadow_banned,
  301. auth_provider=(auth_provider_id or ""),
  302. ).inc()
  303. # If the user does not need to consent at registration, auto-join any
  304. # configured rooms.
  305. if not self.hs.config.consent.user_consent_at_registration:
  306. if (
  307. not self.hs.config.registration.auto_join_rooms_for_guests
  308. and make_guest
  309. ):
  310. logger.info(
  311. "Skipping auto-join for %s because auto-join for guests is disabled",
  312. user_id,
  313. )
  314. else:
  315. await self._auto_join_rooms(user_id)
  316. else:
  317. logger.info(
  318. "Skipping auto-join for %s because consent is required at registration",
  319. user_id,
  320. )
  321. # Bind any specified emails to this account
  322. current_time = self.hs.get_clock().time_msec()
  323. for email in bind_emails:
  324. # generate threepid dict
  325. threepid_dict = {
  326. "medium": "email",
  327. "address": email,
  328. "validated_at": current_time,
  329. }
  330. # Bind email to new account
  331. await self._register_email_threepid(user_id, threepid_dict, None)
  332. return user_id
  333. async def _create_and_join_rooms(self, user_id: str) -> None:
  334. """
  335. Create the auto-join rooms and join or invite the user to them.
  336. This should only be called when the first "real" user registers.
  337. Args:
  338. user_id: The user to join
  339. """
  340. # Getting the handlers during init gives a dependency loop.
  341. room_creation_handler = self.hs.get_room_creation_handler()
  342. room_member_handler = self.hs.get_room_member_handler()
  343. # Generate a stub for how the rooms will be configured.
  344. stub_config = {
  345. "preset": self.hs.config.registration.autocreate_auto_join_room_preset,
  346. }
  347. # If the configuration provides a user ID to create rooms with, use
  348. # that instead of the first user registered.
  349. requires_join = False
  350. if self.hs.config.registration.auto_join_user_id:
  351. fake_requester = create_requester(
  352. self.hs.config.registration.auto_join_user_id,
  353. authenticated_entity=self._server_name,
  354. )
  355. # If the room requires an invite, add the user to the list of invites.
  356. if self.hs.config.registration.auto_join_room_requires_invite:
  357. stub_config["invite"] = [user_id]
  358. # If the room is being created by a different user, the first user
  359. # registered needs to join it. Note that in the case of an invitation
  360. # being necessary this will occur after the invite was sent.
  361. requires_join = True
  362. else:
  363. fake_requester = create_requester(
  364. user_id, authenticated_entity=self._server_name
  365. )
  366. # Choose whether to federate the new room.
  367. if not self.hs.config.registration.autocreate_auto_join_rooms_federated:
  368. stub_config["creation_content"] = {EventContentFields.FEDERATE: False}
  369. for r in self.hs.config.registration.auto_join_rooms:
  370. logger.info("Auto-joining %s to %s", user_id, r)
  371. try:
  372. room_alias = RoomAlias.from_string(r)
  373. if self.hs.hostname != room_alias.domain:
  374. # If the alias is remote, try to join the room. This might fail
  375. # because the room might be invite only, but we don't have any local
  376. # user in the room to invite this one with, so at this point that's
  377. # the best we can do.
  378. logger.info(
  379. "Cannot automatically create room with alias %s as it isn't"
  380. " local, trying to join the room instead",
  381. r,
  382. )
  383. (
  384. room,
  385. remote_room_hosts,
  386. ) = await room_member_handler.lookup_room_alias(room_alias)
  387. room_id = room.to_string()
  388. await room_member_handler.update_membership(
  389. requester=create_requester(
  390. user_id, authenticated_entity=self._server_name
  391. ),
  392. target=UserID.from_string(user_id),
  393. room_id=room_id,
  394. remote_room_hosts=remote_room_hosts,
  395. action="join",
  396. ratelimit=False,
  397. )
  398. else:
  399. # A shallow copy is OK here since the only key that is
  400. # modified is room_alias_name.
  401. config = stub_config.copy()
  402. # create room expects the localpart of the room alias
  403. config["room_alias_name"] = room_alias.localpart
  404. info, _ = await room_creation_handler.create_room(
  405. fake_requester,
  406. config=config,
  407. ratelimit=False,
  408. )
  409. # If the room does not require an invite, but another user
  410. # created it, then ensure the first user joins it.
  411. if requires_join:
  412. await room_member_handler.update_membership(
  413. requester=create_requester(
  414. user_id, authenticated_entity=self._server_name
  415. ),
  416. target=UserID.from_string(user_id),
  417. room_id=info["room_id"],
  418. # Since it was just created, there are no remote hosts.
  419. remote_room_hosts=[],
  420. action="join",
  421. ratelimit=False,
  422. )
  423. except Exception as e:
  424. logger.error("Failed to join new user to %r: %r", r, e)
  425. async def _join_rooms(self, user_id: str) -> None:
  426. """
  427. Join or invite the user to the auto-join rooms.
  428. Args:
  429. user_id: The user to join
  430. """
  431. room_member_handler = self.hs.get_room_member_handler()
  432. for r in self.hs.config.registration.auto_join_rooms:
  433. logger.info("Auto-joining %s to %s", user_id, r)
  434. try:
  435. room_alias = RoomAlias.from_string(r)
  436. if RoomAlias.is_valid(r):
  437. (
  438. room,
  439. remote_room_hosts,
  440. ) = await room_member_handler.lookup_room_alias(room_alias)
  441. room_id = room.to_string()
  442. else:
  443. raise SynapseError(
  444. 400, "%s was not legal room ID or room alias" % (r,)
  445. )
  446. # Calculate whether the room requires an invite or can be
  447. # joined directly. By default, we consider the room as requiring an
  448. # invite if the homeserver is in the room (unless told otherwise by the
  449. # join rules). Otherwise we consider it as being joinable, at the risk of
  450. # failing to join, but in this case there's little more we can do since
  451. # we don't have a local user in the room to craft up an invite with.
  452. requires_invite = await self.store.is_host_joined(
  453. room_id,
  454. self._server_name,
  455. )
  456. if requires_invite:
  457. # If the server is in the room, check if the room is public.
  458. state = await self.store.get_filtered_current_state_ids(
  459. room_id, StateFilter.from_types([(EventTypes.JoinRules, "")])
  460. )
  461. event_id = state.get((EventTypes.JoinRules, ""))
  462. if event_id:
  463. join_rules_event = await self.store.get_event(
  464. event_id, allow_none=True
  465. )
  466. if join_rules_event:
  467. join_rule = join_rules_event.content.get("join_rule", None)
  468. requires_invite = (
  469. join_rule and join_rule != JoinRules.PUBLIC
  470. )
  471. # Send the invite, if necessary.
  472. if requires_invite:
  473. # If an invite is required, there must be a auto-join user ID.
  474. assert self.hs.config.registration.auto_join_user_id
  475. await room_member_handler.update_membership(
  476. requester=create_requester(
  477. self.hs.config.registration.auto_join_user_id,
  478. authenticated_entity=self._server_name,
  479. ),
  480. target=UserID.from_string(user_id),
  481. room_id=room_id,
  482. remote_room_hosts=remote_room_hosts,
  483. action="invite",
  484. ratelimit=False,
  485. )
  486. # Send the join.
  487. await room_member_handler.update_membership(
  488. requester=create_requester(
  489. user_id, authenticated_entity=self._server_name
  490. ),
  491. target=UserID.from_string(user_id),
  492. room_id=room_id,
  493. remote_room_hosts=remote_room_hosts,
  494. action="join",
  495. ratelimit=False,
  496. )
  497. except ConsentNotGivenError as e:
  498. # Technically not necessary to pull out this error though
  499. # moving away from bare excepts is a good thing to do.
  500. logger.error("Failed to join new user to %r: %r", r, e)
  501. except Exception as e:
  502. logger.error("Failed to join new user to %r: %r", r, e)
  503. async def _auto_join_rooms(self, user_id: str) -> None:
  504. """Automatically joins users to auto join rooms - creating the room in the first place
  505. if the user is the first to be created.
  506. Args:
  507. user_id: The user to join
  508. """
  509. # auto-join the user to any rooms we're supposed to dump them into
  510. # try to create the room if we're the first real user on the server. Note
  511. # that an auto-generated support or bot user is not a real user and will never be
  512. # the user to create the room
  513. should_auto_create_rooms = False
  514. is_real_user = await self.store.is_real_user(user_id)
  515. if self.hs.config.registration.autocreate_auto_join_rooms and is_real_user:
  516. count = await self.store.count_real_users()
  517. should_auto_create_rooms = count == 1
  518. if should_auto_create_rooms:
  519. await self._create_and_join_rooms(user_id)
  520. else:
  521. await self._join_rooms(user_id)
  522. async def post_consent_actions(self, user_id: str) -> None:
  523. """A series of registration actions that can only be carried out once consent
  524. has been granted
  525. Args:
  526. user_id: The user to join
  527. """
  528. await self._auto_join_rooms(user_id)
  529. async def appservice_register(self, user_localpart: str, as_token: str) -> str:
  530. user = UserID(user_localpart, self.hs.hostname)
  531. user_id = user.to_string()
  532. service = self.store.get_app_service_by_token(as_token)
  533. if not service:
  534. raise AuthError(403, "Invalid application service token.")
  535. if not service.is_interested_in_user(user_id):
  536. raise SynapseError(
  537. 400,
  538. "Invalid user localpart for this application service.",
  539. errcode=Codes.EXCLUSIVE,
  540. )
  541. service_id = service.id if service.is_exclusive_user(user_id) else None
  542. self.check_user_id_not_appservice_exclusive(user_id, allowed_appservice=service)
  543. await self.register_with_store(
  544. user_id=user_id,
  545. password_hash="",
  546. appservice_id=service_id,
  547. create_profile_with_displayname=user.localpart,
  548. )
  549. return user_id
  550. def check_user_id_not_appservice_exclusive(
  551. self, user_id: str, allowed_appservice: Optional[ApplicationService] = None
  552. ) -> None:
  553. # don't allow people to register the server notices mxid
  554. if self._server_notices_mxid is not None:
  555. if user_id == self._server_notices_mxid:
  556. raise SynapseError(
  557. 400, "This user ID is reserved.", errcode=Codes.EXCLUSIVE
  558. )
  559. # valid user IDs must not clash with any user ID namespaces claimed by
  560. # application services.
  561. services = self.store.get_app_services()
  562. interested_services = [
  563. s
  564. for s in services
  565. if s.is_interested_in_user(user_id) and s != allowed_appservice
  566. ]
  567. for service in interested_services:
  568. if service.is_exclusive_user(user_id):
  569. raise SynapseError(
  570. 400,
  571. "This user ID is reserved by an application service.",
  572. errcode=Codes.EXCLUSIVE,
  573. )
  574. async def check_registration_ratelimit(self, address: Optional[str]) -> None:
  575. """A simple helper method to check whether the registration rate limit has been hit
  576. for a given IP address
  577. Args:
  578. address: the IP address used to perform the registration. If this is
  579. None, no ratelimiting will be performed.
  580. Raises:
  581. LimitExceededError: If the rate limit has been exceeded.
  582. """
  583. if not address:
  584. return
  585. await self.ratelimiter.ratelimit(None, address)
  586. async def register_with_store(
  587. self,
  588. user_id: str,
  589. password_hash: Optional[str] = None,
  590. was_guest: bool = False,
  591. make_guest: bool = False,
  592. appservice_id: Optional[str] = None,
  593. create_profile_with_displayname: Optional[str] = None,
  594. admin: bool = False,
  595. user_type: Optional[str] = None,
  596. address: Optional[str] = None,
  597. shadow_banned: bool = False,
  598. ) -> None:
  599. """Register user in the datastore.
  600. Args:
  601. user_id: The desired user ID to register.
  602. password_hash: Optional. The password hash for this user.
  603. was_guest: Optional. Whether this is a guest account being
  604. upgraded to a non-guest account.
  605. make_guest: True if the the new user should be guest,
  606. false to add a regular user account.
  607. appservice_id: The ID of the appservice registering the user.
  608. create_profile_with_displayname: Optionally create a
  609. profile for the user, setting their displayname to the given value
  610. admin: is an admin user?
  611. user_type: type of user. One of the values from
  612. api.constants.UserTypes, or None for a normal user.
  613. address: the IP address used to perform the registration.
  614. shadow_banned: Whether to shadow-ban the user
  615. """
  616. if self.hs.config.worker.worker_app:
  617. await self._register_client(
  618. user_id=user_id,
  619. password_hash=password_hash,
  620. was_guest=was_guest,
  621. make_guest=make_guest,
  622. appservice_id=appservice_id,
  623. create_profile_with_displayname=create_profile_with_displayname,
  624. admin=admin,
  625. user_type=user_type,
  626. address=address,
  627. shadow_banned=shadow_banned,
  628. )
  629. else:
  630. await self.store.register_user(
  631. user_id=user_id,
  632. password_hash=password_hash,
  633. was_guest=was_guest,
  634. make_guest=make_guest,
  635. appservice_id=appservice_id,
  636. create_profile_with_displayname=create_profile_with_displayname,
  637. admin=admin,
  638. user_type=user_type,
  639. shadow_banned=shadow_banned,
  640. )
  641. # Only call the account validity module(s) on the main process, to avoid
  642. # repeating e.g. database writes on all of the workers.
  643. await self._account_validity_handler.on_user_registration(user_id)
  644. async def register_device(
  645. self,
  646. user_id: str,
  647. device_id: Optional[str],
  648. initial_display_name: Optional[str],
  649. is_guest: bool = False,
  650. is_appservice_ghost: bool = False,
  651. auth_provider_id: Optional[str] = None,
  652. should_issue_refresh_token: bool = False,
  653. auth_provider_session_id: Optional[str] = None,
  654. ) -> Tuple[str, str, Optional[int], Optional[str]]:
  655. """Register a device for a user and generate an access token.
  656. The access token will be limited by the homeserver's session_lifetime config.
  657. Args:
  658. user_id: full canonical @user:id
  659. device_id: The device ID to check, or None to generate a new one.
  660. initial_display_name: An optional display name for the device.
  661. is_guest: Whether this is a guest account
  662. auth_provider_id: The SSO IdP the user used, if any.
  663. should_issue_refresh_token: Whether it should also issue a refresh token
  664. auth_provider_session_id: The session ID received during login from the SSO IdP.
  665. Returns:
  666. Tuple of device ID, access token, access token expiration time and refresh token
  667. """
  668. res = await self._register_device_client(
  669. user_id=user_id,
  670. device_id=device_id,
  671. initial_display_name=initial_display_name,
  672. is_guest=is_guest,
  673. is_appservice_ghost=is_appservice_ghost,
  674. should_issue_refresh_token=should_issue_refresh_token,
  675. auth_provider_id=auth_provider_id,
  676. auth_provider_session_id=auth_provider_session_id,
  677. )
  678. login_counter.labels(
  679. guest=is_guest,
  680. auth_provider=(auth_provider_id or ""),
  681. ).inc()
  682. return (
  683. res["device_id"],
  684. res["access_token"],
  685. res["valid_until_ms"],
  686. res["refresh_token"],
  687. )
  688. async def register_device_inner(
  689. self,
  690. user_id: str,
  691. device_id: Optional[str],
  692. initial_display_name: Optional[str],
  693. is_guest: bool = False,
  694. is_appservice_ghost: bool = False,
  695. should_issue_refresh_token: bool = False,
  696. auth_provider_id: Optional[str] = None,
  697. auth_provider_session_id: Optional[str] = None,
  698. ) -> LoginDict:
  699. """Helper for register_device
  700. Does the bits that need doing on the main process. Not for use outside this
  701. class and RegisterDeviceReplicationServlet.
  702. """
  703. assert not self.hs.config.worker.worker_app
  704. now_ms = self.clock.time_msec()
  705. access_token_expiry = None
  706. if self.session_lifetime is not None:
  707. if is_guest:
  708. raise Exception(
  709. "session_lifetime is not currently implemented for guest access"
  710. )
  711. access_token_expiry = now_ms + self.session_lifetime
  712. if self.nonrefreshable_access_token_lifetime is not None:
  713. if access_token_expiry is not None:
  714. # Don't allow the non-refreshable access token to outlive the
  715. # session.
  716. access_token_expiry = min(
  717. now_ms + self.nonrefreshable_access_token_lifetime,
  718. access_token_expiry,
  719. )
  720. else:
  721. access_token_expiry = now_ms + self.nonrefreshable_access_token_lifetime
  722. refresh_token = None
  723. refresh_token_id = None
  724. registered_device_id = await self.device_handler.check_device_registered(
  725. user_id,
  726. device_id,
  727. initial_display_name,
  728. auth_provider_id=auth_provider_id,
  729. auth_provider_session_id=auth_provider_session_id,
  730. )
  731. if is_guest:
  732. assert access_token_expiry is None
  733. access_token = self.macaroon_gen.generate_guest_access_token(user_id)
  734. else:
  735. if should_issue_refresh_token:
  736. # A refreshable access token lifetime must be configured
  737. # since we're told to issue a refresh token (the caller checks
  738. # that this value is set before setting this flag).
  739. assert self.refreshable_access_token_lifetime is not None
  740. # Set the expiry time of the refreshable access token
  741. access_token_expiry = now_ms + self.refreshable_access_token_lifetime
  742. # Set the refresh token expiry time (if configured)
  743. refresh_token_expiry = None
  744. if self.refresh_token_lifetime is not None:
  745. refresh_token_expiry = now_ms + self.refresh_token_lifetime
  746. # Set an ultimate session expiry time (if configured)
  747. ultimate_session_expiry_ts = None
  748. if self.session_lifetime is not None:
  749. ultimate_session_expiry_ts = now_ms + self.session_lifetime
  750. # Also ensure that the issued tokens don't outlive the
  751. # session.
  752. # (It would be weird to configure a homeserver with a shorter
  753. # session lifetime than token lifetime, but may as well handle
  754. # it.)
  755. access_token_expiry = min(
  756. access_token_expiry, ultimate_session_expiry_ts
  757. )
  758. if refresh_token_expiry is not None:
  759. refresh_token_expiry = min(
  760. refresh_token_expiry, ultimate_session_expiry_ts
  761. )
  762. (
  763. refresh_token,
  764. refresh_token_id,
  765. ) = await self._auth_handler.create_refresh_token_for_user_id(
  766. user_id,
  767. device_id=registered_device_id,
  768. expiry_ts=refresh_token_expiry,
  769. ultimate_session_expiry_ts=ultimate_session_expiry_ts,
  770. )
  771. access_token = await self._auth_handler.create_access_token_for_user_id(
  772. user_id,
  773. device_id=registered_device_id,
  774. valid_until_ms=access_token_expiry,
  775. is_appservice_ghost=is_appservice_ghost,
  776. refresh_token_id=refresh_token_id,
  777. )
  778. return {
  779. "device_id": registered_device_id,
  780. "access_token": access_token,
  781. "valid_until_ms": access_token_expiry,
  782. "refresh_token": refresh_token,
  783. }
  784. async def post_registration_actions(
  785. self, user_id: str, auth_result: dict, access_token: Optional[str]
  786. ) -> None:
  787. """A user has completed registration
  788. Args:
  789. user_id: The user ID that consented
  790. auth_result: The authenticated credentials of the newly registered user.
  791. access_token: The access token of the newly logged in device, or
  792. None if `inhibit_login` enabled.
  793. """
  794. # TODO: 3pid registration can actually happen on the workers. Consider
  795. # refactoring it.
  796. if self.hs.config.worker.worker_app:
  797. await self._post_registration_client(
  798. user_id=user_id, auth_result=auth_result, access_token=access_token
  799. )
  800. return
  801. if auth_result and LoginType.EMAIL_IDENTITY in auth_result:
  802. threepid = auth_result[LoginType.EMAIL_IDENTITY]
  803. # Necessary due to auth checks prior to the threepid being
  804. # written to the db
  805. if is_threepid_reserved(
  806. self.hs.config.server.mau_limits_reserved_threepids, threepid
  807. ):
  808. await self.store.upsert_monthly_active_user(user_id)
  809. await self._register_email_threepid(user_id, threepid, access_token)
  810. if auth_result and LoginType.MSISDN in auth_result:
  811. threepid = auth_result[LoginType.MSISDN]
  812. await self._register_msisdn_threepid(user_id, threepid)
  813. if auth_result and LoginType.TERMS in auth_result:
  814. # The terms type should only exist if consent is enabled.
  815. assert self._user_consent_version is not None
  816. await self._on_user_consented(user_id, self._user_consent_version)
  817. async def _on_user_consented(self, user_id: str, consent_version: str) -> None:
  818. """A user consented to the terms on registration
  819. Args:
  820. user_id: The user ID that consented.
  821. consent_version: version of the policy the user has consented to.
  822. """
  823. logger.info("%s has consented to the privacy policy", user_id)
  824. await self.store.user_set_consent_version(user_id, consent_version)
  825. await self.post_consent_actions(user_id)
  826. async def _register_email_threepid(
  827. self, user_id: str, threepid: dict, token: Optional[str]
  828. ) -> None:
  829. """Add an email address as a 3pid identifier
  830. Also adds an email pusher for the email address, if configured in the
  831. HS config
  832. Must be called on master.
  833. Args:
  834. user_id: id of user
  835. threepid: m.login.email.identity auth response
  836. token: access_token for the user, or None if not logged in.
  837. """
  838. reqd = ("medium", "address", "validated_at")
  839. if any(x not in threepid for x in reqd):
  840. # This will only happen if the ID server returns a malformed response
  841. logger.info("Can't add incomplete 3pid")
  842. return
  843. await self._auth_handler.add_threepid(
  844. user_id,
  845. threepid["medium"],
  846. threepid["address"],
  847. threepid["validated_at"],
  848. )
  849. # And we add an email pusher for them by default, but only
  850. # if email notifications are enabled (so people don't start
  851. # getting mail spam where they weren't before if email
  852. # notifs are set up on a homeserver)
  853. if (
  854. self.hs.config.email.email_enable_notifs
  855. and self.hs.config.email.email_notif_for_new_users
  856. and token
  857. ):
  858. # Pull the ID of the access token back out of the db
  859. # It would really make more sense for this to be passed
  860. # up when the access token is saved, but that's quite an
  861. # invasive change I'd rather do separately.
  862. user_tuple = await self.store.get_user_by_access_token(token)
  863. # The token better still exist.
  864. assert user_tuple
  865. token_id = user_tuple.token_id
  866. await self.pusher_pool.add_pusher(
  867. user_id=user_id,
  868. access_token=token_id,
  869. kind="email",
  870. app_id="m.email",
  871. app_display_name="Email Notifications",
  872. device_display_name=threepid["address"],
  873. pushkey=threepid["address"],
  874. lang=None, # We don't know a user's language here
  875. data={},
  876. )
  877. async def _register_msisdn_threepid(self, user_id: str, threepid: dict) -> None:
  878. """Add a phone number as a 3pid identifier
  879. Must be called on master.
  880. Args:
  881. user_id: id of user
  882. threepid: m.login.msisdn auth response
  883. """
  884. try:
  885. assert_params_in_dict(threepid, ["medium", "address", "validated_at"])
  886. except SynapseError as ex:
  887. if ex.errcode == Codes.MISSING_PARAM:
  888. # This will only happen if the ID server returns a malformed response
  889. logger.info("Can't add incomplete 3pid")
  890. return None
  891. raise
  892. await self._auth_handler.add_threepid(
  893. user_id,
  894. threepid["medium"],
  895. threepid["address"],
  896. threepid["validated_at"],
  897. )