Skip to content

Commit 3865b81

Browse files
authored
Add federation ACL test (#624)
* Add ACL test * Variable naming, check GET /rooms/{roomID}/state * PR review changes, check we see our sentinel event, remove comment * Skip on Dendrite for now
1 parent 69d1326 commit 3865b81

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

tests/federation_acl_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package tests
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/matrix-org/complement/internal/b"
8+
"github.com/matrix-org/complement/internal/client"
9+
"github.com/matrix-org/complement/internal/match"
10+
"github.com/matrix-org/complement/internal/must"
11+
"github.com/matrix-org/complement/runtime"
12+
)
13+
14+
// Test for https://github.com/matrix-org/dendrite/issues/3004
15+
func TestACLs(t *testing.T) {
16+
runtime.SkipIf(t, runtime.Dendrite) // needs https://github.com/matrix-org/dendrite/pull/3008
17+
// 1. Prepare 3 or more servers. 1st will be room host, 2nd will be blocked with m.room.server_acl and 3rd server will be affected by this issue. 1st and 2nd servers don't have to be powered by dendrite.
18+
deployment := Deploy(t, b.Blueprint{
19+
Name: "federation_three_homeservers",
20+
Homeservers: []b.Homeserver{
21+
{
22+
Name: "hs1",
23+
Users: []b.User{
24+
{
25+
Localpart: "alice",
26+
DisplayName: "Alice",
27+
},
28+
},
29+
},
30+
{
31+
Name: "hs2",
32+
Users: []b.User{
33+
{
34+
Localpart: "bob",
35+
DisplayName: "Bob",
36+
},
37+
},
38+
},
39+
{
40+
Name: "hs3",
41+
Users: []b.User{
42+
{
43+
Localpart: "charlie",
44+
DisplayName: "Charlie",
45+
},
46+
},
47+
},
48+
},
49+
})
50+
defer deployment.Destroy(t)
51+
52+
alice := deployment.Client(t, "hs1", "@alice:hs1")
53+
bob := deployment.Client(t, "hs2", "@bob:hs2")
54+
charlie := deployment.Client(t, "hs3", "@charlie:hs3")
55+
56+
// 2. Create room on 1st server
57+
roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"})
58+
aliceSince := alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID))
59+
60+
// 3. Join this room from 2nd server
61+
bob.JoinRoom(t, roomID, []string{"hs1"})
62+
aliceSince = alice.MustSyncUntil(t, client.SyncReq{Since: aliceSince}, client.SyncJoinedTo(bob.UserID, roomID))
63+
bobSince := bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID))
64+
65+
// create a different room used for a sentinel event
66+
sentinelRoom := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"})
67+
aliceSince = alice.MustSyncUntil(t, client.SyncReq{Since: aliceSince}, client.SyncJoinedTo(alice.UserID, sentinelRoom))
68+
bob.JoinRoom(t, sentinelRoom, []string{"hs1"})
69+
charlie.JoinRoom(t, sentinelRoom, []string{"hs1"})
70+
aliceSince = alice.MustSyncUntil(t, client.SyncReq{Since: aliceSince},
71+
client.SyncJoinedTo(bob.UserID, sentinelRoom),
72+
client.SyncJoinedTo(charlie.UserID, sentinelRoom),
73+
)
74+
75+
// 4. Add deny rule, to block 2nd server from participating
76+
stateKey := ""
77+
eventID := alice.SendEventSynced(t, roomID, b.Event{
78+
Type: "m.room.server_acl",
79+
Sender: alice.UserID,
80+
StateKey: &stateKey,
81+
Content: map[string]interface{}{
82+
"allow": []string{"*"},
83+
"allow_ip_literals": true,
84+
"deny": []string{"hs2"},
85+
},
86+
})
87+
// wait for the ACL to show up on hs2
88+
bob.MustSyncUntil(t, client.SyncReq{Since: bobSince}, client.SyncTimelineHasEventID(roomID, eventID))
89+
90+
// 5. Join from 3rd server.
91+
charlie.JoinRoom(t, roomID, []string{"hs1"})
92+
aliceSince = alice.MustSyncUntil(t, client.SyncReq{Since: aliceSince}, client.SyncJoinedTo(charlie.UserID, roomID))
93+
charlieSince := charlie.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(charlie.UserID, roomID))
94+
95+
// 6. Any events sent by 2nd server will not appear for users from 1st server, but will be visible for users from 3rd server
96+
eventID = bob.SendEventSynced(t, roomID, b.Event{
97+
Type: "m.room.message",
98+
Sender: bob.UserID,
99+
Content: map[string]interface{}{
100+
"msgtype": "m.text",
101+
"body": "I should be blocked",
102+
},
103+
})
104+
105+
// sentinel event in room2
106+
sentinelEventID := bob.SendEventSynced(t, sentinelRoom, b.Event{
107+
Type: "m.room.message",
108+
Sender: bob.UserID,
109+
Content: map[string]interface{}{
110+
"msgtype": "m.text",
111+
"body": "I should be visible",
112+
},
113+
})
114+
// wait for the sentinel event to come down sync
115+
alice.MustSyncUntil(t, client.SyncReq{Since: aliceSince}, client.SyncTimelineHasEventID(sentinelRoom, sentinelEventID))
116+
charlie.MustSyncUntil(t, client.SyncReq{Since: charlieSince}, client.SyncTimelineHasEventID(sentinelRoom, sentinelEventID))
117+
118+
// Verify with alice and charlie that we never received eventID
119+
for _, user := range []*client.CSAPI{alice, charlie} {
120+
syncResp, _ := user.MustSync(t, client.SyncReq{})
121+
122+
// we don't expect eventID (blocked) to be in the sync response
123+
events := syncResp.Get(fmt.Sprintf("rooms.join.%s.timeline.events", client.GjsonEscape(roomID))).Array()
124+
for _, ev := range events {
125+
if ev.Get("event_id").Str == eventID {
126+
t.Fatalf("unexpected eventID from ACLed room: %s", eventID)
127+
}
128+
}
129+
130+
// also check that our sentinel event is present
131+
var seenSentinelEvent bool
132+
events = syncResp.Get(fmt.Sprintf("rooms.join.%s.timeline.events", client.GjsonEscape(sentinelRoom))).Array()
133+
for _, ev := range events {
134+
if ev.Get("event_id").Str == sentinelEventID {
135+
seenSentinelEvent = true
136+
break
137+
}
138+
}
139+
140+
if !seenSentinelEvent {
141+
t.Fatalf("expected to see sentinel event but didn't")
142+
}
143+
144+
// Validate the ACL event is actually in the rooms state
145+
res := user.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.server_acl"})
146+
must.MatchResponse(t, res, match.HTTPResponse{
147+
JSON: []match.JSON{
148+
match.JSONKeyEqual("allow", []string{"*"}),
149+
match.JSONKeyEqual("deny", []string{"hs2"}),
150+
match.JSONKeyEqual("allow_ip_literals", true),
151+
},
152+
})
153+
}
154+
}

0 commit comments

Comments
 (0)