experimental delegate_register

This commit is contained in:
Matthew Hodgson 2018-10-29 00:12:07 +00:00
parent 9498cd3e7b
commit 1ef1b716e2
3 changed files with 55 additions and 2 deletions

View file

@ -60,6 +60,8 @@ class RegistrationConfig(Config):
if not isinstance(self.replicate_user_profiles_to, list):
self.replicate_user_profiles_to = [self.replicate_user_profiles_to, ]
self.chain_register = config.get("chain_register", None)
def default_config(self, **kwargs):
registration_shared_secret = random_string_with_symbols(50)
@ -137,6 +139,13 @@ class RegistrationConfig(Config):
# cross-homeserver user directories.
# replicate_user_profiles_to: example.com
# If specified, attempt to replay registrations on the given target
# homeserver and identity server. The HS is authed via a given shared secret
# chain_register:
# hs: https://shadow.example.com
# hs_shared_secret: 12u394refgbdhivsia
# is: https://shadow-is.example.com
# If enabled, don't let users set their own display names/avatars
# other than for the very first time (unless they are a server admin).
# Useful when provisioning users based on the contents of a 3rd party

View file

@ -51,6 +51,7 @@ class RegistrationHandler(BaseHandler):
self.profile_handler = hs.get_profile_handler()
self.user_directory_handler = hs.get_user_directory_handler()
self.captcha_client = CaptchaServerHttpClient(hs)
self.http_client = hs.get_simple_http_client()
self._next_generated_user_id = None
@ -396,6 +397,43 @@ class RegistrationHandler(BaseHandler):
errcode=Codes.EXCLUSIVE
)
@defer.inlineCallbacks
def chain_register(self, localpart, auth_result, params):
"""Invokes the current registration on another server, using
shared secret registration, passing in any auth_results from
other registration UI auth flows (e.g. validated 3pids)
Useful for setting up shadow/backup accounts on a parallel deployment.
"""
# TODO: retries
chained_hs = self.hs.config.chain_register.get("hs")
user = localpart.encode("utf-8")
mac = hmac.new(
key=self.hs.config.chain_register.get("hs_shared_secret").encode(),
msg=user,
digestmod=sha1,
).hexdigest()
data = yield self.http_client.post_urlencoded_get_json(
"https://%s%s" % (
chained_hs, "/_matrix/client/r0/register"
),
{
# XXX: auth_result is an unspecified extension for chained registration
'auth_result': auth_result,
'username': localpart,
'password': params.get("password"),
'bind_email': params.get("bind_email"),
'bind_msisdn': params.get("bind_msisdn"),
'device_id': params.get("device_id"),
'initial_device_display_name': params.get("initial_device_display_name"),
'inhibit_login': True,
'mac': mac,
}
)
@defer.inlineCallbacks
def _generate_user_id(self, reseed=False):
if reseed or self._next_generated_user_id is None:

View file

@ -467,7 +467,6 @@ class RegisterRestServlet(RestServlet):
pass
guest_access_token = params.get("guest_access_token", None)
new_password = params.get("password", None)
# XXX: don't we need to validate these for length etc like we did on
# the ones from the JSON body earlier on in the method?
@ -477,12 +476,19 @@ class RegisterRestServlet(RestServlet):
(registered_user_id, _) = yield self.registration_handler.register(
localpart=desired_username,
password=new_password,
password=params.get("password", None),
guest_access_token=guest_access_token,
generate_token=False,
display_name=desired_display_name,
)
if self.hs.config.chain_register:
yield self.registration_handler.chain_register(
localpart=desired_username,
auth_result=auth_result,
params=params,
)
# remember that we've now registered that user account, and with
# what user ID (since the user may not have specified)
self.auth_handler.set_session_data(