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

Return errors from send_join etc if the event is rejected #10243

Merged
merged 4 commits into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/10243.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve validation on federation `send_{join,leave,knock}` endpoints.
46 changes: 39 additions & 7 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1953,16 +1953,31 @@ async def on_send_membership_event(
self, origin: str, event: EventBase
) -> EventContext:
"""
We have received a join/leave/knock event for a room.
We have received a join/leave/knock event for a room via send_join/leave/knock.

Verify that event and send it into the room on the remote homeserver's behalf.

This is quite similar to on_receive_pdu, with the following principal
differences:
* only membership events are permitted (and only events with
sender==state_key -- ie, no kicks or bans)
* *We* send out the event on behalf of the remote server.
* We enforce the membership restrictions of restricted rooms.
* Rejected events result in an exception rather than being stored.

There are also other differences, however it is not clear if these are by
design or omission. In particular, we do not attempt to backfill any missing
prev_events.

Args:
origin: The homeserver of the remote (joining/invited/knocking) user.
event: The member event that has been signed by the remote homeserver.

Returns:
The context of the event after inserting it into the room graph.

Raises:
SynapseError if the event is not accepted into the room
"""
logger.debug(
"on_send_membership_event: Got event: %s, signatures: %s",
Expand All @@ -1981,7 +1996,7 @@ async def on_send_membership_event(
if event.sender != event.state_key:
raise SynapseError(400, "state_key and sender must match", Codes.BAD_JSON)

event.internal_metadata.outlier = False
assert not event.internal_metadata.outlier
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no way that we can have an outlier here.


# Send this event on behalf of the other server.
#
Expand All @@ -1991,6 +2006,11 @@ async def on_send_membership_event(
event.internal_metadata.send_on_behalf_of = origin

context = await self.state_handler.compute_event_context(event)
context = await self._check_event_auth(origin, event, context)
if context.rejected:
raise SynapseError(
403, f"{event.membership} event was rejected", Codes.FORBIDDEN
)

# for joins, we need to check the restrictions of restricted rooms
if event.membership == Membership.JOIN:
Expand All @@ -2008,8 +2028,8 @@ async def on_send_membership_event(
403, "This event is not allowed in this context", Codes.FORBIDDEN
)

await self._auth_and_persist_event(origin, event, context)

# all looks good, we can persist the event.
await self._run_push_actions_and_persist_event(event, context)
return context

async def _check_join_restrictions(
Expand Down Expand Up @@ -2179,6 +2199,18 @@ async def _auth_and_persist_event(
backfilled=backfilled,
)

await self._run_push_actions_and_persist_event(event, context, backfilled)

async def _run_push_actions_and_persist_event(
self, event: EventBase, context: EventContext, backfilled: bool = False
):
"""Run the push actions for a received event, and persist it.

Args:
event: The event itself.
context: The event context.
backfilled: True if the event was backfilled.
"""
try:
if (
not event.internal_metadata.is_outlier()
Expand Down Expand Up @@ -2492,9 +2524,9 @@ async def _check_event_auth(
origin: str,
event: EventBase,
context: EventContext,
state: Optional[Iterable[EventBase]],
auth_events: Optional[MutableStateMap[EventBase]],
backfilled: bool,
state: Optional[Iterable[EventBase]] = None,
auth_events: Optional[MutableStateMap[EventBase]] = None,
backfilled: bool = False,
) -> EventContext:
"""
Checks whether an event should be rejected (for failing auth checks).
Expand Down
4 changes: 1 addition & 3 deletions tests/federation/transport/test_knocking.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,7 @@ async def approve_all_signature_checking(_, pdu):

# Have this homeserver skip event auth checks. This is necessary due to
# event auth checks ensuring that events were signed by the sender's homeserver.
async def _check_event_auth(
origin, event, context, state, auth_events, backfilled
):
async def _check_event_auth(origin, event, context, *args, **kwargs):
return context

homeserver.get_federation_handler()._check_event_auth = _check_event_auth
Expand Down