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

Commit

Permalink
Revert shadow HS support (#104)
Browse files Browse the repository at this point in the history
Revert shadow HS support added in #4145

Fixes matrix-org/matrix-dinsic#803

Part of that PR isn't reverted because it relates to matrix-org/matrix-dinsic#793
  • Loading branch information
babolivier authored Sep 27, 2021
1 parent 6b439a7 commit 95f29bc
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 272 deletions.
1 change: 1 addition & 0 deletions changelog.d/104.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove shadow HS support.
9 changes: 0 additions & 9 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1343,15 +1343,6 @@ url_preview_accept_language:
#
#replicate_user_profiles_to: example.com

# If specified, attempt to replay registrations, profile changes & 3pid
# bindings on the given target homeserver via the AS API. The HS is authed
# via a given AS token.
#
#shadow_server:
# hs_url: https://shadow.example.com
# hs: shadow.example.com
# as_token: 12u394refgbdhivsia

# 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
Expand Down
10 changes: 0 additions & 10 deletions synapse/config/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ def read_config(self, config, **kwargs):
if not isinstance(self.replicate_user_profiles_to, list):
self.replicate_user_profiles_to = [self.replicate_user_profiles_to]

self.shadow_server = config.get("shadow_server", None)
self.rewrite_identity_server_urls = (
config.get("rewrite_identity_server_urls") or {}
)
Expand Down Expand Up @@ -312,15 +311,6 @@ def generate_config_section(self, generate_secrets=False, **kwargs):
#
#replicate_user_profiles_to: example.com
# If specified, attempt to replay registrations, profile changes & 3pid
# bindings on the given target homeserver via the AS API. The HS is authed
# via a given AS token.
#
#shadow_server:
# hs_url: https://shadow.example.com
# hs: shadow.example.com
# as_token: 12u394refgbdhivsia
# 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
Expand Down
53 changes: 3 additions & 50 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,7 @@ async def post_consent_actions(self, user_id: str) -> None:
"""
await self._auto_join_rooms(user_id)

async def appservice_register(
self, user_localpart: str, as_token: str, password_hash: str, display_name: str
):
async def appservice_register(self, user_localpart: str, as_token: str):
# FIXME: this should be factored out and merged with normal register()
user = UserID(user_localpart, self.hs.hostname)
user_id = user.to_string()
Expand All @@ -630,26 +628,12 @@ async def appservice_register(

self.check_user_id_not_appservice_exclusive(user_id, allowed_appservice=service)

display_name = display_name or user.localpart

await self.register_with_store(
user_id=user_id,
password_hash=password_hash,
password_hash="",
appservice_id=service_id,
create_profile_with_displayname=display_name,
)

requester = create_requester(user)
await self.profile_handler.set_displayname(
user, requester, display_name, by_admin=True
create_profile_with_displayname=user.localpart,
)

if self.hs.config.user_directory_search_all_users:
profile = await self.store.get_profileinfo(user_localpart)
await self.user_directory_handler.handle_local_profile_change(
user_id, profile
)

return user_id

def check_user_id_not_appservice_exclusive(
Expand Down Expand Up @@ -678,37 +662,6 @@ def check_user_id_not_appservice_exclusive(
errcode=Codes.EXCLUSIVE,
)

async def shadow_register(self, localpart, display_name, 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
shadow_hs_url = self.hs.config.shadow_server.get("hs_url")
as_token = self.hs.config.shadow_server.get("as_token")

await self.http_client.post_json_get_json(
"%s/_matrix/client/r0/register?access_token=%s" % (shadow_hs_url, as_token),
{
# XXX: auth_result is an unspecified extension for shadow registration
"auth_result": auth_result,
# XXX: another unspecified extension for shadow registration to ensure
# that the displayname is correctly set by the masters erver
"display_name": display_name,
"username": localpart,
"password": params.get("password"),
"bind_msisdn": params.get("bind_msisdn"),
"device_id": params.get("device_id"),
"initial_device_display_name": params.get(
"initial_device_display_name"
),
"inhibit_login": False,
"access_token": as_token,
},
)

async def check_registration_ratelimit(self, address: Optional[str]) -> None:
"""A simple helper method to check whether the registration rate limit has been hit
for a given IP address
Expand Down
156 changes: 24 additions & 132 deletions synapse/rest/client/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import random
import re
from http import HTTPStatus
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING
from urllib.parse import urlparse

from synapse.api.constants import LoginType
Expand All @@ -38,7 +38,6 @@
)
from synapse.metrics import threepid_send_requests
from synapse.push.mailer import Mailer
from synapse.types import UserID
from synapse.util.msisdn import phone_number_to_msisdn
from synapse.util.stringutils import assert_valid_client_secret, random_string
from synapse.util.threepids import check_3pid_allowed, validate_email
Expand Down Expand Up @@ -196,31 +195,30 @@ async def on_POST(self, request):
if self.auth.has_access_token(request):
requester = await self.auth.get_user_by_req(request)
# blindly trust ASes without UI-authing them
if requester.app_service:
params = body
else:
try:
(
params,
session_id,
) = await self.auth_handler.validate_user_via_ui_auth(
requester,
request,
body,
"modify your account password",
try:
(
params,
session_id,
) = await self.auth_handler.validate_user_via_ui_auth(
requester,
request,
body,
"modify your account password",
)
except InteractiveAuthIncompleteError as e:
# The user needs to provide more steps to complete auth, but
# they're not required to provide the password again.
#
# If a password is available now, hash the provided password and
# store it for later.
if new_password:
password_hash = await self.auth_handler.hash(new_password)
await self.auth_handler.set_session_data(
e.session_id,
UIAuthSessionDataConstants.PASSWORD_HASH,
password_hash,
)
except InteractiveAuthIncompleteError as e:
# The user needs to provide more steps to complete auth, but
# they're not required to provide the password again.
#
# If a password is available now, hash the provided password and
# store it for later.
if new_password:
password_hash = await self.auth_handler.hash(new_password)
await self.auth_handler.set_session_data(
e.session_id, "password_hash", password_hash
)
raise
raise
user_id = requester.user.to_string()
else:
requester = None
Expand Down Expand Up @@ -290,28 +288,11 @@ async def on_POST(self, request):
user_id, password_hash, logout_devices, requester
)

if self.hs.config.shadow_server:
shadow_user = UserID(
requester.user.localpart, self.hs.config.shadow_server.get("hs")
)
await self.shadow_password(params, shadow_user.to_string())

return 200, {}

def on_OPTIONS(self, _):
return 200, {}

async def shadow_password(self, body, user_id):
# TODO: retries
shadow_hs_url = self.hs.config.shadow_server.get("hs_url")
as_token = self.hs.config.shadow_server.get("as_token")

await self.http_client.post_json_get_json(
"%s/_matrix/client/r0/account/password?access_token=%s&user_id=%s"
% (shadow_hs_url, as_token, user_id),
body,
)


class DeactivateAccountRestServlet(RestServlet):
PATTERNS = client_patterns("/account/deactivate$")
Expand Down Expand Up @@ -667,7 +648,6 @@ def __init__(self, hs):
self.auth = hs.get_auth()
self.auth_handler = hs.get_auth_handler()
self.datastore = hs.get_datastore()
self.http_client = hs.get_simple_http_client()

async def on_GET(self, request):
requester = await self.auth.get_user_by_req(request)
Expand All @@ -686,32 +666,6 @@ async def on_POST(self, request):
user_id = requester.user.to_string()
body = parse_json_object_from_request(request)

# skip validation if this is a shadow 3PID from an AS
if requester.app_service:
# XXX: ASes pass in a validated threepid directly to bypass the IS.
# This makes the API entirely change shape when we have an AS token;
# it really should be an entirely separate API - perhaps
# /account/3pid/replicate or something.
threepid: Optional[dict] = body.get("threepid")

if not threepid:
raise SynapseError(400, "Missing param 'threepid'")

await self.auth_handler.add_threepid(
user_id,
threepid["medium"],
threepid["address"],
threepid["validated_at"],
)

if self.hs.config.shadow_server:
shadow_user = UserID(
requester.user.localpart, self.hs.config.shadow_server.get("hs")
)
await self.shadow_3pid({"threepid": threepid}, shadow_user.to_string())

return 200, {}

threepid_creds = body.get("threePidCreds") or body.get("three_pid_creds")
if threepid_creds is None:
raise SynapseError(
Expand All @@ -733,35 +687,12 @@ async def on_POST(self, request):
validation_session["address"],
validation_session["validated_at"],
)

if self.hs.config.shadow_server:
shadow_user = UserID(
requester.user.localpart, self.hs.config.shadow_server.get("hs")
)
threepid = {
"medium": validation_session["medium"],
"address": validation_session["address"],
"validated_at": validation_session["validated_at"],
}
await self.shadow_3pid({"threepid": threepid}, shadow_user.to_string())

return 200, {}

raise SynapseError(
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
)

async def shadow_3pid(self, body, user_id):
# TODO: retries
shadow_hs_url = self.hs.config.shadow_server.get("hs_url")
as_token = self.hs.config.shadow_server.get("as_token")

await self.http_client.post_json_get_json(
"%s/_matrix/client/r0/account/3pid?access_token=%s&user_id=%s"
% (shadow_hs_url, as_token, user_id),
body,
)


class ThreepidAddRestServlet(RestServlet):
PATTERNS = client_patterns("/account/3pid/add$")
Expand Down Expand Up @@ -807,33 +738,12 @@ async def on_POST(self, request):
validation_session["address"],
validation_session["validated_at"],
)
if self.hs.config.shadow_server:
shadow_user = UserID(
requester.user.localpart, self.hs.config.shadow_server.get("hs")
)
threepid = {
"medium": validation_session["medium"],
"address": validation_session["address"],
"validated_at": validation_session["validated_at"],
}
await self.shadow_3pid({"threepid": threepid}, shadow_user.to_string())
return 200, {}

raise SynapseError(
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
)

async def shadow_3pid(self, body, user_id):
# TODO: retries
shadow_hs_url = self.hs.config.shadow_server.get("hs_url")
as_token = self.hs.config.shadow_server.get("as_token")

await self.http_client.post_json_get_json(
"%s/_matrix/client/r0/account/3pid?access_token=%s&user_id=%s"
% (shadow_hs_url, as_token, user_id),
body,
)


class ThreepidBindRestServlet(RestServlet):
PATTERNS = client_patterns("/account/3pid/bind$")
Expand Down Expand Up @@ -903,7 +813,6 @@ def __init__(self, hs):
self.hs = hs
self.auth = hs.get_auth()
self.auth_handler = hs.get_auth_handler()
self.http_client = hs.get_simple_http_client()

async def on_POST(self, request):
if not self.hs.config.enable_3pid_changes:
Expand All @@ -928,30 +837,13 @@ async def on_POST(self, request):
logger.exception("Failed to remove threepid")
raise SynapseError(500, "Failed to remove threepid")

if self.hs.config.shadow_server:
shadow_user = UserID(
requester.user.localpart, self.hs.config.shadow_server.get("hs")
)
await self.shadow_3pid_delete(body, shadow_user.to_string())

if ret:
id_server_unbind_result = "success"
else:
id_server_unbind_result = "no-support"

return 200, {"id_server_unbind_result": id_server_unbind_result}

async def shadow_3pid_delete(self, body, user_id):
# TODO: retries
shadow_hs_url = self.hs.config.shadow_server.get("hs_url")
as_token = self.hs.config.shadow_server.get("as_token")

await self.http_client.post_json_get_json(
"%s/_matrix/client/r0/account/3pid/delete?access_token=%s&user_id=%s"
% (shadow_hs_url, as_token, user_id),
body,
)


class ThreepidLookupRestServlet(RestServlet):
PATTERNS = [re.compile("^/_matrix/client/unstable/account/3pid/lookup$")]
Expand Down
Loading

0 comments on commit 95f29bc

Please sign in to comment.