Hash passwords earlier in the registration process (#7523)

This commit is contained in:
Patrick Cloke 2020-05-18 09:46:18 -04:00 committed by GitHub
parent 75fbc1a0c6
commit 56db0b1365
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 31 deletions

1
changelog.d/7523.bugfix Normal file
View file

@ -0,0 +1 @@
Hash passwords as early as possible during registration.

View file

@ -132,7 +132,7 @@ class RegistrationHandler(BaseHandler):
def register_user( def register_user(
self, self,
localpart=None, localpart=None,
password=None, password_hash=None,
guest_access_token=None, guest_access_token=None,
make_guest=False, make_guest=False,
admin=False, admin=False,
@ -147,7 +147,7 @@ class RegistrationHandler(BaseHandler):
Args: Args:
localpart: The local part of the user ID to register. If None, localpart: The local part of the user ID to register. If None,
one will be generated. 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 login again. This can be None which means they cannot login again
via a password (e.g. the user is an application service user). via a password (e.g. the user is an application service user).
user_type (str|None): type of user. One of the values from user_type (str|None): type of user. One of the values from
@ -164,11 +164,6 @@ class RegistrationHandler(BaseHandler):
yield self.check_registration_ratelimit(address) yield self.check_registration_ratelimit(address)
yield self.auth.check_auth_blocking(threepid=threepid) 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: if localpart is not None:
yield self.check_username(localpart, guest_access_token=guest_access_token) yield self.check_username(localpart, guest_access_token=guest_access_token)

View file

@ -243,11 +243,11 @@ class UserRestServletV2(RestServlet):
else: # create user else: # create user
password = body.get("password") password = body.get("password")
if password is not None and ( password_hash = None
not isinstance(body["password"], text_type) if password is not None:
or len(body["password"]) > 512 if not isinstance(password, text_type) or len(password) > 512:
): raise SynapseError(400, "Invalid password")
raise SynapseError(400, "Invalid password") password_hash = await self.auth_handler.hash(password)
admin = body.get("admin", None) admin = body.get("admin", None)
user_type = body.get("user_type", None) user_type = body.get("user_type", None)
@ -259,7 +259,7 @@ class UserRestServletV2(RestServlet):
user_id = await self.registration_handler.register_user( user_id = await self.registration_handler.register_user(
localpart=target_user.localpart, localpart=target_user.localpart,
password=password, password_hash=password_hash,
admin=bool(admin), admin=bool(admin),
default_display_name=displayname, default_display_name=displayname,
user_type=user_type, user_type=user_type,
@ -298,7 +298,7 @@ class UserRegisterServlet(RestServlet):
NONCE_TIMEOUT = 60 NONCE_TIMEOUT = 60
def __init__(self, hs): def __init__(self, hs):
self.handlers = hs.get_handlers() self.auth_handler = hs.get_auth_handler()
self.reactor = hs.get_reactor() self.reactor = hs.get_reactor()
self.nonces = {} self.nonces = {}
self.hs = hs self.hs = hs
@ -362,16 +362,16 @@ class UserRegisterServlet(RestServlet):
400, "password must be specified", errcode=Codes.BAD_JSON 400, "password must be specified", errcode=Codes.BAD_JSON
) )
else: else:
if ( password = body["password"]
not isinstance(body["password"], text_type) if not isinstance(password, text_type) or len(password) > 512:
or len(body["password"]) > 512
):
raise SynapseError(400, "Invalid password") raise SynapseError(400, "Invalid password")
password = body["password"].encode("utf-8") password_bytes = password.encode("utf-8")
if b"\x00" in password: if b"\x00" in password_bytes:
raise SynapseError(400, "Invalid password") raise SynapseError(400, "Invalid password")
password_hash = await self.auth_handler.hash(password)
admin = body.get("admin", None) admin = body.get("admin", None)
user_type = body.get("user_type", None) user_type = body.get("user_type", None)
@ -388,7 +388,7 @@ class UserRegisterServlet(RestServlet):
want_mac_builder.update(b"\x00") want_mac_builder.update(b"\x00")
want_mac_builder.update(username) want_mac_builder.update(username)
want_mac_builder.update(b"\x00") 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"\x00")
want_mac_builder.update(b"admin" if admin else b"notadmin") want_mac_builder.update(b"admin" if admin else b"notadmin")
if user_type: if user_type:
@ -407,7 +407,7 @@ class UserRegisterServlet(RestServlet):
user_id = await register.registration_handler.register_user( user_id = await register.registration_handler.register_user(
localpart=body["username"].lower(), localpart=body["username"].lower(),
password=body["password"], password_hash=password_hash,
admin=bool(admin), admin=bool(admin),
user_type=user_type, user_type=user_type,
) )

View file

@ -426,12 +426,16 @@ class RegisterRestServlet(RestServlet):
# we do basic sanity checks here because the auth layer will store these # we do basic sanity checks here because the auth layer will store these
# in sessions. Pull out the username/password provided to us. # in sessions. Pull out the username/password provided to us.
if "password" in body: if "password" in body:
if ( password = body.pop("password")
not isinstance(body["password"], string_types) if not isinstance(password, string_types) or len(password) > 512:
or len(body["password"]) > 512
):
raise SynapseError(400, "Invalid password") 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 desired_username = None
if "username" in body: if "username" in body:
@ -484,7 +488,7 @@ class RegisterRestServlet(RestServlet):
guest_access_token = body.get("guest_access_token", None) 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 # ignore 'initial_device_display_name' if sent without
# a password to work around a client bug where it sent # a password to work around a client bug where it sent
# the 'initial_device_display_name' param alone, wiping out # the 'initial_device_display_name' param alone, wiping out
@ -546,11 +550,11 @@ class RegisterRestServlet(RestServlet):
registered = False registered = False
else: else:
# NB: This may be from the auth handler and NOT from the POST # 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) desired_username = params.get("username", None)
guest_access_token = params.get("guest_access_token", 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: if desired_username is not None:
desired_username = desired_username.lower() desired_username = desired_username.lower()
@ -583,7 +587,7 @@ class RegisterRestServlet(RestServlet):
registered_user_id = await self.registration_handler.register_user( registered_user_id = await self.registration_handler.register_user(
localpart=desired_username, localpart=desired_username,
password=new_password, password_hash=new_password_hash,
guest_access_token=guest_access_token, guest_access_token=guest_access_token,
threepid=threepid, threepid=threepid,
address=client_addr, address=client_addr,