Synapse 1.13.0rc3 (2020-05-18)

Bugfixes:
 
 - Hash passwords as early as possible during registration. #7523
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEF3tZXk38tRDFVnUIM/xY9qcRMEgFAl7CpGYACgkQM/xY9qcR
 MEhVixAAk2hDWVXxbGzUk2LmfiIsFA2eV55sw+VqEw0eRfe1d/mP6aH75VmTt3pw
 IymZUVxDXdbTnPNPw+ldyGhzu9C6JJjXnNRBZnIkR5vcSbWsV0mPl/qHFu/4FnZI
 m4Nj1Sx3sG0CyNDpWjVrzTW6SbDX9J68DXbLwnNTSX3KPa7gNn6TUmFfKzlrNI23
 pPmD+EITYMn/H9HOhxhTzq//Ja7UOViAKQ0q4N2I4GxmLP6ufx9P3s5FG/oJqA+H
 Pka2+9JnfHq2Ze22CoDcg8q5f5MgVkQzGeir0ZsGJwJqOYjeTmbCvD3T/RYWO5g+
 ZghON3tsMQmdzUQqGRxcn/YLOZY9ZqrX2kBf5E6Wapwj9MfKg2ToLZM4yrWN0+RX
 KDuWaKXYtkSQCo1nDS2KooVMWjGNZautWWnHzZ0KNQCIkxVpGC234JYI685grKXb
 dg7R41kdXI7NJzqS4iM1fxXoLx64fpoREa/pbLF6VeLaYXBlzMjfhiIx2pQBN3L/
 q/y3ftev9VCp+2wPxiKUkiC4Sh7dgWUzNuyHU+4lsPUbI1H/MN5dN2ryObdEGWc/
 5YU3tv2MTQJ7jECHR+/fastnG+5d2kVm/FK+zVhG17JvA2VmDaLnSde+mzGbsO1N
 gIUx5VrTEP7y0tC8C/VgbS3c2KqCSOopqd3j2slLLrtQlXM71VE=
 =lpDI
 -----END PGP SIGNATURE-----

Merge tag 'v1.13.0rc3' into develop

Synapse 1.13.0rc3 (2020-05-18)

Bugfixes:

- Hash passwords as early as possible during registration. #7523
This commit is contained in:
Patrick Cloke 2020-05-18 11:10:04 -04:00
commit ee421e5244
5 changed files with 40 additions and 32 deletions

View file

@ -1,3 +1,12 @@
Synapse 1.13.0rc3 (2020-05-18)
==============================
Bugfixes
--------
- Hash passwords as early as possible during registration. ([\#7523](https://github.com/matrix-org/synapse/issues/7523))
Synapse 1.13.0rc2 (2020-05-14) Synapse 1.13.0rc2 (2020-05-14)
============================== ==============================

View file

@ -36,7 +36,7 @@ try:
except ImportError: except ImportError:
pass pass
__version__ = "1.13.0rc2" __version__ = "1.13.0rc3"
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)): if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
# We import here so that we don't have to install a bunch of deps when # We import here so that we don't have to install a bunch of deps when

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,