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

Commit

Permalink
Hash passwords earlier in the registration process (#7523)
Browse files Browse the repository at this point in the history
  • Loading branch information
clokep committed May 18, 2020
1 parent 75fbc1a commit 56db0b1
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 31 deletions.
1 change: 1 addition & 0 deletions changelog.d/7523.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hash passwords as early as possible during registration.
9 changes: 2 additions & 7 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def check_username(self, localpart, guest_access_token=None, assigned_user_id=No
def register_user(
self,
localpart=None,
password=None,
password_hash=None,
guest_access_token=None,
make_guest=False,
admin=False,
Expand All @@ -147,7 +147,7 @@ def register_user(
Args:
localpart: The local part of the user ID to register. If None,
one will be generated.
password (unicode): The password to assign to this user so they can
password_hash (str|None): The hashed password to assign to this user so they can
login again. This can be None which means they cannot login again
via a password (e.g. the user is an application service user).
user_type (str|None): type of user. One of the values from
Expand All @@ -164,11 +164,6 @@ def register_user(
yield self.check_registration_ratelimit(address)

yield self.auth.check_auth_blocking(threepid=threepid)
password_hash = None
if password:
password_hash = yield defer.ensureDeferred(
self._auth_handler.hash(password)
)

if localpart is not None:
yield self.check_username(localpart, guest_access_token=guest_access_token)
Expand Down
30 changes: 15 additions & 15 deletions synapse/rest/admin/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,11 @@ async def on_PUT(self, request, user_id):

else: # create user
password = body.get("password")
if password is not None and (
not isinstance(body["password"], text_type)
or len(body["password"]) > 512
):
raise SynapseError(400, "Invalid password")
password_hash = None
if password is not None:
if not isinstance(password, text_type) or len(password) > 512:
raise SynapseError(400, "Invalid password")
password_hash = await self.auth_handler.hash(password)

admin = body.get("admin", None)
user_type = body.get("user_type", None)
Expand All @@ -259,7 +259,7 @@ async def on_PUT(self, request, user_id):

user_id = await self.registration_handler.register_user(
localpart=target_user.localpart,
password=password,
password_hash=password_hash,
admin=bool(admin),
default_display_name=displayname,
user_type=user_type,
Expand Down Expand Up @@ -298,7 +298,7 @@ class UserRegisterServlet(RestServlet):
NONCE_TIMEOUT = 60

def __init__(self, hs):
self.handlers = hs.get_handlers()
self.auth_handler = hs.get_auth_handler()
self.reactor = hs.get_reactor()
self.nonces = {}
self.hs = hs
Expand Down Expand Up @@ -362,16 +362,16 @@ async def on_POST(self, request):
400, "password must be specified", errcode=Codes.BAD_JSON
)
else:
if (
not isinstance(body["password"], text_type)
or len(body["password"]) > 512
):
password = body["password"]
if not isinstance(password, text_type) or len(password) > 512:
raise SynapseError(400, "Invalid password")

password = body["password"].encode("utf-8")
if b"\x00" in password:
password_bytes = password.encode("utf-8")
if b"\x00" in password_bytes:
raise SynapseError(400, "Invalid password")

password_hash = await self.auth_handler.hash(password)

admin = body.get("admin", None)
user_type = body.get("user_type", None)

Expand All @@ -388,7 +388,7 @@ async def on_POST(self, request):
want_mac_builder.update(b"\x00")
want_mac_builder.update(username)
want_mac_builder.update(b"\x00")
want_mac_builder.update(password)
want_mac_builder.update(password_bytes)
want_mac_builder.update(b"\x00")
want_mac_builder.update(b"admin" if admin else b"notadmin")
if user_type:
Expand All @@ -407,7 +407,7 @@ async def on_POST(self, request):

user_id = await register.registration_handler.register_user(
localpart=body["username"].lower(),
password=body["password"],
password_hash=password_hash,
admin=bool(admin),
user_type=user_type,
)
Expand Down
22 changes: 13 additions & 9 deletions synapse/rest/client/v2_alpha/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,16 @@ async def on_POST(self, request):
# we do basic sanity checks here because the auth layer will store these
# in sessions. Pull out the username/password provided to us.
if "password" in body:
if (
not isinstance(body["password"], string_types)
or len(body["password"]) > 512
):
password = body.pop("password")
if not isinstance(password, string_types) or len(password) > 512:
raise SynapseError(400, "Invalid password")
self.password_policy_handler.validate_password(body["password"])
self.password_policy_handler.validate_password(password)

# If the password is valid, hash it and store it back on the request.
# This ensures the hashed password is handled everywhere.
if "password_hash" in body:
raise SynapseError(400, "Unexpected property: password_hash")
body["password_hash"] = await self.auth_handler.hash(password)

desired_username = None
if "username" in body:
Expand Down Expand Up @@ -484,7 +488,7 @@ async def on_POST(self, request):

guest_access_token = body.get("guest_access_token", None)

if "initial_device_display_name" in body and "password" not in body:
if "initial_device_display_name" in body and "password_hash" not in body:
# ignore 'initial_device_display_name' if sent without
# a password to work around a client bug where it sent
# the 'initial_device_display_name' param alone, wiping out
Expand Down Expand Up @@ -546,11 +550,11 @@ async def on_POST(self, request):
registered = False
else:
# NB: This may be from the auth handler and NOT from the POST
assert_params_in_dict(params, ["password"])
assert_params_in_dict(params, ["password_hash"])

desired_username = params.get("username", None)
guest_access_token = params.get("guest_access_token", None)
new_password = params.get("password", None)
new_password_hash = params.get("password_hash", None)

if desired_username is not None:
desired_username = desired_username.lower()
Expand Down Expand Up @@ -583,7 +587,7 @@ async def on_POST(self, request):

registered_user_id = await self.registration_handler.register_user(
localpart=desired_username,
password=new_password,
password_hash=new_password_hash,
guest_access_token=guest_access_token,
threepid=threepid,
address=client_addr,
Expand Down

0 comments on commit 56db0b1

Please sign in to comment.