Merge pull request #1136 from matrix-org/erikj/fix_signed_3pid

Allow invites via 3pid to bypass sender sig check
This commit is contained in:
Erik Johnston 2016-09-22 13:41:49 +01:00 committed by GitHub
commit 667fcd54e8
3 changed files with 35 additions and 12 deletions

View file

@ -72,7 +72,7 @@ class Auth(object):
auth_events = { auth_events = {
(e.type, e.state_key): e for e in auth_events.values() (e.type, e.state_key): e for e in auth_events.values()
} }
self.check(event, auth_events=auth_events, do_sig_check=False) self.check(event, auth_events=auth_events, do_sig_check=do_sig_check)
def check(self, event, auth_events, do_sig_check=True): def check(self, event, auth_events, do_sig_check=True):
""" Checks if this event is correctly authed. """ Checks if this event is correctly authed.
@ -91,10 +91,27 @@ class Auth(object):
if not hasattr(event, "room_id"): if not hasattr(event, "room_id"):
raise AuthError(500, "Event has no room_id: %s" % event) raise AuthError(500, "Event has no room_id: %s" % event)
if do_sig_check:
sender_domain = get_domain_from_id(event.sender) sender_domain = get_domain_from_id(event.sender)
event_id_domain = get_domain_from_id(event.event_id)
is_invite_via_3pid = (
event.type == EventTypes.Member
and event.membership == Membership.INVITE
and "third_party_invite" in event.content
)
# Check the sender's domain has signed the event # Check the sender's domain has signed the event
if do_sig_check and not event.signatures.get(sender_domain): if not event.signatures.get(sender_domain):
# We allow invites via 3pid to have a sender from a different
# HS, as the sender must match the sender of the original
# 3pid invite. This is checked further down with the
# other dedicated membership checks.
if not is_invite_via_3pid:
raise AuthError(403, "Event not signed by sender's server")
# Check the event_id's domain has signed the event
if not event.signatures.get(event_id_domain):
raise AuthError(403, "Event not signed by sending server") raise AuthError(403, "Event not signed by sending server")
if auth_events is None: if auth_events is None:
@ -491,6 +508,9 @@ class Auth(object):
if not invite_event: if not invite_event:
return False return False
if invite_event.sender != event.sender:
return False
if event.user_id != invite_event.user_id: if event.user_id != invite_event.user_id:
return False return False

View file

@ -1922,15 +1922,18 @@ class FederationHandler(BaseHandler):
original_invite = yield self.store.get_event( original_invite = yield self.store.get_event(
original_invite_id, allow_none=True original_invite_id, allow_none=True
) )
if not original_invite: if original_invite:
logger.info(
"Could not find invite event for third_party_invite - "
"discarding: %s" % (event_dict,)
)
return
display_name = original_invite.content["display_name"] display_name = original_invite.content["display_name"]
event_dict["content"]["third_party_invite"]["display_name"] = display_name event_dict["content"]["third_party_invite"]["display_name"] = display_name
else:
logger.info(
"Could not find invite event for third_party_invite: %r",
event_dict
)
# We don't discard here as this is not the appropriate place to do
# auth checks. If we need the invite and don't have it then the
# auth check code will explode appropriately.
builder = self.event_builder_factory.new(event_dict) builder = self.event_builder_factory.new(event_dict)
EventValidator().validate_new(builder) EventValidator().validate_new(builder)
message_handler = self.hs.get_handlers().message_handler message_handler = self.hs.get_handlers().message_handler

View file

@ -56,7 +56,7 @@ def get_domain_from_id(string):
try: try:
return string.split(":", 1)[1] return string.split(":", 1)[1]
except IndexError: except IndexError:
raise SynapseError(400, "Invalid ID: %r", string) raise SynapseError(400, "Invalid ID: %r" % (string,))
class DomainSpecificString( class DomainSpecificString(