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

Commit 8165ba4

Browse files
authored
Return errors from send_join etc if the event is rejected (#10243)
Rather than persisting rejected events via `send_join` and friends, raise a 403 if someone tries to pull a fast one.
1 parent 6e8fb42 commit 8165ba4

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

changelog.d/10243.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve validation on federation `send_{join,leave,knock}` endpoints.

synapse/handlers/federation.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,16 +1953,31 @@ async def on_send_membership_event(
19531953
self, origin: str, event: EventBase
19541954
) -> EventContext:
19551955
"""
1956-
We have received a join/leave/knock event for a room.
1956+
We have received a join/leave/knock event for a room via send_join/leave/knock.
19571957
19581958
Verify that event and send it into the room on the remote homeserver's behalf.
19591959
1960+
This is quite similar to on_receive_pdu, with the following principal
1961+
differences:
1962+
* only membership events are permitted (and only events with
1963+
sender==state_key -- ie, no kicks or bans)
1964+
* *We* send out the event on behalf of the remote server.
1965+
* We enforce the membership restrictions of restricted rooms.
1966+
* Rejected events result in an exception rather than being stored.
1967+
1968+
There are also other differences, however it is not clear if these are by
1969+
design or omission. In particular, we do not attempt to backfill any missing
1970+
prev_events.
1971+
19601972
Args:
19611973
origin: The homeserver of the remote (joining/invited/knocking) user.
19621974
event: The member event that has been signed by the remote homeserver.
19631975
19641976
Returns:
19651977
The context of the event after inserting it into the room graph.
1978+
1979+
Raises:
1980+
SynapseError if the event is not accepted into the room
19661981
"""
19671982
logger.debug(
19681983
"on_send_membership_event: Got event: %s, signatures: %s",
@@ -1981,7 +1996,7 @@ async def on_send_membership_event(
19811996
if event.sender != event.state_key:
19821997
raise SynapseError(400, "state_key and sender must match", Codes.BAD_JSON)
19831998

1984-
event.internal_metadata.outlier = False
1999+
assert not event.internal_metadata.outlier
19852000

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

19932008
context = await self.state_handler.compute_event_context(event)
2009+
context = await self._check_event_auth(origin, event, context)
2010+
if context.rejected:
2011+
raise SynapseError(
2012+
403, f"{event.membership} event was rejected", Codes.FORBIDDEN
2013+
)
19942014

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

2011-
await self._auth_and_persist_event(origin, event, context)
2012-
2031+
# all looks good, we can persist the event.
2032+
await self._run_push_actions_and_persist_event(event, context)
20132033
return context
20142034

20152035
async def _check_join_restrictions(
@@ -2179,6 +2199,18 @@ async def _auth_and_persist_event(
21792199
backfilled=backfilled,
21802200
)
21812201

2202+
await self._run_push_actions_and_persist_event(event, context, backfilled)
2203+
2204+
async def _run_push_actions_and_persist_event(
2205+
self, event: EventBase, context: EventContext, backfilled: bool = False
2206+
):
2207+
"""Run the push actions for a received event, and persist it.
2208+
2209+
Args:
2210+
event: The event itself.
2211+
context: The event context.
2212+
backfilled: True if the event was backfilled.
2213+
"""
21822214
try:
21832215
if (
21842216
not event.internal_metadata.is_outlier()
@@ -2492,9 +2524,9 @@ async def _check_event_auth(
24922524
origin: str,
24932525
event: EventBase,
24942526
context: EventContext,
2495-
state: Optional[Iterable[EventBase]],
2496-
auth_events: Optional[MutableStateMap[EventBase]],
2497-
backfilled: bool,
2527+
state: Optional[Iterable[EventBase]] = None,
2528+
auth_events: Optional[MutableStateMap[EventBase]] = None,
2529+
backfilled: bool = False,
24982530
) -> EventContext:
24992531
"""
25002532
Checks whether an event should be rejected (for failing auth checks).

tests/federation/transport/test_knocking.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,7 @@ async def approve_all_signature_checking(_, pdu):
205205

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

213211
homeserver.get_federation_handler()._check_event_auth = _check_event_auth

0 commit comments

Comments
 (0)