Implement MSC3231: Token authenticated registration (#10142)

Signed-off-by: Callum Brown <callum@calcuode.com>

This is part of my GSoC project implementing [MSC3231](https://github.com/matrix-org/matrix-doc/pull/3231).
This commit is contained in:
Callum Brown 2021-08-21 22:14:43 +01:00 committed by GitHub
parent ecd823d766
commit 947dbbdfd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 2389 additions and 1 deletions

View file

@ -241,11 +241,76 @@ class MsisdnAuthChecker(UserInteractiveAuthChecker, _BaseThreepidAuthChecker):
return await self._check_threepid("msisdn", authdict)
class RegistrationTokenAuthChecker(UserInteractiveAuthChecker):
AUTH_TYPE = LoginType.REGISTRATION_TOKEN
def __init__(self, hs: "HomeServer"):
super().__init__(hs)
self.hs = hs
self._enabled = bool(hs.config.registration_requires_token)
self.store = hs.get_datastore()
def is_enabled(self) -> bool:
return self._enabled
async def check_auth(self, authdict: dict, clientip: str) -> Any:
if "token" not in authdict:
raise LoginError(400, "Missing registration token", Codes.MISSING_PARAM)
if not isinstance(authdict["token"], str):
raise LoginError(
400, "Registration token must be a string", Codes.INVALID_PARAM
)
if "session" not in authdict:
raise LoginError(400, "Missing UIA session", Codes.MISSING_PARAM)
# Get these here to avoid cyclic dependencies
from synapse.handlers.ui_auth import UIAuthSessionDataConstants
auth_handler = self.hs.get_auth_handler()
session = authdict["session"]
token = authdict["token"]
# If the LoginType.REGISTRATION_TOKEN stage has already been completed,
# return early to avoid incrementing `pending` again.
stored_token = await auth_handler.get_session_data(
session, UIAuthSessionDataConstants.REGISTRATION_TOKEN
)
if stored_token:
if token != stored_token:
raise LoginError(
400, "Registration token has changed", Codes.INVALID_PARAM
)
else:
return token
if await self.store.registration_token_is_valid(token):
# Increment pending counter, so that if token has limited uses it
# can't be used up by someone else in the meantime.
await self.store.set_registration_token_pending(token)
# Store the token in the UIA session, so that once registration
# is complete `completed` can be incremented.
await auth_handler.set_session_data(
session,
UIAuthSessionDataConstants.REGISTRATION_TOKEN,
token,
)
# The token will be stored as the result of the authentication stage
# in ui_auth_sessions_credentials. This allows the pending counter
# for tokens to be decremented when expired sessions are deleted.
return token
else:
raise LoginError(
401, "Invalid registration token", errcode=Codes.UNAUTHORIZED
)
INTERACTIVE_AUTH_CHECKERS = [
DummyAuthChecker,
TermsAuthChecker,
RecaptchaAuthChecker,
EmailIdentityAuthChecker,
MsisdnAuthChecker,
RegistrationTokenAuthChecker,
]
"""A list of UserInteractiveAuthChecker classes"""