Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Reduce CPU overhead of change password endpoint (#16264)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikjohnston authored Sep 8, 2023
1 parent 1cd410a commit d23c394
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 58 deletions.
1 change: 1 addition & 0 deletions changelog.d/16264.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reduce CPU overhead of change password endpoint.
112 changes: 54 additions & 58 deletions synapse/rest/client/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,85 +179,81 @@ async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
#
# In the second case, we require a password to confirm their identity.

requester = None
if self.auth.has_access_token(request):
requester = await self.auth.get_user_by_req(request)
try:
try:
requester = None
if self.auth.has_access_token(request):
requester = await self.auth.get_user_by_req(request)
params, session_id = await self.auth_handler.validate_user_via_ui_auth(
requester,
request,
body.dict(exclude_unset=True),
"modify your account password",
)
except InteractiveAuthIncompleteError as e:
# The user needs to provide more steps to complete auth, but
# they're not required to provide the password again.
#
# If a password is available now, hash the provided password and
# store it for later.
if new_password:
new_password_hash = await self.auth_handler.hash(new_password)
await self.auth_handler.set_session_data(
e.session_id,
UIAuthSessionDataConstants.PASSWORD_HASH,
new_password_hash,
)
raise
user_id = requester.user.to_string()
else:
try:
user_id = requester.user.to_string()
else:
result, params, session_id = await self.auth_handler.check_ui_auth(
[[LoginType.EMAIL_IDENTITY]],
request,
body.dict(exclude_unset=True),
"modify your account password",
)
except InteractiveAuthIncompleteError as e:
# The user needs to provide more steps to complete auth, but
# they're not required to provide the password again.
#
# If a password is available now, hash the provided password and
# store it for later.
if new_password:
new_password_hash = await self.auth_handler.hash(new_password)
await self.auth_handler.set_session_data(
e.session_id,
UIAuthSessionDataConstants.PASSWORD_HASH,
new_password_hash,

if LoginType.EMAIL_IDENTITY in result:
threepid = result[LoginType.EMAIL_IDENTITY]
if "medium" not in threepid or "address" not in threepid:
raise SynapseError(500, "Malformed threepid")
if threepid["medium"] == "email":
# For emails, canonicalise the address.
# We store all email addresses canonicalised in the DB.
# (See add_threepid in synapse/handlers/auth.py)
try:
threepid["address"] = validate_email(threepid["address"])
except ValueError as e:
raise SynapseError(400, str(e))
# if using email, we must know about the email they're authing with!
threepid_user_id = await self.datastore.get_user_id_by_threepid(
threepid["medium"], threepid["address"]
)
if not threepid_user_id:
raise SynapseError(
404, "Email address not found", Codes.NOT_FOUND
)
user_id = threepid_user_id
else:
logger.error("Auth succeeded but no known type! %r", result.keys())
raise SynapseError(500, "", Codes.UNKNOWN)

except InteractiveAuthIncompleteError as e:
# The user needs to provide more steps to complete auth, but
# they're not required to provide the password again.
#
# If a password is available now, hash the provided password and
# store it for later. We only do this if we don't already have the
# password hash stored, to avoid repeatedly hashing the password.

if not new_password:
raise

if LoginType.EMAIL_IDENTITY in result:
threepid = result[LoginType.EMAIL_IDENTITY]
if "medium" not in threepid or "address" not in threepid:
raise SynapseError(500, "Malformed threepid")
if threepid["medium"] == "email":
# For emails, canonicalise the address.
# We store all email addresses canonicalised in the DB.
# (See add_threepid in synapse/handlers/auth.py)
try:
threepid["address"] = validate_email(threepid["address"])
except ValueError as e:
raise SynapseError(400, str(e))
# if using email, we must know about the email they're authing with!
threepid_user_id = await self.datastore.get_user_id_by_threepid(
threepid["medium"], threepid["address"]
)
if not threepid_user_id:
raise SynapseError(404, "Email address not found", Codes.NOT_FOUND)
user_id = threepid_user_id
else:
logger.error("Auth succeeded but no known type! %r", result.keys())
raise SynapseError(500, "", Codes.UNKNOWN)
existing_session_password_hash = await self.auth_handler.get_session_data(
e.session_id, UIAuthSessionDataConstants.PASSWORD_HASH, None
)
if existing_session_password_hash:
raise

new_password_hash = await self.auth_handler.hash(new_password)
await self.auth_handler.set_session_data(
e.session_id,
UIAuthSessionDataConstants.PASSWORD_HASH,
new_password_hash,
)
raise

# If we have a password in this request, prefer it. Otherwise, use the
# password hash from an earlier request.
if new_password:
password_hash: Optional[str] = await self.auth_handler.hash(new_password)
elif session_id is not None:
password_hash = await self.auth_handler.get_session_data(
session_id, UIAuthSessionDataConstants.PASSWORD_HASH, None
)
password_hash = existing_session_password_hash
else:
# UI validation was skipped, but the request did not include a new
# password.
Expand Down

0 comments on commit d23c394

Please sign in to comment.