From d5633d17a49090188dd90c9898ac1ab28df9cabb Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 31 Mar 2021 11:31:51 -0400 Subject: [PATCH 01/66] Add pointer to draft. --- proposals/3083-restricted-rooms.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 proposals/3083-restricted-rooms.md diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md new file mode 100644 index 0000000000..c65b1ca829 --- /dev/null +++ b/proposals/3083-restricted-rooms.md @@ -0,0 +1,4 @@ +# Restricting room membership based on space membership + +This is still in a draft stage: see +https://hackmd.io/zO0fQwo9TqurOt66mF5Qmg for the current draft. From dfcc4675b128166409b06ae32e7039613792a65e Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 14 Apr 2021 13:07:03 -0400 Subject: [PATCH 02/66] Include the proposed MSC. --- proposals/3083-restricted-rooms.md | 161 ++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index c65b1ca829..1121ebf6a9 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -1,4 +1,161 @@ # Restricting room membership based on space membership -This is still in a draft stage: see -https://hackmd.io/zO0fQwo9TqurOt66mF5Qmg for the current draft. +Draft join rule changes for [spaces](https://github.com/matrix-org/matrix-doc/pull/1772), +this is meant to replaces the second half of [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962/). + +A desirable feature is to give room admins the power to restrict membership of +their room based on the membership of one or more spaces, for example: + +> members of the #doglovers space can join this room without an invitation[1](#f1) + +We could represent the allowed spaces with a new `join_rule` - `restricted` - to +reflect the fact that what we have is a cross between `invite` and `public`. This +would have additional content of the rooms to trust for membership. For example: + +```json +{ + "type": "m.room.join_rules", + "state_key": "", + "content": { + "join_rule": "restricted", + "allow": [ + { + "space": "!mods:example.org", + "via": ["example.org"] + }, + { + "space": "!users:example.org", + "via": ["example.org"] + } + ] + } +} +``` + +This means that a user must be a member of the `!mods:example.org` space or +`!users:example.org` space in order to join without an invite[2](#f2). Membership in +a single space is enough. + +If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the +following keys, or a string representing the MXID of the user exempted: + +* `space`: The room ID of the space to check the membership of. +* `via`: A list of servers which may be used to peek for membership of the space. + +Any entries in the list which do not match the expected format are ignored. + +When a server receives a `/join` request from a client or a `/make_join` / `/send_join` +request from a server, the request should only be permitted if the user has a valid +invite or is in one of the listed spaces (established by peeking if the server is not +already in the space, see [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444)). + +Unlike the `invite` join rule, confirmation that the `allow` rules were properly +checked cannot be enforced over federation by event authorization, so servers in +the room are trusted not to allow invalid users to join.[3](#f3) +However, user IDs listed as strings can be properly checked over federation. + +## Summary of the behaviour of join rules + +See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) +specification for full details, but the summary below should highlight the differences +between `public`, `invite`, and `restricted`. + +* `public`: anyone can join, subject to `ban` and `server_acls`, as today. +* `invite`: only people with membership `invite` can join, as today. +* `knock`: the same as `invite`, except anyone can knock, subject to `ban` and + `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). +* `private`: This is reserved and not implemented. +* `restricted`: the same as `public` from the perspective of the auth rules, but + with the additional caveat that servers are expected to check the `allow` rules + before generating a `join` event (whether for a local or a remote user). + +## Security considerations + +The `allow` feature for `join_rules` places increased trust in the servers in the + room. We consider this acceptable: if you don't want evil servers randomly + joining spurious users into your rooms, then: + +1. Don't let evil servers in your room in the first place +2. Don't use `allow` lists, given the expansion increases the attack surface anyway by letting members in other rooms dictate who's allowed into your room. + +The peek server also has significant power. For example, a poorly chosen peek +server could lie about the space membership and add an `@evil_user:example.org`. + +## Unstable prefix + +The `restricted` join rule will be included in a future room version to ensure +that servers and clients opt-into the new functionality. + +During development it is expected that an unstable room version of +`org.matrix.mscXXXX` is used. Since the room version namespaces the behaviour, +the `allow` key and the `restricted` value do not need unstable prefixes. + +## History / Rationale + +It may seem that just having the `allow` key with `public` join rules is enough, +as suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962/), +but there are concerns that having a `public` join rule that is restricted may +cause issues if an implementation does not understand the semantics of the `allow` +keyword. Using an `allow` key with `invite` join rules also does not make sense as +from the perspective of the auth rules, this is akin to `public` (since the checking +of whether a member is in the space is done during the call to `/join` +or `/make_join` / `/send_join`). + +The above concerns about an implementation not understanding the semantics of `allow` +could be solved by introducing a new room version, but if this is done it seems clearer +to just introduce a a new join rule - `restricted` - as described above. + +## Future extensions + +Potential future extensions which should not be designed out +include, but are not included in this MSC. + +### Checking space membership over federation + + + +### Kicking users out when they leave the allowed space + +In the above example, suppose `@bob:server.example` leaves `!users:example.org`: +they should be removed from the room. One option is to leave the departure up +to Bob's server `server.example`, but this places a relatively high level of trust +in that server. Additionally, if `server.example` were offline, other users in +the room would still see Bob in the room (and their servers would attempt to +send message traffic to it). + +Another consideration is that users may have joined via a direct invite, not via access through a space. + +Fixing this is thorny. Some sort of annotation on the membership events might +help. but it's unclear what the desired semantics are: + +* Assuming that users in a given space are *not* kicked when that space is + removed from `allow`, are those users then given a pass to remain + in the room indefinitely? What happens if the space is added back to + `allow` and *then* the user leaves it? +* Suppose a user joins a room via a space (SpaceA). Later, SpaceB is added to + the `allow` list and SpaceA is removed. What should happen when the + user leaves SpaceB? Are they exempt from the kick? + +### Inheriting join rules + +If you make a parent space invite-only, should that (optionally?) cascade into +child rooms? Seems to have some of the same problems as inheriting power levels, as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). + +## Footnotes + +[1]: The converse restriction, "anybody can join, provided they are not members +of the '#catlovers' space" is less useful since: + +1. Users in the banned space could simply leave it at any time +2. This functionality is already somewhat provided by [Moderation policy lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) + +[2]: Note that there is nothing stopping users sending and +receiving invites in `public` rooms today, and they work as you might expect. +The only difference is that you are not *required* to hold an invite when +joining the room. [↩](#a2) + +[3]: This is a marginal decrease in security from the current +situation. Currently, a misbehaving server can allow unauthorized users to join +any room by first issuing an invite to that user. In theory that can be +prevented by raising the PL required to send an invite, but in practice that is +rarely done. [↩](#a2) From c81947a39c5332ea36e74eb104013bd166f8f733 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 15 Apr 2021 10:27:08 -0400 Subject: [PATCH 03/66] Document the error response. --- proposals/3083-restricted-rooms.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 1121ebf6a9..b8e3198b75 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -44,11 +44,14 @@ following keys, or a string representing the MXID of the user exempted: Any entries in the list which do not match the expected format are ignored. -When a server receives a `/join` request from a client or a `/make_join` / `/send_join` +When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from a server, the request should only be permitted if the user has a valid invite or is in one of the listed spaces (established by peeking if the server is not already in the space, see [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444)). +If the user is not part of the proper space, the homeserver should return an error response +with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. + Unlike the `invite` join rule, confirmation that the `allow` rules were properly checked cannot be enforced over federation by event authorization, so servers in the room are trusted not to allow invalid users to join.[3](#f3) From 4fc5acf500c4769b0718072f64bd56a3a88e53de Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Apr 2021 08:44:48 -0400 Subject: [PATCH 04/66] Update a placeholder. --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b8e3198b75..b9945e3555 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -90,7 +90,7 @@ The `restricted` join rule will be included in a future room version to ensure that servers and clients opt-into the new functionality. During development it is expected that an unstable room version of -`org.matrix.mscXXXX` is used. Since the room version namespaces the behaviour, +`org.matrix.msc3083` is used. Since the room version namespaces the behaviour, the `allow` key and the `restricted` value do not need unstable prefixes. ## History / Rationale From 13e3f18bc44e664a57061212933b840e5114c4fd Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Apr 2021 08:49:48 -0400 Subject: [PATCH 05/66] Rework bits about peeking. --- proposals/3083-restricted-rooms.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b9945e3555..979b19b0d8 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -46,8 +46,8 @@ Any entries in the list which do not match the expected format are ignored. When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from a server, the request should only be permitted if the user has a valid -invite or is in one of the listed spaces (established by peeking if the server is not -already in the space, see [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444)). +invite or is in one of the listed spaces. Note that the server may not know if the user +is in a particular space, this is left to a future MSC to solve. If the user is not part of the proper space, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. @@ -81,9 +81,6 @@ The `allow` feature for `join_rules` places increased trust in the servers in th 1. Don't let evil servers in your room in the first place 2. Don't use `allow` lists, given the expansion increases the attack surface anyway by letting members in other rooms dictate who's allowed into your room. -The peek server also has significant power. For example, a poorly chosen peek -server could lie about the space membership and add an `@evil_user:example.org`. - ## Unstable prefix The `restricted` join rule will be included in a future room version to ensure @@ -115,7 +112,15 @@ include, but are not included in this MSC. ### Checking space membership over federation +If a server is not in a space (and thus doesn't know the membership of a space) it +cannot enforce membership of a space during a join. Peeking over federation, +as described in [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), +could be used to establish if the user is in any of the proper spaces. +Note that there are additional security considerations with this, namely that +the peek server has significant power. For example, a poorly chosen peek +server could lie about the space membership and add an `@evil_user:example.org` +to a space to gain membership to a room. ### Kicking users out when they leave the allowed space From 36b19fb08366d426fb6112a59587aecbb869ba40 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 3 May 2021 12:43:57 -0400 Subject: [PATCH 06/66] Clarify link. --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 979b19b0d8..909a153438 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -1,6 +1,6 @@ # Restricting room membership based on space membership -Draft join rule changes for [spaces](https://github.com/matrix-org/matrix-doc/pull/1772), +Draft join rule changes for [MSC1772: spaces](https://github.com/matrix-org/matrix-doc/pull/1772), this is meant to replaces the second half of [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962/). A desirable feature is to give room admins the power to restrict membership of From 2919e5752530f71981a5424a1abfe82a295874b6 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 12 May 2021 10:05:15 -0400 Subject: [PATCH 07/66] Update dependencies to include MSC3173. --- proposals/3083-restricted-rooms.md | 67 ++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 909a153438..f7846aed18 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -1,16 +1,17 @@ # Restricting room membership based on space membership -Draft join rule changes for [MSC1772: spaces](https://github.com/matrix-org/matrix-doc/pull/1772), -this is meant to replaces the second half of [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962/). - A desirable feature is to give room admins the power to restrict membership of -their room based on the membership of one or more spaces, for example: +their room based on the membership of one or more spaces from +[MSC1772: spaces](https://github.com/matrix-org/matrix-doc/pull/1772), +for example: > members of the #doglovers space can join this room without an invitation[1](#f1) -We could represent the allowed spaces with a new `join_rule` - `restricted` - to -reflect the fact that what we have is a cross between `invite` and `public`. This -would have additional content of the rooms to trust for membership. For example: +## Proposal + +A new `join_rule` (`restricted`) will be used to reflect a cross between `invite` +and `public` join rules. The content of the join rules would include the rooms +to trust for membership. For example: ```json { @@ -57,6 +58,51 @@ checked cannot be enforced over federation by event authorization, so servers in the room are trusted not to allow invalid users to join.[3](#f3) However, user IDs listed as strings can be properly checked over federation. +### Discovery of restricted rooms + +The discovery of rooms in a space, as discussed in [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946): spaces summary, +must be updated to allow for discovery of restricted rooms. + +MSC2946 defines that a room should be included in the spaces summary if it is +accessible (world-readable or if the user is already in the room). [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173) +declares that if a user can view the stripped state of a room if they are *able* +to join the room. Combining these two MSCs, the spaces summary should include +rooms with restricted join rule which a user is able to join (i.e. they're a +member of one of the spaces declared in the join rule). + +The server-server API discussed in [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) +does not know the user who is requesting a summary of the space, but should divulge +the above information if any member of a server could see it. It is up to the +calling server to properly filter this information. + +Trust is placed in the calling server: if there are any users on the calling +server in the correct space, that calling server has a right to know about the +rooms in that space and should return the relevant summaries, along with enough +information that the calling server can then do some filtering, thus an +additional field is added to the server-server response of the spaces summary: + +*TODO* + +Consider that Alice and Bob share a server; Alice is a member of a space, but Bob +is not. The remote server will not know whether the request is on behalf of Alice +or Bob (and hence whether it should share details of restricted rooms within that +space). + +Consider the above with a restricted room on a different server which defers +access to the above space. When summarizing the space, the homeserver must make +a request over federation for information on the room. The response would include +the room (since Alice is able to join it), but the calling server does not know +*why* they received the room, without additional information the server cannot +properly filter the returned results. + +(The alternative, where the calling server sends the requesting `user_id`, and +the target server does the filtering, is unattractive because it rules out a +future world where the calling server can cache the result.) + +This does not decrease security since a server could lie and make a request on +behalf of a user in the proper space to see the given information. I.e. the +calling server must be trusted anyway. + ## Summary of the behaviour of join rules See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) @@ -67,7 +113,7 @@ between `public`, `invite`, and `restricted`. * `invite`: only people with membership `invite` can join, as today. * `knock`: the same as `invite`, except anyone can knock, subject to `ban` and `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). -* `private`: This is reserved and not implemented. +* `private`: This is reserved and not implemented. * `restricted`: the same as `public` from the perspective of the auth rules, but with the additional caveat that servers are expected to check the `allow` rules before generating a `join` event (whether for a local or a remote user). @@ -92,8 +138,11 @@ the `allow` key and the `restricted` value do not need unstable prefixes. ## History / Rationale +Note that this replaces the second half of an older version of +[MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). + It may seem that just having the `allow` key with `public` join rules is enough, -as suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962/), +as suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962), but there are concerns that having a `public` join rule that is restricted may cause issues if an implementation does not understand the semantics of the `allow` keyword. Using an `allow` key with `invite` join rules also does not make sense as From fab5eaa67bdf40dcc5cac03dab773909d55db34e Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 12 May 2021 10:58:35 -0400 Subject: [PATCH 08/66] Add notes from @madlittlemods. --- proposals/3083-restricted-rooms.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index f7846aed18..d6f4ee33b8 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -174,13 +174,21 @@ to a space to gain membership to a room. ### Kicking users out when they leave the allowed space In the above example, suppose `@bob:server.example` leaves `!users:example.org`: -they should be removed from the room. One option is to leave the departure up -to Bob's server `server.example`, but this places a relatively high level of trust -in that server. Additionally, if `server.example` were offline, other users in -the room would still see Bob in the room (and their servers would attempt to -send message traffic to it). +should they be removed from the room? Likely not, by analogy with what happens +when you switch the join rules from public to invite. Join rules currently govern +joins, not existing room membership. -Another consideration is that users may have joined via a direct invite, not via access through a space. +It is left to a future MSC to consider this, but some potential thoughts are +given below. + +If you assume that a user *should* be removed in this case, one option is to +leave the departure up to Bob's server `server.example`, but this places a +relatively high level of trust in that server. Additionally, if `server.example` +were offline, other users in the room would still see Bob in the room (and their +servers would attempt to send message traffic to it). + +Another consideration is that users may have joined via a direct invite, not via +access through a space. Fixing this is thorny. Some sort of annotation on the membership events might help. but it's unclear what the desired semantics are: @@ -193,6 +201,9 @@ help. but it's unclear what the desired semantics are: the `allow` list and SpaceA is removed. What should happen when the user leaves SpaceB? Are they exempt from the kick? +It is possible that completely different state should be kept, or a different +`m.room.member` state could be used in a more reasonable way to track this. + ### Inheriting join rules If you make a parent space invite-only, should that (optionally?) cascade into From 5afe23a1c0033ee514c780e6ab87469eb218e400 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 12 May 2021 11:16:27 -0400 Subject: [PATCH 09/66] More wrapping. --- proposals/3083-restricted-rooms.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index d6f4ee33b8..daa08e69ec 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -34,10 +34,11 @@ to trust for membership. For example: ``` This means that a user must be a member of the `!mods:example.org` space or -`!users:example.org` space in order to join without an invite[2](#f2). Membership in -a single space is enough. +`!users:example.org` space in order to join without an invite[2](#f2). +Membership in a single space is enough. -If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the +If the `allow` key is an empty list (or not a list at all), then no users are +allowed to join without an invite. Each entry is expected to be an object with the following keys, or a string representing the MXID of the user exempted: * `space`: The room ID of the space to check the membership of. @@ -50,8 +51,8 @@ request from a server, the request should only be permitted if the user has a va invite or is in one of the listed spaces. Note that the server may not know if the user is in a particular space, this is left to a future MSC to solve. -If the user is not part of the proper space, the homeserver should return an error response -with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +If the user is not part of the proper space, the homeserver should return an error +response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Unlike the `invite` join rule, confirmation that the `allow` rules were properly checked cannot be enforced over federation by event authorization, so servers in @@ -60,7 +61,8 @@ However, user IDs listed as strings can be properly checked over federation. ### Discovery of restricted rooms -The discovery of rooms in a space, as discussed in [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946): spaces summary, +The discovery of rooms in a space, as discussed in +[MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946): spaces summary, must be updated to allow for discovery of restricted rooms. MSC2946 defines that a room should be included in the spaces summary if it is @@ -125,7 +127,8 @@ The `allow` feature for `join_rules` places increased trust in the servers in th joining spurious users into your rooms, then: 1. Don't let evil servers in your room in the first place -2. Don't use `allow` lists, given the expansion increases the attack surface anyway by letting members in other rooms dictate who's allowed into your room. +2. Don't use `allow` lists, given the expansion increases the attack surface anyway + by letting members in other rooms dictate who's allowed into your room. ## Unstable prefix @@ -207,7 +210,8 @@ It is possible that completely different state should be kept, or a different ### Inheriting join rules If you make a parent space invite-only, should that (optionally?) cascade into -child rooms? Seems to have some of the same problems as inheriting power levels, as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). +child rooms? Seems to have some of the same problems as inheriting power levels, +as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). ## Footnotes From 590b7a48e7e7f531b28083a8043e714cac15f846 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 12 May 2021 14:36:32 -0400 Subject: [PATCH 10/66] Fill in the TODO about what how to mark access via spaces for the summary API. --- proposals/3083-restricted-rooms.md | 36 +++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index daa08e69ec..71a0cd6be1 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -83,7 +83,41 @@ rooms in that space and should return the relevant summaries, along with enough information that the calling server can then do some filtering, thus an additional field is added to the server-server response of the spaces summary: -*TODO* +* `allowed_spaces`: A list of space IDs which give access to this room. + +This would modify the example response given to: + +```jsonc +{ + "rooms": [ + { + "room_id": "!ol19s:bleecker.street", + "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE", + "guest_can_join": false, + "name": "CHEESE", + "num_joined_members": 37, + "topic": "Tasty tasty cheese", + "world_readable": true, + "room_type": "m.space", + "allowed_spaces": ["!mods:example.org", "!users:example.org"] + }, + { ... } + ], + "events": [ + { + "type": "m.space.child", + "state_key": "!efgh:example.com", + "content": { + "via": ["example.com"], + "suggested": true + }, + "room_id": "!ol19s:bleecker.street", + "sender": "@alice:bleecker.street" + }, + { ... } + ] +} +``` Consider that Alice and Bob share a server; Alice is a member of a space, but Bob is not. The remote server will not know whether the request is on behalf of Alice From cbc4515a9463b82f48667324db95a76d09935c6f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 13 May 2021 08:37:09 -0400 Subject: [PATCH 11/66] Spacing. --- proposals/3083-restricted-rooms.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 71a0cd6be1..a3e5bd2eb8 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -9,7 +9,7 @@ for example: ## Proposal -A new `join_rule` (`restricted`) will be used to reflect a cross between `invite` +A new `join_rule` (`restricted`) will be used to reflect a cross between `invite` and `public` join rules. The content of the join rules would include the rooms to trust for membership. For example: @@ -35,7 +35,7 @@ to trust for membership. For example: This means that a user must be a member of the `!mods:example.org` space or `!users:example.org` space in order to join without an invite[2](#f2). -Membership in a single space is enough. +Membership in a single space is enough. If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the @@ -52,9 +52,9 @@ invite or is in one of the listed spaces. Note that the server may not know if t is in a particular space, this is left to a future MSC to solve. If the user is not part of the proper space, the homeserver should return an error -response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. -Unlike the `invite` join rule, confirmation that the `allow` rules were properly +Unlike the `invite` join rule, confirmation that the `allow` rules were properly checked cannot be enforced over federation by event authorization, so servers in the room are trusted not to allow invalid users to join.[3](#f3) However, user IDs listed as strings can be properly checked over federation. @@ -120,8 +120,8 @@ This would modify the example response given to: ``` Consider that Alice and Bob share a server; Alice is a member of a space, but Bob -is not. The remote server will not know whether the request is on behalf of Alice -or Bob (and hence whether it should share details of restricted rooms within that +is not. The remote server will not know whether the request is on behalf of Alice +or Bob (and hence whether it should share details of restricted rooms within that space). Consider the above with a restricted room on a different server which defers @@ -157,8 +157,8 @@ between `public`, `invite`, and `restricted`. ## Security considerations The `allow` feature for `join_rules` places increased trust in the servers in the - room. We consider this acceptable: if you don't want evil servers randomly - joining spurious users into your rooms, then: +room. We consider this acceptable: if you don't want evil servers randomly +joining spurious users into your rooms, then: 1. Don't let evil servers in your room in the first place 2. Don't use `allow` lists, given the expansion increases the attack surface anyway @@ -193,8 +193,8 @@ to just introduce a a new join rule - `restricted` - as described above. ## Future extensions -Potential future extensions which should not be designed out -include, but are not included in this MSC. +Potential future extensions which should not be designed out include, but are not +included in this MSC. ### Checking space membership over federation @@ -219,10 +219,10 @@ It is left to a future MSC to consider this, but some potential thoughts are given below. If you assume that a user *should* be removed in this case, one option is to -leave the departure up to Bob's server `server.example`, but this places a -relatively high level of trust in that server. Additionally, if `server.example` -were offline, other users in the room would still see Bob in the room (and their -servers would attempt to send message traffic to it). +leave the departure up to Bob's server `server.example`, but this places a +relatively high level of trust in that server. Additionally, if `server.example` +were offline, other users in the room would still see Bob in the room (and their +servers would attempt to send message traffic to it). Another consideration is that users may have joined via a direct invite, not via access through a space. @@ -261,7 +261,7 @@ The only difference is that you are not *required* to hold an invite when joining the room. [↩](#a2) [3]: This is a marginal decrease in security from the current -situation. Currently, a misbehaving server can allow unauthorized users to join +situation. Currently, a misbehaving server can allow unauthorized users to join any room by first issuing an invite to that user. In theory that can be prevented by raising the PL required to send an invite, but in practice that is rarely done. [↩](#a2) From 4eeb27f467c85772b19e412ff6b1f24045bca9e5 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 13 May 2021 08:41:32 -0400 Subject: [PATCH 12/66] Add more notes about edge-cases. --- proposals/3083-restricted-rooms.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index a3e5bd2eb8..768529988e 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -131,6 +131,12 @@ the room (since Alice is able to join it), but the calling server does not know *why* they received the room, without additional information the server cannot properly filter the returned results. +Note that there are still potential situations where each server individually +doesn't have enough information to properly return the full summary, but these +do not seem reasonable in what is considered a normal structure of spaces. (E.g. +in the above example, if the remote server is not in the space and does not know +whether the server is in the space or not it cannot return the room.) + (The alternative, where the calling server sends the requesting `user_id`, and the target server does the filtering, is unattractive because it rules out a future world where the calling server can cache the result.) From 0f4961118eddaf2959ad1d765dd3a0c8422df0a6 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 4 Jun 2021 08:24:49 -0400 Subject: [PATCH 13/66] Remove spaces summary changes. --- proposals/3083-restricted-rooms.md | 86 ------------------------------ 1 file changed, 86 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 768529988e..c21e40784f 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -59,92 +59,6 @@ checked cannot be enforced over federation by event authorization, so servers in the room are trusted not to allow invalid users to join.[3](#f3) However, user IDs listed as strings can be properly checked over federation. -### Discovery of restricted rooms - -The discovery of rooms in a space, as discussed in -[MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946): spaces summary, -must be updated to allow for discovery of restricted rooms. - -MSC2946 defines that a room should be included in the spaces summary if it is -accessible (world-readable or if the user is already in the room). [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173) -declares that if a user can view the stripped state of a room if they are *able* -to join the room. Combining these two MSCs, the spaces summary should include -rooms with restricted join rule which a user is able to join (i.e. they're a -member of one of the spaces declared in the join rule). - -The server-server API discussed in [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946) -does not know the user who is requesting a summary of the space, but should divulge -the above information if any member of a server could see it. It is up to the -calling server to properly filter this information. - -Trust is placed in the calling server: if there are any users on the calling -server in the correct space, that calling server has a right to know about the -rooms in that space and should return the relevant summaries, along with enough -information that the calling server can then do some filtering, thus an -additional field is added to the server-server response of the spaces summary: - -* `allowed_spaces`: A list of space IDs which give access to this room. - -This would modify the example response given to: - -```jsonc -{ - "rooms": [ - { - "room_id": "!ol19s:bleecker.street", - "avatar_url": "mxc://bleecker.street/CHEDDARandBRIE", - "guest_can_join": false, - "name": "CHEESE", - "num_joined_members": 37, - "topic": "Tasty tasty cheese", - "world_readable": true, - "room_type": "m.space", - "allowed_spaces": ["!mods:example.org", "!users:example.org"] - }, - { ... } - ], - "events": [ - { - "type": "m.space.child", - "state_key": "!efgh:example.com", - "content": { - "via": ["example.com"], - "suggested": true - }, - "room_id": "!ol19s:bleecker.street", - "sender": "@alice:bleecker.street" - }, - { ... } - ] -} -``` - -Consider that Alice and Bob share a server; Alice is a member of a space, but Bob -is not. The remote server will not know whether the request is on behalf of Alice -or Bob (and hence whether it should share details of restricted rooms within that -space). - -Consider the above with a restricted room on a different server which defers -access to the above space. When summarizing the space, the homeserver must make -a request over federation for information on the room. The response would include -the room (since Alice is able to join it), but the calling server does not know -*why* they received the room, without additional information the server cannot -properly filter the returned results. - -Note that there are still potential situations where each server individually -doesn't have enough information to properly return the full summary, but these -do not seem reasonable in what is considered a normal structure of spaces. (E.g. -in the above example, if the remote server is not in the space and does not know -whether the server is in the space or not it cannot return the room.) - -(The alternative, where the calling server sends the requesting `user_id`, and -the target server does the filtering, is unattractive because it rules out a -future world where the calling server can cache the result.) - -This does not decrease security since a server could lie and make a request on -behalf of a user in the proper space to see the given information. I.e. the -calling server must be trusted anyway. - ## Summary of the behaviour of join rules See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) From c7ab867cefe28bca54381d93cca824d50a892109 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 4 Jun 2021 08:25:23 -0400 Subject: [PATCH 14/66] Fix broken backlink. --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index c21e40784f..be507cb532 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -184,4 +184,4 @@ joining the room. [↩](#a2) situation. Currently, a misbehaving server can allow unauthorized users to join any room by first issuing an invite to that user. In theory that can be prevented by raising the PL required to send an invite, but in practice that is -rarely done. [↩](#a2) +rarely done. [↩](#a3) From c1eb461c8cc8d4578b6165fd68ab77a1ea39030a Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 4 Jun 2021 08:33:26 -0400 Subject: [PATCH 15/66] Remove bit about user IDs being listed directly. --- proposals/3083-restricted-rooms.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index be507cb532..aa8f25e780 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -39,7 +39,7 @@ Membership in a single space is enough. If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the -following keys, or a string representing the MXID of the user exempted: +following keys: * `space`: The room ID of the space to check the membership of. * `via`: A list of servers which may be used to peek for membership of the space. @@ -57,7 +57,6 @@ response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Unlike the `invite` join rule, confirmation that the `allow` rules were properly checked cannot be enforced over federation by event authorization, so servers in the room are trusted not to allow invalid users to join.[3](#f3) -However, user IDs listed as strings can be properly checked over federation. ## Summary of the behaviour of join rules From 41dd06d355f42400959a963847defc5a25c6f9c6 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 4 Jun 2021 08:33:38 -0400 Subject: [PATCH 16/66] Clarify an edge case. --- proposals/3083-restricted-rooms.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index aa8f25e780..5399fb4ce0 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -48,12 +48,16 @@ Any entries in the list which do not match the expected format are ignored. When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from a server, the request should only be permitted if the user has a valid -invite or is in one of the listed spaces. Note that the server may not know if the user -is in a particular space, this is left to a future MSC to solve. +invite or is in one of the listed spaces. If the user is not part of the proper space, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +It is possible for a homeserver receiving a `/make_join` / `/send_join` request +to not know if the user is in a particular space (due to not participating in any +of the necessary spaces). In this case the homeserver should reject the join, +the requesting server may wish to attempt to join via other homeservers. + Unlike the `invite` join rule, confirmation that the `allow` rules were properly checked cannot be enforced over federation by event authorization, so servers in the room are trusted not to allow invalid users to join.[3](#f3) From e81686c7d040c30060368032f73b4fb721d8580d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 4 Jun 2021 08:52:35 -0400 Subject: [PATCH 17/66] Many clarifications. --- proposals/3083-restricted-rooms.md | 59 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 5399fb4ce0..62d4029c56 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -59,7 +59,7 @@ of the necessary spaces). In this case the homeserver should reject the join, the requesting server may wish to attempt to join via other homeservers. Unlike the `invite` join rule, confirmation that the `allow` rules were properly -checked cannot be enforced over federation by event authorization, so servers in +checked cannot be enforced over federation by event authorisation, so servers in the room are trusted not to allow invalid users to join.[3](#f3) ## Summary of the behaviour of join rules @@ -72,10 +72,10 @@ between `public`, `invite`, and `restricted`. * `invite`: only people with membership `invite` can join, as today. * `knock`: the same as `invite`, except anyone can knock, subject to `ban` and `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). -* `private`: This is reserved and not implemented. -* `restricted`: the same as `public` from the perspective of the auth rules, but - with the additional caveat that servers are expected to check the `allow` rules - before generating a `join` event (whether for a local or a remote user). +* `private`: This is reserved, but unspecified. +* `restricted`: the same as `public` from the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), + but with the additional caveat that servers are expected to check the `allow` + rules before generating a `join` event (whether for a local or a remote user). ## Security considerations @@ -89,36 +89,31 @@ joining spurious users into your rooms, then: ## Unstable prefix -The `restricted` join rule will be included in a future room version to ensure -that servers and clients opt-into the new functionality. +The `restricted` join rule will be included in a future room version to allow +servers and clients to opt-into the new functionality. -During development it is expected that an unstable room version of -`org.matrix.msc3083` is used. Since the room version namespaces the behaviour, -the `allow` key and the `restricted` value do not need unstable prefixes. +During development, an unstable room version of `org.matrix.msc3083` will be used. +Since the room version namespaces the behaviour, the `allow` key and the +`restricted` value do not need unstable prefixes. -## History / Rationale +## Alternatives -Note that this replaces the second half of an older version of -[MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). - -It may seem that just having the `allow` key with `public` join rules is enough, -as suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962), +It may seem that just having the `allow` key with `public` join rules is enough +(as originally suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962)), but there are concerns that having a `public` join rule that is restricted may -cause issues if an implementation does not understand the semantics of the `allow` -keyword. Using an `allow` key with `invite` join rules also does not make sense as -from the perspective of the auth rules, this is akin to `public` (since the checking -of whether a member is in the space is done during the call to `/join` -or `/make_join` / `/send_join`). +cause issues if an implementation has not been updated to understand the semantics +of the `allow` keyword. This could be solved by introducing a new room version, +but in that case it seems clearer to introduce the `restricted` join rule, as +described above. -The above concerns about an implementation not understanding the semantics of `allow` -could be solved by introducing a new room version, but if this is done it seems clearer -to just introduce a a new join rule - `restricted` - as described above. +Using an `allow` key with `invite` join rules to broaden who can join was rejected +as an option since it requires weakening the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules). +From the perspective of the auth rules, the `restricted` join rule is identical +to `public` (since the checking of whether a member is in the space is done during +the call to `/join` or `/make_join` / `/send_join` regardless). ## Future extensions -Potential future extensions which should not be designed out include, but are not -included in this MSC. - ### Checking space membership over federation If a server is not in a space (and thus doesn't know the membership of a space) it @@ -131,6 +126,9 @@ the peek server has significant power. For example, a poorly chosen peek server could lie about the space membership and add an `@evil_user:example.org` to a space to gain membership to a room. +This MSC recommends rejecting the join in this case and allowing the requesting +homeserver to ask another homeserver. + ### Kicking users out when they leave the allowed space In the above example, suppose `@bob:server.example` leaves `!users:example.org`: @@ -167,7 +165,7 @@ It is possible that completely different state should be kept, or a different ### Inheriting join rules If you make a parent space invite-only, should that (optionally?) cascade into -child rooms? Seems to have some of the same problems as inheriting power levels, +child rooms? This would have some of the same problems as inheriting power levels, as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). ## Footnotes @@ -176,7 +174,8 @@ as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). of the '#catlovers' space" is less useful since: 1. Users in the banned space could simply leave it at any time -2. This functionality is already somewhat provided by [Moderation policy lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) +2. This functionality is already partially provided by + [Moderation policy lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) [2]: Note that there is nothing stopping users sending and receiving invites in `public` rooms today, and they work as you might expect. @@ -184,7 +183,7 @@ The only difference is that you are not *required* to hold an invite when joining the room. [↩](#a2) [3]: This is a marginal decrease in security from the current -situation. Currently, a misbehaving server can allow unauthorized users to join +situation. Currently, a misbehaving server can allow unauthorised users to join any room by first issuing an invite to that user. In theory that can be prevented by raising the PL required to send an invite, but in practice that is rarely done. [↩](#a3) From 8a3ad4717519c5737fbfefb1ee1b2d6ecce035e7 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 4 Jun 2021 08:57:41 -0400 Subject: [PATCH 18/66] A bit less passive. --- proposals/3083-restricted-rooms.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 62d4029c56..b3daba6d39 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -2,8 +2,7 @@ A desirable feature is to give room admins the power to restrict membership of their room based on the membership of one or more spaces from -[MSC1772: spaces](https://github.com/matrix-org/matrix-doc/pull/1772), -for example: +[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772), for example: > members of the #doglovers space can join this room without an invitation[1](#f1) @@ -74,8 +73,8 @@ between `public`, `invite`, and `restricted`. `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). * `private`: This is reserved, but unspecified. * `restricted`: the same as `public` from the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), - but with the additional caveat that servers are expected to check the `allow` - rules before generating a `join` event (whether for a local or a remote user). + but with the additional caveat that servers must check the `allow` rules before + generating a `join` event (whether for a local or a remote user). ## Security considerations From 1d1d356aca2b665aa67e0df2a47398612d890eee Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 10 Jun 2021 12:02:14 -0400 Subject: [PATCH 19/66] Space -> room. --- proposals/3083-restricted-rooms.md | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b3daba6d39..9146c457ce 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -20,11 +20,11 @@ to trust for membership. For example: "join_rule": "restricted", "allow": [ { - "space": "!mods:example.org", + "room": "!mods:example.org", "via": ["example.org"] }, { - "space": "!users:example.org", + "room": "!users:example.org", "via": ["example.org"] } ] @@ -32,29 +32,29 @@ to trust for membership. For example: } ``` -This means that a user must be a member of the `!mods:example.org` space or -`!users:example.org` space in order to join without an invite[2](#f2). -Membership in a single space is enough. +This means that a user must be a member of the `!mods:example.org` room or +`!users:example.org` room in order to join without an invite[2](#f2). +Membership in a single room is enough. If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the following keys: -* `space`: The room ID of the space to check the membership of. -* `via`: A list of servers which may be used to peek for membership of the space. +* `room`: The room ID to check the membership of. +* `via`: A list of servers which may be used to peek for membership of the room. Any entries in the list which do not match the expected format are ignored. When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from a server, the request should only be permitted if the user has a valid -invite or is in one of the listed spaces. +invite or is in one of the listed rooms. -If the user is not part of the proper space, the homeserver should return an error -response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +If the user is not a member of at least one of the rooms, the homeserver should +return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. It is possible for a homeserver receiving a `/make_join` / `/send_join` request -to not know if the user is in a particular space (due to not participating in any -of the necessary spaces). In this case the homeserver should reject the join, +to not know if the user is in a particular room (due to not participating in any +of the necessary rooms). In this case the homeserver should reject the join, the requesting server may wish to attempt to join via other homeservers. Unlike the `invite` join rule, confirmation that the `allow` rules were properly @@ -108,22 +108,22 @@ described above. Using an `allow` key with `invite` join rules to broaden who can join was rejected as an option since it requires weakening the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules). From the perspective of the auth rules, the `restricted` join rule is identical -to `public` (since the checking of whether a member is in the space is done during +to `public` (since the checking of whether a member is in the room is done during the call to `/join` or `/make_join` / `/send_join` regardless). ## Future extensions -### Checking space membership over federation +### Checking room membership over federation -If a server is not in a space (and thus doesn't know the membership of a space) it -cannot enforce membership of a space during a join. Peeking over federation, +If a server is not in a room (and thus doesn't know the membership of a room) it +cannot enforce membership of a room during a join. Peeking over federation, as described in [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), -could be used to establish if the user is in any of the proper spaces. +could be used to establish if the user is in any of the proper rooms. Note that there are additional security considerations with this, namely that the peek server has significant power. For example, a poorly chosen peek -server could lie about the space membership and add an `@evil_user:example.org` -to a space to gain membership to a room. +server could lie about the room membership and add an `@evil_user:example.org` +to a room to gain membership to a room. This MSC recommends rejecting the join in this case and allowing the requesting homeserver to ask another homeserver. @@ -145,7 +145,7 @@ were offline, other users in the room would still see Bob in the room (and their servers would attempt to send message traffic to it). Another consideration is that users may have joined via a direct invite, not via -access through a space. +access through a room. Fixing this is thorny. Some sort of annotation on the membership events might help. but it's unclear what the desired semantics are: @@ -172,7 +172,7 @@ as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). [1]: The converse restriction, "anybody can join, provided they are not members of the '#catlovers' space" is less useful since: -1. Users in the banned space could simply leave it at any time +1. Users in the banned room could simply leave it at any time 2. This functionality is already partially provided by [Moderation policy lists](https://matrix.org/docs/spec/client_server/r0.6.1#moderation-policy-lists). [↩](#a1) From 7061e199e0c7ab3d6b0acdcd748cbb74387c8e1d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 10 Jun 2021 12:16:01 -0400 Subject: [PATCH 20/66] Add a type field. --- proposals/3083-restricted-rooms.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 9146c457ce..fda815927f 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -20,10 +20,12 @@ to trust for membership. For example: "join_rule": "restricted", "allow": [ { + "type": "room-membership", "room": "!mods:example.org", "via": ["example.org"] }, { + "type": "room-membership", "room": "!users:example.org", "via": ["example.org"] } @@ -40,10 +42,14 @@ If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the following keys: +* `type`: `"room-membership"` to describe that we are allowing access via room + membership. Future MSCs may define other types. * `room`: The room ID to check the membership of. * `via`: A list of servers which may be used to peek for membership of the room. -Any entries in the list which do not match the expected format are ignored. +Any entries in the list which do not match the expected format are ignored. Thus, +if all entries are invalid, the list behaves as if empty and all users without +an invite are rejected. When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from a server, the request should only be permitted if the user has a valid @@ -167,6 +173,17 @@ If you make a parent space invite-only, should that (optionally?) cascade into child rooms? This would have some of the same problems as inheriting power levels, as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). +### Additional allow types + +Future MSCs may wish to define additional values for the `type` argument, potentially +restricting access via: + +* MXIDs or servers. +* A shared secret (room password). + +These are just examples are not fully thought through for this MSC, but it should +be possible to add these behaviors in the future. + ## Footnotes [1]: The converse restriction, "anybody can join, provided they are not members From 5a58af676ea39d816baa5567eb62c636afea4d4c Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 15 Jun 2021 13:11:57 -0400 Subject: [PATCH 21/66] Namespace the allow type. --- proposals/3083-restricted-rooms.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index fda815927f..506067c560 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -20,12 +20,12 @@ to trust for membership. For example: "join_rule": "restricted", "allow": [ { - "type": "room-membership", + "type": "m.room_membership", "room": "!mods:example.org", "via": ["example.org"] }, { - "type": "room-membership", + "type": "m.room_membership", "room": "!users:example.org", "via": ["example.org"] } @@ -42,7 +42,7 @@ If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the following keys: -* `type`: `"room-membership"` to describe that we are allowing access via room +* `type`: `"m.room_membership"` to describe that we are allowing access via room membership. Future MSCs may define other types. * `room`: The room ID to check the membership of. * `via`: A list of servers which may be used to peek for membership of the room. @@ -98,8 +98,8 @@ The `restricted` join rule will be included in a future room version to allow servers and clients to opt-into the new functionality. During development, an unstable room version of `org.matrix.msc3083` will be used. -Since the room version namespaces the behaviour, the `allow` key and the -`restricted` value do not need unstable prefixes. +Since the room version namespaces the behaviour, the `allow` key and value, as well +as the `restricted` join rule value do not need unstable prefixes. ## Alternatives From f3e7fba85f073d16238a0047c435312958d2796b Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 15 Jun 2021 13:13:17 -0400 Subject: [PATCH 22/66] Re-iterate that ban and server-acls matter. --- proposals/3083-restricted-rooms.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 506067c560..85ef353c2d 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -74,7 +74,8 @@ specification for full details, but the summary below should highlight the diffe between `public`, `invite`, and `restricted`. * `public`: anyone can join, subject to `ban` and `server_acls`, as today. -* `invite`: only people with membership `invite` can join, as today. +* `invite`: only people with membership `invite` can join, subject to `ban` and + `server_acls`, as today. * `knock`: the same as `invite`, except anyone can knock, subject to `ban` and `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). * `private`: This is reserved, but unspecified. From ed679c71f58acc1901e4f30497fa16ab0ee53aec Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 15 Jun 2021 13:24:15 -0400 Subject: [PATCH 23/66] Clarify membership checking over federation. --- proposals/3083-restricted-rooms.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 85ef353c2d..b363714030 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -123,8 +123,8 @@ the call to `/join` or `/make_join` / `/send_join` regardless). ### Checking room membership over federation If a server is not in a room (and thus doesn't know the membership of a room) it -cannot enforce membership of a room during a join. Peeking over federation, -as described in [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), +cannot enforce membership of a room during a call to `/make_join`, or `/send_join`. +Peeking over federation, as described in [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), could be used to establish if the user is in any of the proper rooms. Note that there are additional security considerations with this, namely that @@ -132,8 +132,8 @@ the peek server has significant power. For example, a poorly chosen peek server could lie about the room membership and add an `@evil_user:example.org` to a room to gain membership to a room. -This MSC recommends rejecting the join in this case and allowing the requesting -homeserver to ask another homeserver. +As iterated above, this MSC recommends rejecting the join, potentially allowing +the requesting homeserver to retry via another homeserver. ### Kicking users out when they leave the allowed space From bfa0dfe6008cc65c4e5bf5cdf9c8d8505d42e219 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 15 Jun 2021 13:29:13 -0400 Subject: [PATCH 24/66] Clarify auth rules for restrictedjoin rules. --- proposals/3083-restricted-rooms.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b363714030..d3b0e4a0af 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -51,6 +51,10 @@ Any entries in the list which do not match the expected format are ignored. Thus if all entries are invalid, the list behaves as if empty and all users without an invite are rejected. +From the perspective of hee [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), +the `restricted` join rule has the same behavior as `public`. Additional checks +against the `allow` rules are performed during event generation, as described below. + When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from a server, the request should only be permitted if the user has a valid invite or is in one of the listed rooms. From 39b9a9d582cb8eb9ef9295861202dc676acdd66d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 15 Jun 2021 14:34:34 -0400 Subject: [PATCH 25/66] Clarify security concerns. --- proposals/3083-restricted-rooms.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index d3b0e4a0af..ec2893b18b 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -90,8 +90,12 @@ between `public`, `invite`, and `restricted`. ## Security considerations The `allow` feature for `join_rules` places increased trust in the servers in the -room. We consider this acceptable: if you don't want evil servers randomly -joining spurious users into your rooms, then: +room. Any server which is joined to the room will be able to issue join events +for the room, there are situations which no individual server in the room can +verify that the membership event was issued in good faith. + +We consider this acceptable: if you don't want evil servers randomly joining +spurious users into your rooms, then: 1. Don't let evil servers in your room in the first place 2. Don't use `allow` lists, given the expansion increases the attack surface anyway @@ -122,6 +126,12 @@ From the perspective of the auth rules, the `restricted` join rule is identical to `public` (since the checking of whether a member is in the room is done during the call to `/join` or `/make_join` / `/send_join` regardless). +It was also considered to limit servers which can issue join membership events +to those in the `via` field (or some other list of trusted servers). This is +undesirable since it would increase centralization (e.g. a server already in the +room couldn't issue membership events for another user on that server). It is +unclear that this would significantly increase the security of the room. + ## Future extensions ### Checking room membership over federation From 91c761271650299449d4dbd02808938cc208f2e0 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 16 Jun 2021 14:12:00 -0400 Subject: [PATCH 26/66] Handle feedback from Travis. --- proposals/3083-restricted-rooms.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index ec2893b18b..e3415cbef6 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -8,9 +8,9 @@ their room based on the membership of one or more spaces from ## Proposal -A new `join_rule` (`restricted`) will be used to reflect a cross between `invite` -and `public` join rules. The content of the join rules would include the rooms -to trust for membership. For example: +In a future room version a new `join_rule` (`restricted`) will be used to reflect +a cross between `invite` and `public` join rules. The content of the join rules +would include the rooms to trust for membership. For example: ```json { @@ -21,12 +21,12 @@ to trust for membership. For example: "allow": [ { "type": "m.room_membership", - "room": "!mods:example.org", + "room_id": "!mods:example.org", "via": ["example.org"] }, { "type": "m.room_membership", - "room": "!users:example.org", + "room_id": "!users:example.org", "via": ["example.org"] } ] @@ -44,14 +44,14 @@ following keys: * `type`: `"m.room_membership"` to describe that we are allowing access via room membership. Future MSCs may define other types. -* `room`: The room ID to check the membership of. +* `room_id`: The room ID to check the membership of. * `via`: A list of servers which may be used to peek for membership of the room. Any entries in the list which do not match the expected format are ignored. Thus, if all entries are invalid, the list behaves as if empty and all users without an invite are rejected. -From the perspective of hee [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), +From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`. Additional checks against the `allow` rules are performed during event generation, as described below. From 39fdfa3fcbfbd518a7dd011fe5fde79041f84e80 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 17 Jun 2021 14:20:49 -0400 Subject: [PATCH 27/66] Add a list of trusted servers. --- proposals/3083-restricted-rooms.md | 137 ++++++++++++++++------------- 1 file changed, 74 insertions(+), 63 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index e3415cbef6..b13589cd90 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -29,14 +29,15 @@ would include the rooms to trust for membership. For example: "room_id": "!users:example.org", "via": ["example.org"] } - ] + ], + "authorised_servers": ["example.org"] } } ``` This means that a user must be a member of the `!mods:example.org` room or `!users:example.org` room in order to join without an invite[2](#f2). -Membership in a single room is enough. +Membership in a single allowed room is enough. If the `allow` key is an empty list (or not a list at all), then no users are allowed to join without an invite. Each entry is expected to be an object with the @@ -51,30 +52,46 @@ Any entries in the list which do not match the expected format are ignored. Thus if all entries are invalid, the list behaves as if empty and all users without an invite are rejected. -From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), -the `restricted` join rule has the same behavior as `public`. Additional checks -against the `allow` rules are performed during event generation, as described below. - -When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` -request from a server, the request should only be permitted if the user has a valid -invite or is in one of the listed rooms. +The `authorised_servers` key lists servers which are trusted to verify the above +allow rules. It must be a list of string server name, a special value of `"*"` +can be used to allow any server with a member in the room. Any non-string entries +are discarded, if the list is non-existent or empty then no users may join without +an invite.[3](#f3) -If the user is not a member of at least one of the rooms, the homeserver should -return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), +the `restricted` join rule has the same behavior as `public`, with the additional +caveat that servers must ensure that: + +* The user's current membership is `invite` or `join`, or +* The `m.room.member` event has a valid signature from one of the servers listed + in `authorised_servers`. + +The above check must also be performed against the current room state to potentially +soft-fail the event. This is the primary mechanism for guarding against state +changes when old events are referenced. (E.g. if an authorised server is removed +it should not be able to issue new membership events by referencing an old event +in the room.) + +When an authorised homeserver receives a `/join` request from a client or a +`/make_join` / `/send_join` request from another homeserver, the request should +only be permitted if the user has a valid invite or is in one of the listed rooms. +If the user is not a member of at least one of the rooms, the authorised homeserver +should return an error response with HTTP status code of 403 and an `errcode` of +`M_FORBIDDEN`. It is possible for a homeserver receiving a `/make_join` / `/send_join` request to not know if the user is in a particular room (due to not participating in any of the necessary rooms). In this case the homeserver should reject the join, -the requesting server may wish to attempt to join via other homeservers. +the requesting server may wish to attempt to join via another authorised homeserver. -Unlike the `invite` join rule, confirmation that the `allow` rules were properly -checked cannot be enforced over federation by event authorisation, so servers in -the room are trusted not to allow invalid users to join.[3](#f3) +Note that the authorised homeservers have significant power, as they are trusted +to confirm that the `allow` rules were properly checked (since this cannot +easily be enforced over federation by event authorisation).[4](#f4) ## Summary of the behaviour of join rules See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) -specification for full details, but the summary below should highlight the differences +specification for full details, the summary below is meant to highlight the differences between `public`, `invite`, and `restricted`. * `public`: anyone can join, subject to `ban` and `server_acls`, as today. @@ -83,23 +100,19 @@ between `public`, `invite`, and `restricted`. * `knock`: the same as `invite`, except anyone can knock, subject to `ban` and `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). * `private`: This is reserved, but unspecified. -* `restricted`: the same as `public` from the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), - but with the additional caveat that servers must check the `allow` rules before - generating a `join` event (whether for a local or a remote user). +* `restricted`: the same as `public`, with the additional caveat that servers must + verify the `m.room.member` event is signed by one of the `authorised_servers` if + a member is not yet invited or joined to the room. ## Security considerations -The `allow` feature for `join_rules` places increased trust in the servers in the -room. Any server which is joined to the room will be able to issue join events -for the room, there are situations which no individual server in the room can -verify that the membership event was issued in good faith. +The `allow` feature for `join_rules` places increased trust in the authorised +servers. Any authorised server which is joined to the room will be able to issue +join events for the room which no individual server in the room could verify was +issued in good faith. -We consider this acceptable: if you don't want evil servers randomly joining -spurious users into your rooms, then: - -1. Don't let evil servers in your room in the first place -2. Don't use `allow` lists, given the expansion increases the attack surface anyway - by letting members in other rooms dictate who's allowed into your room. +The increased trust in authorised servers is considered an acceptable trade-off +between increased centralisation and increased security. ## Unstable prefix @@ -114,42 +127,36 @@ as the `restricted` join rule value do not need unstable prefixes. It may seem that just having the `allow` key with `public` join rules is enough (as originally suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962)), -but there are concerns that having a `public` join rule that is restricted may -cause issues if an implementation has not been updated to understand the semantics -of the `allow` keyword. This could be solved by introducing a new room version, -but in that case it seems clearer to introduce the `restricted` join rule, as -described above. +but there are concerns that changing the behaviour of a pre-existing a `public` +join rule may cause security issues in older implementations (that do not yet +understand the new behaviour). This could be solved by introducing a new room +version, thus it seems clearer to introduce a new join rule -- `restricted`. -Using an `allow` key with `invite` join rules to broaden who can join was rejected +Using an `allow` key with the `invite` join rules to broaden who can join was rejected as an option since it requires weakening the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules). From the perspective of the auth rules, the `restricted` join rule is identical -to `public` (since the checking of whether a member is in the room is done during -the call to `/join` or `/make_join` / `/send_join` regardless). - -It was also considered to limit servers which can issue join membership events -to those in the `via` field (or some other list of trusted servers). This is -undesirable since it would increase centralization (e.g. a server already in the -room couldn't issue membership events for another user on that server). It is -unclear that this would significantly increase the security of the room. +to `public` with additional checks on the signature to ensure it was issued by +an authorised server. ## Future extensions ### Checking room membership over federation -If a server is not in a room (and thus doesn't know the membership of a room) it -cannot enforce membership of a room during a call to `/make_join`, or `/send_join`. -Peeking over federation, as described in [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), +If an authorised server is not in an allowed room (and thus doesn't know the +membership of it) then the server cannot enforce the membership checks while +generating a join event. Peeking over federation, as described in +[MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), could be used to establish if the user is in any of the proper rooms. -Note that there are additional security considerations with this, namely that -the peek server has significant power. For example, a poorly chosen peek +This would then delegate power out to a (potentially) untrusted server, giving that +the peek server significant power. For example, a poorly chosen peek server could lie about the room membership and add an `@evil_user:example.org` -to a room to gain membership to a room. +to an allowed room to gain membership to a room. As iterated above, this MSC recommends rejecting the join, potentially allowing the requesting homeserver to retry via another homeserver. -### Kicking users out when they leave the allowed space +### Kicking users out when they leave the allowed room In the above example, suppose `@bob:server.example` leaves `!users:example.org`: should they be removed from the room? Likely not, by analogy with what happens @@ -171,22 +178,22 @@ access through a room. Fixing this is thorny. Some sort of annotation on the membership events might help. but it's unclear what the desired semantics are: -* Assuming that users in a given space are *not* kicked when that space is +* Assuming that users in an allowed room are *not* kicked when that room is removed from `allow`, are those users then given a pass to remain - in the room indefinitely? What happens if the space is added back to + in the room indefinitely? What happens if the room is added back to `allow` and *then* the user leaves it? -* Suppose a user joins a room via a space (SpaceA). Later, SpaceB is added to - the `allow` list and SpaceA is removed. What should happen when the - user leaves SpaceB? Are they exempt from the kick? +* Suppose a user joins a room via an allowed room (RoomA). Later, RoomB is added + to the `allow` list and RoomA is removed. What should happen when the + user leaves RoomB? Are they exempt from the kick? It is possible that completely different state should be kept, or a different `m.room.member` state could be used in a more reasonable way to track this. ### Inheriting join rules -If you make a parent space invite-only, should that (optionally?) cascade into -child rooms? This would have some of the same problems as inheriting power levels, -as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). +If an allowed room is a space and you make a parent space invite-only, should that +(optionally?) cascade into child rooms? This would have some of the same problems +as inheriting power levels, as discussed in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962). ### Additional allow types @@ -213,8 +220,12 @@ receiving invites in `public` rooms today, and they work as you might expect. The only difference is that you are not *required* to hold an invite when joining the room. [↩](#a2) -[3]: This is a marginal decrease in security from the current -situation. Currently, a misbehaving server can allow unauthorised users to join -any room by first issuing an invite to that user. In theory that can be -prevented by raising the PL required to send an invite, but in practice that is -rarely done. [↩](#a3) +[3]: This unfortunately introduces another piece of data which must be +maintained by room administrators. It is recommended that clients initially set +this to the homeserver of the creator or the special value `"*"`. [↩](#a3) + +[4]: This has the downside of increased centralisation, as a homeserver +that is not an authorised server but is already in the room may not issue a join +event for another user on that server. (It must go through the `/make_join` / +`/send_join` flow of an authorised server.) This is considered a reasonable +trade-off. [↩](#a4) From 3bab6bd9e1ec9287e84ef43ce745719719d33f8a Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 17 Jun 2021 14:21:45 -0400 Subject: [PATCH 28/66] Remove via field. --- proposals/3083-restricted-rooms.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b13589cd90..936470b980 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -21,13 +21,11 @@ would include the rooms to trust for membership. For example: "allow": [ { "type": "m.room_membership", - "room_id": "!mods:example.org", - "via": ["example.org"] + "room_id": "!mods:example.org" }, { "type": "m.room_membership", - "room_id": "!users:example.org", - "via": ["example.org"] + "room_id": "!users:example.org" } ], "authorised_servers": ["example.org"] @@ -46,7 +44,6 @@ following keys: * `type`: `"m.room_membership"` to describe that we are allowing access via room membership. Future MSCs may define other types. * `room_id`: The room ID to check the membership of. -* `via`: A list of servers which may be used to peek for membership of the room. Any entries in the list which do not match the expected format are ignored. Thus, if all entries are invalid, the list behaves as if empty and all users without From 8e0b0014862e5fc09e34ec10cb36f3fd7936e2bf Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 17 Jun 2021 14:22:55 -0400 Subject: [PATCH 29/66] Add a note about ensuring each allowed room has at least one server in it. --- proposals/3083-restricted-rooms.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 936470b980..053adca81e 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -80,6 +80,8 @@ It is possible for a homeserver receiving a `/make_join` / `/send_join` request to not know if the user is in a particular room (due to not participating in any of the necessary rooms). In this case the homeserver should reject the join, the requesting server may wish to attempt to join via another authorised homeserver. +If no authorised servers are in an allowed room its membership cannot be checked +(and this is a misconfiguration). Note that the authorised homeservers have significant power, as they are trusted to confirm that the `allow` rules were properly checked (since this cannot From 0b499321dc62c2ebea40d20f8a0607c066ed8f99 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 18 Jun 2021 08:09:36 -0400 Subject: [PATCH 30/66] Clarifications. Co-authored-by: Jonathan de Jong --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 053adca81e..bd5b506ef3 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -101,7 +101,7 @@ between `public`, `invite`, and `restricted`. * `private`: This is reserved, but unspecified. * `restricted`: the same as `public`, with the additional caveat that servers must verify the `m.room.member` event is signed by one of the `authorised_servers` if - a member is not yet invited or joined to the room. + a member was not yet invited or joined into the room. ## Security considerations From b4296efa54baa543f658cc0a18aa1cc92394a65d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 22 Jun 2021 08:34:05 -0400 Subject: [PATCH 31/66] Remove the authorised servers list. --- proposals/3083-restricted-rooms.md | 91 ++++++++++++++---------------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index bd5b506ef3..8af446ca56 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -27,8 +27,7 @@ would include the rooms to trust for membership. For example: "type": "m.room_membership", "room_id": "!users:example.org" } - ], - "authorised_servers": ["example.org"] + ] } } ``` @@ -49,43 +48,38 @@ Any entries in the list which do not match the expected format are ignored. Thus if all entries are invalid, the list behaves as if empty and all users without an invite are rejected. -The `authorised_servers` key lists servers which are trusted to verify the above -allow rules. It must be a list of string server name, a special value of `"*"` -can be used to allow any server with a member in the room. Any non-string entries -are discarded, if the list is non-existent or empty then no users may join without -an invite.[3](#f3) +When an homeserver receives a `/join` request from a client or a `/make_join` / +`/send_join` request from another homeserver, the request should only be permitted +if the user has a valid invite or is in one of the listed rooms. If the user is +not a member of at least one of the rooms, the homeserver should return an error +response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. + +It is possible for a homeserver receiving a `/make_join` / `/send_join` request +to not know if the user is in a particular room (due to not participating in any +of the necessary rooms). In this case the homeserver should reject the join, +the requesting server may wish to attempt to join via another homeserver. If no +servers are in an allowed room its membership cannot be checked (and this is a +misconfiguration). From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional caveat that servers must ensure that: -* The user's current membership is `invite` or `join`, or -* The `m.room.member` event has a valid signature from one of the servers listed - in `authorised_servers`. +* The user's previous membership was `invite` or `join`, or +* The `m.room.member` event has a valid signature from a homeserver whose users + have the power to issue invites. The above check must also be performed against the current room state to potentially soft-fail the event. This is the primary mechanism for guarding against state -changes when old events are referenced. (E.g. if an authorised server is removed -it should not be able to issue new membership events by referencing an old event -in the room.) - -When an authorised homeserver receives a `/join` request from a client or a -`/make_join` / `/send_join` request from another homeserver, the request should -only be permitted if the user has a valid invite or is in one of the listed rooms. -If the user is not a member of at least one of the rooms, the authorised homeserver -should return an error response with HTTP status code of 403 and an `errcode` of -`M_FORBIDDEN`. +changes when old events are referenced. (E.g. if the power levels change, a +server should not be able to issue new membership events by referencing an old +event in the room.) -It is possible for a homeserver receiving a `/make_join` / `/send_join` request -to not know if the user is in a particular room (due to not participating in any -of the necessary rooms). In this case the homeserver should reject the join, -the requesting server may wish to attempt to join via another authorised homeserver. -If no authorised servers are in an allowed room its membership cannot be checked -(and this is a misconfiguration). - -Note that the authorised homeservers have significant power, as they are trusted -to confirm that the `allow` rules were properly checked (since this cannot -easily be enforced over federation by event authorisation).[4](#f4) +Note that the homeservers whose users can issue invites are trusted to confirm +that the `allow` rules were properly checked (since this cannot easily be +enforced over federation by event authorisation).[3](#f3) +(The rationale for trusting these homeservers is that they could easily +side-step the restriction by issuing an invite first.) ## Summary of the behaviour of join rules @@ -100,18 +94,20 @@ between `public`, `invite`, and `restricted`. `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). * `private`: This is reserved, but unspecified. * `restricted`: the same as `public`, with the additional caveat that servers must - verify the `m.room.member` event is signed by one of the `authorised_servers` if - a member was not yet invited or joined into the room. + verify the `m.room.member` event is signed by a homeserver whose users may issue + invites if the joining member was not previously invited or joined into the room. ## Security considerations -The `allow` feature for `join_rules` places increased trust in the authorised -servers. Any authorised server which is joined to the room will be able to issue -join events for the room which no individual server in the room could verify was -issued in good faith. +Although increased trust to enforce the join rules during `/join` / `/make_join` +/ `/send_join` is placed in the homeservers whose users can issue invites, this +is considered only a miniscule change in room security. -The increased trust in authorised servers is considered an acceptable trade-off -between increased centralisation and increased security. +This MSC limits the homeservers who can issue join events (via calls to `/join`, +`/make_join`, and `/send_join`) and trusts those servers to enforce the additional +allow rules. Although other homeservers may not be able to verify that a join +event was issued in good faith, there is no benefit for a homeserver to do this +since they could have issued an invite anyway. ## Unstable prefix @@ -134,14 +130,13 @@ version, thus it seems clearer to introduce a new join rule -- `restricted`. Using an `allow` key with the `invite` join rules to broaden who can join was rejected as an option since it requires weakening the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules). From the perspective of the auth rules, the `restricted` join rule is identical -to `public` with additional checks on the signature to ensure it was issued by -an authorised server. +to `public` with additional checks on the signature of the event. ## Future extensions ### Checking room membership over federation -If an authorised server is not in an allowed room (and thus doesn't know the +If a homeserver is not in an allowed room (and thus doesn't know the membership of it) then the server cannot enforce the membership checks while generating a join event. Peeking over federation, as described in [MSC2444](https://github.com/matrix-org/matrix-doc/pull/2444), @@ -219,12 +214,8 @@ receiving invites in `public` rooms today, and they work as you might expect. The only difference is that you are not *required* to hold an invite when joining the room. [↩](#a2) -[3]: This unfortunately introduces another piece of data which must be -maintained by room administrators. It is recommended that clients initially set -this to the homeserver of the creator or the special value `"*"`. [↩](#a3) - -[4]: This has the downside of increased centralisation, as a homeserver -that is not an authorised server but is already in the room may not issue a join -event for another user on that server. (It must go through the `/make_join` / -`/send_join` flow of an authorised server.) This is considered a reasonable -trade-off. [↩](#a4) +[3]: This has the downside of increased centralisation, as some +homeservers that are already in the room may not issue a join event for another +user on that server. (It must go through the `/make_join` / `/send_join` flow of +a server whose users may issue invites.) This is considered a reasonable +trade-off. [↩](#a3) From e5305a72f2d56db24a16b0c6a0988d975106f7e3 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 22 Jun 2021 08:46:19 -0400 Subject: [PATCH 32/66] Clarifications / simplifications. --- proposals/3083-restricted-rooms.md | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 8af446ca56..8107a99346 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -55,11 +55,10 @@ not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. It is possible for a homeserver receiving a `/make_join` / `/send_join` request -to not know if the user is in a particular room (due to not participating in any -of the necessary rooms). In this case the homeserver should reject the join, -the requesting server may wish to attempt to join via another homeserver. If no -servers are in an allowed room its membership cannot be checked (and this is a -misconfiguration). +to not know if the user is in any of the allowed room (due to not participating +in them). In this case the homeserver should reject the join, the requesting +server may wish to attempt to join via another homeserver. If no servers are in +an allowed room its membership cannot be checked (and this is a misconfiguration). From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional @@ -78,8 +77,6 @@ event in the room.) Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be enforced over federation by event authorisation).[3](#f3) -(The rationale for trusting these homeservers is that they could easily -side-step the restriction by issuing an invite first.) ## Summary of the behaviour of join rules @@ -99,15 +96,11 @@ between `public`, `invite`, and `restricted`. ## Security considerations -Although increased trust to enforce the join rules during `/join` / `/make_join` -/ `/send_join` is placed in the homeservers whose users can issue invites, this -is considered only a miniscule change in room security. - -This MSC limits the homeservers who can issue join events (via calls to `/join`, -`/make_join`, and `/send_join`) and trusts those servers to enforce the additional -allow rules. Although other homeservers may not be able to verify that a join -event was issued in good faith, there is no benefit for a homeserver to do this -since they could have issued an invite anyway. +Increased trust to enforce the join rules during calls to `/join`, `/make_join`, +and `/send_join` is placed in the homeservers whose users can issue invites. +Although it is possible for those homeservers to issue a join event in bad faith, +there is no real-world benefit to doing this as those homeservers could easily +side-side the restriction by issuing an invite first anyway. ## Unstable prefix From 6d041d4dd9d5313383fd8f527deb1deb17929a9c Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 24 Jun 2021 08:20:44 -0400 Subject: [PATCH 33/66] Fix typos. Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/3083-restricted-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 8107a99346..1aae6d42a7 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -81,7 +81,7 @@ enforced over federation by event authorisation).[3](#f3) ## Summary of the behaviour of join rules See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) -specification for full details, the summary below is meant to highlight the differences +specification for full details; the summary below is meant to highlight the differences between `public`, `invite`, and `restricted`. * `public`: anyone can join, subject to `ban` and `server_acls`, as today. @@ -100,7 +100,7 @@ Increased trust to enforce the join rules during calls to `/join`, `/make_join`, and `/send_join` is placed in the homeservers whose users can issue invites. Although it is possible for those homeservers to issue a join event in bad faith, there is no real-world benefit to doing this as those homeservers could easily -side-side the restriction by issuing an invite first anyway. +side-step the restriction by issuing an invite first anyway. ## Unstable prefix From 69aec559acaa631bdedb928e09f7549ff2c372d4 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 24 Jun 2021 08:30:49 -0400 Subject: [PATCH 34/66] Clarify soft-failure is extension of current algorithm. Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/3083-restricted-rooms.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 1aae6d42a7..9adad0b62a 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -68,11 +68,10 @@ caveat that servers must ensure that: * The `m.room.member` event has a valid signature from a homeserver whose users have the power to issue invites. -The above check must also be performed against the current room state to potentially -soft-fail the event. This is the primary mechanism for guarding against state -changes when old events are referenced. (E.g. if the power levels change, a -server should not be able to issue new membership events by referencing an old -event in the room.) +As normal, the above check is also performed against the current room state during +[soft-failure](https://matrix.org/docs/spec/server_server/r0.1.4#soft-failure), +to guard against servers issuing new membership events by referencing old +events in the room. Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be From 42a34de18da103d9bfcf809125d5ebfaf3d95897 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 24 Jun 2021 08:32:36 -0400 Subject: [PATCH 35/66] Clarify that signature checks only apply to joining users. --- proposals/3083-restricted-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 9adad0b62a..63d290aa72 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -65,8 +65,8 @@ the `restricted` join rule has the same behavior as `public`, with the additiona caveat that servers must ensure that: * The user's previous membership was `invite` or `join`, or -* The `m.room.member` event has a valid signature from a homeserver whose users - have the power to issue invites. +* The `m.room.member` event with a `membership` of `join` has a valid signature + from a homeserver whose users have the power to issue invites. As normal, the above check is also performed against the current room state during [soft-failure](https://matrix.org/docs/spec/server_server/r0.1.4#soft-failure), From 808bb1bc5a45fd74a89d2295ac6626fc0a43126f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 28 Jun 2021 08:34:44 -0400 Subject: [PATCH 36/66] Pull note about ban & ACLs out of each join rule description. --- proposals/3083-restricted-rooms.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 63d290aa72..6e30f09ed4 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -81,13 +81,13 @@ enforced over federation by event authorisation).[3](#f3) See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) specification for full details; the summary below is meant to highlight the differences -between `public`, `invite`, and `restricted`. +between `public`, `invite`, and `restricted`. Note that all join rules are subject +to `ban` and `server_acls`. -* `public`: anyone can join, subject to `ban` and `server_acls`, as today. -* `invite`: only people with membership `invite` can join, subject to `ban` and - `server_acls`, as today. -* `knock`: the same as `invite`, except anyone can knock, subject to `ban` and - `server_acls`. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). +* `public`: anyone can join, as today. +* `invite`: only people with membership `invite` can join, as today. +* `knock`: the same as `invite`, except anyone can knock. See + [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). * `private`: This is reserved, but unspecified. * `restricted`: the same as `public`, with the additional caveat that servers must verify the `m.room.member` event is signed by a homeserver whose users may issue From 87f993820de683c2e2954786960cc6b2e35a9b5f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 28 Jun 2021 08:35:44 -0400 Subject: [PATCH 37/66] Use a different room version to specify changes in join rules. --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 6e30f09ed4..b33c4f0c4f 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -106,7 +106,7 @@ side-step the restriction by issuing an invite first anyway. The `restricted` join rule will be included in a future room version to allow servers and clients to opt-into the new functionality. -During development, an unstable room version of `org.matrix.msc3083` will be used. +During development, an unstable room version of `org.matrix.msc3083.v2` will be used. Since the room version namespaces the behaviour, the `allow` key and value, as well as the `restricted` join rule value do not need unstable prefixes. From 182c806bc45549c72b2d3ca1864bc471351e9ec2 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 28 Jun 2021 08:55:52 -0400 Subject: [PATCH 38/66] Clarify what happens if a homeserver cannot verify membership. --- proposals/3083-restricted-rooms.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b33c4f0c4f..a77c363836 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -55,10 +55,13 @@ not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. It is possible for a homeserver receiving a `/make_join` / `/send_join` request -to not know if the user is in any of the allowed room (due to not participating -in them). In this case the homeserver should reject the join, the requesting -server may wish to attempt to join via another homeserver. If no servers are in -an allowed room its membership cannot be checked (and this is a misconfiguration). +to not know if the user is in some of the allowed room (due to not participating +in them). Any allow room that the homeserver cannot verify the membership should +be treated as if the user is not in that room. If the user is not in any of the +rooms (or some of the rooms cannot be verified) the homeserver should reject the +join, as above. The requesting server may wish to attempt to join via another +homeserver. If no servers are in any of the allowed rooms its membership cannot +be verified (and this is a misconfiguration). From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional From 1be4019a6267a2963cd8a689da310efbefa49998 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 28 Jun 2021 09:02:19 -0400 Subject: [PATCH 39/66] Clarify implications of signing events. --- proposals/3083-restricted-rooms.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index a77c363836..bd6b0a7e3a 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -69,7 +69,18 @@ caveat that servers must ensure that: * The user's previous membership was `invite` or `join`, or * The `m.room.member` event with a `membership` of `join` has a valid signature - from a homeserver whose users have the power to issue invites. + from a homeserver whose users have the power to issue invites. This implies + that: + + * A join event issued via `/make_join` & `/send_join` is signed by the not + just the requesting server, but also the resident server. (This seems like + an improvement regardless since the resident server is accepting the event + on behalf of the joining server and ideally this should be verifiable after + the fact, even for current room versions.) + * The auth chain of the join event needs to include an event which proves + the homeserver can be issuing the join. This can be done by including the + `m.room.power_levels` event and an `m.room.member` event with `membership` + equal to `join` for a member who could issue invites from that server. As normal, the above check is also performed against the current room state during [soft-failure](https://matrix.org/docs/spec/server_server/r0.1.4#soft-failure), From 76333ee222c67cd99e60836fe635c1d8c16d0351 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 1 Jul 2021 12:54:00 -0400 Subject: [PATCH 40/66] Add notes about the via key and authorised servers being out of sync. --- proposals/3083-restricted-rooms.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index bd6b0a7e3a..19ea0ab9cc 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -206,6 +206,24 @@ restricting access via: These are just examples are not fully thought through for this MSC, but it should be possible to add these behaviors in the future. +### Interaction with `m.space.child` events + +[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) defines a `via` +key in the content of `m.space.child` events: + +> the content must contain a via `key` which gives a list of candidate servers +> that can be used to join the room. + +It is possible for the candidate servers and the list of authorised servers to +not be in sync. In the case where there's no overlap between these lists, it may +not be possible for a server to complete the request. + +If there is some overlap between the lists of servers the join request should +complete successfully. + +A future MSC may define a way to override or update the `via` key in a coherent +manner. + ## Footnotes [1]: The converse restriction, "anybody can join, provided they are not members From 5f2240a59e0498014e442dc0cb5ae330be94c3bd Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 12 Jul 2021 13:53:20 -0400 Subject: [PATCH 41/66] Fix typo. Co-authored-by: Hubert Chathi --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 19ea0ab9cc..7389cacb57 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -72,7 +72,7 @@ caveat that servers must ensure that: from a homeserver whose users have the power to issue invites. This implies that: - * A join event issued via `/make_join` & `/send_join` is signed by the not + * A join event issued via `/make_join` & `/send_join` is signed by not just the requesting server, but also the resident server. (This seems like an improvement regardless since the resident server is accepting the event on behalf of the joining server and ideally this should be verifiable after From 30372321b38228c339d7fa1c65c771acd7807d9e Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:32:11 -0400 Subject: [PATCH 42/66] Fix typo. Co-authored-by: Travis Ralston --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 7389cacb57..b9e3660e5d 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -55,7 +55,7 @@ not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. It is possible for a homeserver receiving a `/make_join` / `/send_join` request -to not know if the user is in some of the allowed room (due to not participating +to not know if the user is in some of the allowed rooms (due to not participating in them). Any allow room that the homeserver cannot verify the membership should be treated as if the user is not in that room. If the user is not in any of the rooms (or some of the rooms cannot be verified) the homeserver should reject the From 2c65a03d594043e8f83aeeaab9894bbffef6bbc3 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:35:31 -0400 Subject: [PATCH 43/66] Fix typo. Co-authored-by: Matthew Hodgson --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index b9e3660e5d..60d5429072 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -128,7 +128,7 @@ as the `restricted` join rule value do not need unstable prefixes. It may seem that just having the `allow` key with `public` join rules is enough (as originally suggested in [MSC2962](https://github.com/matrix-org/matrix-doc/pull/2962)), -but there are concerns that changing the behaviour of a pre-existing a `public` +but there are concerns that changing the behaviour of a pre-existing `public` join rule may cause security issues in older implementations (that do not yet understand the new behaviour). This could be solved by introducing a new room version, thus it seems clearer to introduce a new join rule -- `restricted`. From b9204cccf844afc27e7b2876fae8d452b6615462 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:35:49 -0400 Subject: [PATCH 44/66] Remove extraneous paragraph. --- proposals/3083-restricted-rooms.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 60d5429072..6f45b68b1d 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -82,11 +82,6 @@ caveat that servers must ensure that: `m.room.power_levels` event and an `m.room.member` event with `membership` equal to `join` for a member who could issue invites from that server. -As normal, the above check is also performed against the current room state during -[soft-failure](https://matrix.org/docs/spec/server_server/r0.1.4#soft-failure), -to guard against servers issuing new membership events by referencing old -events in the room. - Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be enforced over federation by event authorisation).[3](#f3) From d95200f5e220056d512658fee4b20d668be54cb5 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:36:54 -0400 Subject: [PATCH 45/66] Add domains to the example room aliases. --- proposals/3083-restricted-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 6f45b68b1d..93095247a7 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -4,7 +4,7 @@ A desirable feature is to give room admins the power to restrict membership of their room based on the membership of one or more spaces from [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772), for example: -> members of the #doglovers space can join this room without an invitation[1](#f1) +> members of the #doglovers:example.com space can join this room without an invitation[1](#f1) ## Proposal @@ -222,7 +222,7 @@ manner. ## Footnotes [1]: The converse restriction, "anybody can join, provided they are not members -of the '#catlovers' space" is less useful since: +of the #catlovers:example.com space" is less useful since: 1. Users in the banned room could simply leave it at any time 2. This functionality is already partially provided by From dc945a48435ec65949b239431585b9d086f5564f Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:43:48 -0400 Subject: [PATCH 46/66] Reword intro. --- proposals/3083-restricted-rooms.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 93095247a7..5a23a9db1c 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -1,10 +1,19 @@ # Restricting room membership based on space membership A desirable feature is to give room admins the power to restrict membership of -their room based on the membership of one or more spaces from -[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772), for example: +their room based on the membership of one or more rooms. -> members of the #doglovers:example.com space can join this room without an invitation[1](#f1) +Potential usecases include: + +* Private spaces (allowing any member of a [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) + space to join child rooms in that space), for example: + + > members of the #doglovers:example.com space can join this room without an invitation[1](#f1) +* Room upgrades for private rooms (instead of issuing invites to each user). +* Allowing all users in a private room to be able to join a private breakout room. + +This does not preclude members from being directly invited to the room, which is +still a useful discovery feature. ## Proposal From 2012466214781414659032d555584d639adcc5ef Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:46:29 -0400 Subject: [PATCH 47/66] Clarify users must be joined to an allowed room. Co-authored-by: Matthew Hodgson --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 5a23a9db1c..3e0f0f7ce9 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -59,7 +59,7 @@ an invite are rejected. When an homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from another homeserver, the request should only be permitted -if the user has a valid invite or is in one of the listed rooms. If the user is +if the user is invited to this room, or is joined to one of the listed rooms. If the user is not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. From db40a1c8a3adbbb137d4e05f4739b4908366a346 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 08:47:14 -0400 Subject: [PATCH 48/66] Reflow. --- proposals/3083-restricted-rooms.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 3e0f0f7ce9..bf67cd119a 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -59,9 +59,9 @@ an invite are rejected. When an homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from another homeserver, the request should only be permitted -if the user is invited to this room, or is joined to one of the listed rooms. If the user is -not a member of at least one of the rooms, the homeserver should return an error -response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +if the user is invited to this room, or is joined to one of the listed rooms. If +the user is not a member of at least one of the rooms, the homeserver should return +an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. It is possible for a homeserver receiving a `/make_join` / `/send_join` request to not know if the user is in some of the allowed rooms (due to not participating From 81a588e63126ffae53d56df17b498adf9d3cfde5 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 12:59:43 -0400 Subject: [PATCH 49/66] Add note about including the authorising server in the content. --- proposals/3083-restricted-rooms.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index bf67cd119a..91bf5f5b03 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -82,18 +82,19 @@ caveat that servers must ensure that: that: * A join event issued via `/make_join` & `/send_join` is signed by not - just the requesting server, but also the resident server. (This seems like - an improvement regardless since the resident server is accepting the event - on behalf of the joining server and ideally this should be verifiable after - the fact, even for current room versions.) + just the requesting server, but also the resident server.[3](#f3) * The auth chain of the join event needs to include an event which proves the homeserver can be issuing the join. This can be done by including the `m.room.power_levels` event and an `m.room.member` event with `membership` equal to `join` for a member who could issue invites from that server. + In order to find a corresponding event quickly for verification, the + content of the join event should include the other user's MXID in the + content with the key `join_authorised_via_users_server`. + Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be -enforced over federation by event authorisation).[3](#f3) +enforced over federation by event authorisation).[4](#f4) ## Summary of the behaviour of join rules @@ -242,8 +243,13 @@ receiving invites in `public` rooms today, and they work as you might expect. The only difference is that you are not *required* to hold an invite when joining the room. [↩](#a2) -[3]: This has the downside of increased centralisation, as some +[3]: This seems like an improvement regardless since the resident server +is accepting the event on behalf of the joining server and ideally this should be +verifiable after the fact, even for current room versions. Requiring all events +to be signed and verified in this way is left to a future MSC. [↩](#a3) + +[4]: This has the downside of increased centralisation, as some homeservers that are already in the room may not issue a join event for another user on that server. (It must go through the `/make_join` / `/send_join` flow of a server whose users may issue invites.) This is considered a reasonable -trade-off. [↩](#a3) +trade-off. [↩](#a4) From b41a1a3392af52da91854f3ef61b23d970286a81 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 13 Jul 2021 13:06:54 -0400 Subject: [PATCH 50/66] Update the information on signature checking. --- proposals/3083-restricted-rooms.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 91bf5f5b03..89103c0d6e 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -81,8 +81,11 @@ caveat that servers must ensure that: from a homeserver whose users have the power to issue invites. This implies that: - * A join event issued via `/make_join` & `/send_join` is signed by not - just the requesting server, but also the resident server.[3](#f3) + * A join event issued via `/send_join` is signed by not just the requesting + server, but also the resident server.[3](#f3) + + In order for the joining server to receive the proper signatures the join + event will be returned via `/send_join` in the `join_event` field. * The auth chain of the join event needs to include an event which proves the homeserver can be issuing the join. This can be done by including the `m.room.power_levels` event and an `m.room.member` event with `membership` From 290f9032f4c4b0d87b3290ab2f0c5d3c24262eb2 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 16 Jul 2021 13:03:49 -0400 Subject: [PATCH 51/66] Updates from review. --- proposals/3083-restricted-rooms.md | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 89103c0d6e..063251d932 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -72,6 +72,8 @@ join, as above. The requesting server may wish to attempt to join via another homeserver. If no servers are in any of the allowed rooms its membership cannot be verified (and this is a misconfiguration). +TODO Better define errors over federation. + From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional caveat that servers must ensure that: @@ -85,35 +87,39 @@ caveat that servers must ensure that: server, but also the resident server.[3](#f3) In order for the joining server to receive the proper signatures the join - event will be returned via `/send_join` in the `join_event` field. + event will be returned via `/send_join` in the `event` field. * The auth chain of the join event needs to include an event which proves the homeserver can be issuing the join. This can be done by including the `m.room.power_levels` event and an `m.room.member` event with `membership` equal to `join` for a member who could issue invites from that server. In order to find a corresponding event quickly for verification, the - content of the join event should include the other user's MXID in the - content with the key `join_authorised_via_users_server`. + content of the join event should include the chosen user's MXID in the + content with the key `join_authorised_via_users_server`. The actual user + chosen is arbitrary. Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be enforced over federation by event authorisation).[4](#f4) +To better cope with joining via aliases, homeservers should use the list of +authorised servers (not the list of candidate servers) when a user attempts to +join a room. + ## Summary of the behaviour of join rules See the [join rules](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-join-rules) specification for full details; the summary below is meant to highlight the differences -between `public`, `invite`, and `restricted`. Note that all join rules are subject -to `ban` and `server_acls`. +between `public`, `invite`, and `restricted` from a user perspective. Note that +all join rules are subject to `ban` and `server_acls`. * `public`: anyone can join, as today. * `invite`: only people with membership `invite` can join, as today. * `knock`: the same as `invite`, except anyone can knock. See [MSC2403](https://github.com/matrix-org/matrix-doc/pull/2403). * `private`: This is reserved, but unspecified. -* `restricted`: the same as `public`, with the additional caveat that servers must - verify the `m.room.member` event is signed by a homeserver whose users may issue - invites if the joining member was not previously invited or joined into the room. +* `restricted`: the same as `invite`, except users may also join if they are a + member of a room listed in the `allow` rules. ## Security considerations @@ -214,7 +220,7 @@ restricting access via: These are just examples are not fully thought through for this MSC, but it should be possible to add these behaviors in the future. -### Interaction with `m.space.child` events +### Client considerations [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) defines a `via` key in the content of `m.space.child` events: @@ -222,13 +228,16 @@ key in the content of `m.space.child` events: > the content must contain a via `key` which gives a list of candidate servers > that can be used to join the room. -It is possible for the candidate servers and the list of authorised servers to -not be in sync. In the case where there's no overlap between these lists, it may -not be possible for a server to complete the request. +It is possible for the list of candidate servers and the list of authorised +servers to diverge. It may not be possible for a user to join a room if there's +no overlap between these lists. If there is some overlap between the lists of servers the join request should complete successfully. +Clients should also consider the authorised servers when generating candidate +servers to embed in links to the room, e.g. via matrix.to. + A future MSC may define a way to override or update the `via` key in a coherent manner. From ffb9095c82672c49f2a500797cd10a919495ea4a Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 16 Jul 2021 13:15:29 -0400 Subject: [PATCH 52/66] Add a note about resident servers. --- proposals/3083-restricted-rooms.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 063251d932..dadff3762b 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -98,6 +98,12 @@ caveat that servers must ensure that: content with the key `join_authorised_via_users_server`. The actual user chosen is arbitrary. + This creates a new restriction on the relationship between the resident + servers used for `/make_join` and `/send_join` -- they must now both go to + the same server (since the `join_authorised_via_users_server` is added in + the call to `/make_join`, while the final signature is added during + the call to `/send_join`). + Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be enforced over federation by event authorisation).[4](#f4) From 7caff82b36617963ea9f8672c852c95046169bfb Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 19 Jul 2021 14:57:34 -0400 Subject: [PATCH 53/66] Add information about errors over federation. --- proposals/3083-restricted-rooms.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index dadff3762b..d739c48e9e 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -63,16 +63,16 @@ if the user is invited to this room, or is joined to one of the listed rooms. If the user is not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. -It is possible for a homeserver receiving a `/make_join` / `/send_join` request -to not know if the user is in some of the allowed rooms (due to not participating -in them). Any allow room that the homeserver cannot verify the membership should -be treated as if the user is not in that room. If the user is not in any of the -rooms (or some of the rooms cannot be verified) the homeserver should reject the -join, as above. The requesting server may wish to attempt to join via another -homeserver. If no servers are in any of the allowed rooms its membership cannot -be verified (and this is a misconfiguration). - -TODO Better define errors over federation. +It is possible for a resident homeserver (one which receives a `/make_join` / +`/send_join` request to not know if the user is in some of the allowed rooms (due +to not participating in them). If the user is not in any of the allowed rooms that +are known to the homeserver it should return an error response with HTTP status code +of 400 with an `errcode` of `M_CANNOT_ALLOW`. The joining server should attempt to +join via another resident homeserver. If the resident homeserver knows that the +user is not in *any* of the allowed rooms it should return an error response with +HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a +configuration error if there are allowed rooms with no participating authorised +servers. From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional From 55b99d29e4a7df3a77e298b95d9e977882c361be Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 19 Jul 2021 15:10:29 -0400 Subject: [PATCH 54/66] Clarify if a resident server cannot issue a join vs. if they're unsure if the user is allowed to join. --- proposals/3083-restricted-rooms.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index d739c48e9e..8e7c82fe70 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -67,13 +67,18 @@ It is possible for a resident homeserver (one which receives a `/make_join` / `/send_join` request to not know if the user is in some of the allowed rooms (due to not participating in them). If the user is not in any of the allowed rooms that are known to the homeserver it should return an error response with HTTP status code -of 400 with an `errcode` of `M_CANNOT_ALLOW`. The joining server should attempt to -join via another resident homeserver. If the resident homeserver knows that the -user is not in *any* of the allowed rooms it should return an error response with -HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a +of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should +attempt to join via another resident homeserver. If the resident homeserver knows +that the user is not in *any* of the allowed rooms it should return an error response +with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a configuration error if there are allowed rooms with no participating authorised servers. +A chosen resident homeserver might also be unable to issue invites, in this case +it should return an error response with HTTP status code of 400 and an `errcode` +of `M_CANNOT_ALLOW`. The joining server should attempt to join via another +resident homeserver. + From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional caveat that servers must ensure that: From 48c1d9d99838e10272904564ab82100c36ec20a9 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Jul 2021 12:28:55 -0400 Subject: [PATCH 55/66] Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/3083-restricted-rooms.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 8e7c82fe70..83073f2166 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -64,7 +64,7 @@ the user is not a member of at least one of the rooms, the homeserver should ret an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. It is possible for a resident homeserver (one which receives a `/make_join` / -`/send_join` request to not know if the user is in some of the allowed rooms (due +`/send_join` request) to not know if the user is in some of the allowed rooms (due to not participating in them). If the user is not in any of the allowed rooms that are known to the homeserver it should return an error response with HTTP status code of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should @@ -74,7 +74,7 @@ with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is configuration error if there are allowed rooms with no participating authorised servers. -A chosen resident homeserver might also be unable to issue invites, in this case +A chosen resident homeserver might also be unable to issue invites; in this case it should return an error response with HTTP status code of 400 and an `errcode` of `M_CANNOT_ALLOW`. The joining server should attempt to join via another resident homeserver. @@ -84,7 +84,7 @@ the `restricted` join rule has the same behavior as `public`, with the additiona caveat that servers must ensure that: * The user's previous membership was `invite` or `join`, or -* The `m.room.member` event with a `membership` of `join` has a valid signature +* The join event has a valid signature from a homeserver whose users have the power to issue invites. This implies that: From 88a94049d29179f1a8a1a531ee121389804258af Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Jul 2021 13:23:17 -0400 Subject: [PATCH 56/66] Review feedback. --- proposals/3083-restricted-rooms.md | 60 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 83073f2166..923477dccc 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -63,45 +63,35 @@ if the user is invited to this room, or is joined to one of the listed rooms. If the user is not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. -It is possible for a resident homeserver (one which receives a `/make_join` / -`/send_join` request) to not know if the user is in some of the allowed rooms (due -to not participating in them). If the user is not in any of the allowed rooms that -are known to the homeserver it should return an error response with HTTP status code -of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should -attempt to join via another resident homeserver. If the resident homeserver knows -that the user is not in *any* of the allowed rooms it should return an error response -with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a -configuration error if there are allowed rooms with no participating authorised -servers. - -A chosen resident homeserver might also be unable to issue invites; in this case -it should return an error response with HTTP status code of 400 and an `errcode` -of `M_CANNOT_ALLOW`. The joining server should attempt to join via another -resident homeserver. - From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional caveat that servers must ensure that: * The user's previous membership was `invite` or `join`, or -* The join event has a valid signature - from a homeserver whose users have the power to issue invites. This implies - that: +* The join event has a valid signature from a homeserver whose users have the + power to issue invites. + + When generating a join event the server should include the MXID of a local user + who could issue an invite in the content with the key + `join_authorised_via_users_server`. The actual user chosen is arbitrary. + + This implies that: * A join event issued via `/send_join` is signed by not just the requesting server, but also the resident server.[3](#f3) In order for the joining server to receive the proper signatures the join event will be returned via `/send_join` in the `event` field. - * The auth chain of the join event needs to include an event which proves - the homeserver can be issuing the join. This can be done by including the - `m.room.power_levels` event and an `m.room.member` event with `membership` - equal to `join` for a member who could issue invites from that server. + * The auth chain of the join event needs to include events which prove + the homeserver can be issuing the join. This can be done by including: - In order to find a corresponding event quickly for verification, the - content of the join event should include the chosen user's MXID in the - content with the key `join_authorised_via_users_server`. The actual user - chosen is arbitrary. + * The `m.room.power_levels` event + * The `m.room.member` event (with `membership` equal to `join`) the user + specified in `join_authorised_via_users_server`. + + It should be confirmed that the authorising user is in the room. (This + prevents situations where any homeserver could process the join, even if + they weren't in the room, under certain power level conditions.) This creates a new restriction on the relationship between the resident servers used for `/make_join` and `/send_join` -- they must now both go to @@ -113,6 +103,22 @@ Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be enforced over federation by event authorisation).[4](#f4) +It is possible for a resident homeserver (one which receives a `/make_join` / +`/send_join` request) to not know if the user is in some of the allowed rooms (due +to not participating in them). If the user is not in any of the allowed rooms that +are known to the homeserver it should return an error response with HTTP status code +of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should +attempt to join via another resident homeserver. If the resident homeserver knows +that the user is not in *any* of the allowed rooms it should return an error response +with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a +configuration error if there are allowed rooms with no participating authorised +servers. + +A chosen resident homeserver might also be unable to issue invites; in this case +it should return an error response with HTTP status code of 400 and an `errcode` +of `M_CANNOT_ALLOW`. The joining server should attempt to join via another +resident homeserver. + To better cope with joining via aliases, homeservers should use the list of authorised servers (not the list of candidate servers) when a user attempts to join a room. From c0b7f0762e093eb5e3be704d89c05f83ca0e015b Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Jul 2021 13:36:26 -0400 Subject: [PATCH 57/66] Move back section about errors for make/send_join & some review comments. --- proposals/3083-restricted-rooms.md | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 923477dccc..8c1f5b6b2e 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -63,6 +63,23 @@ if the user is invited to this room, or is joined to one of the listed rooms. If the user is not a member of at least one of the rooms, the homeserver should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. +It is possible for a resident homeserver (one which receives a `/make_join` / +`/send_join` request) to not know if the user is in some of the allowed rooms (due +to not participating in them). If the user is not in any of the allowed rooms that +are known to the homeserver it should return an error response with HTTP status code +of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should +attempt to join via another resident homeserver. If the resident homeserver knows +that the user is not in *any* of the allowed rooms it should return an error response +with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a +configuration error if there are allowed rooms with no participating authorised +servers. + +A chosen resident homeserver might also be unable to issue invites (which, as below, +is a pre-requisite for generating a correctly-signed join event). In this case +it should return an error response with HTTP status code of 400 and an `errcode` +of `M_CANNOT_ALLOW`. The joining server should attempt to join via another +resident homeserver. + From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional caveat that servers must ensure that: @@ -86,8 +103,7 @@ caveat that servers must ensure that: the homeserver can be issuing the join. This can be done by including: * The `m.room.power_levels` event - * The `m.room.member` event (with `membership` equal to `join`) the user - specified in `join_authorised_via_users_server`. + * The join event of the user specified in `join_authorised_via_users_server`. It should be confirmed that the authorising user is in the room. (This prevents situations where any homeserver could process the join, even if @@ -103,22 +119,6 @@ Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be enforced over federation by event authorisation).[4](#f4) -It is possible for a resident homeserver (one which receives a `/make_join` / -`/send_join` request) to not know if the user is in some of the allowed rooms (due -to not participating in them). If the user is not in any of the allowed rooms that -are known to the homeserver it should return an error response with HTTP status code -of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should -attempt to join via another resident homeserver. If the resident homeserver knows -that the user is not in *any* of the allowed rooms it should return an error response -with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a -configuration error if there are allowed rooms with no participating authorised -servers. - -A chosen resident homeserver might also be unable to issue invites; in this case -it should return an error response with HTTP status code of 400 and an `errcode` -of `M_CANNOT_ALLOW`. The joining server should attempt to join via another -resident homeserver. - To better cope with joining via aliases, homeservers should use the list of authorised servers (not the list of candidate servers) when a user attempts to join a room. From 77422e211f8956b14d327a78de02f6aa45656883 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Jul 2021 13:37:40 -0400 Subject: [PATCH 58/66] Move changes to make/send_join out of auth rules section. --- proposals/3083-restricted-rooms.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 8c1f5b6b2e..3e4a33f07b 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -109,11 +109,11 @@ caveat that servers must ensure that: prevents situations where any homeserver could process the join, even if they weren't in the room, under certain power level conditions.) - This creates a new restriction on the relationship between the resident - servers used for `/make_join` and `/send_join` -- they must now both go to - the same server (since the `join_authorised_via_users_server` is added in - the call to `/make_join`, while the final signature is added during - the call to `/send_join`). +The above creates a new restriction on the relationship between the resident +servers used for `/make_join` and `/send_join` -- they must now both go to +the same server (since the `join_authorised_via_users_server` is added in +the call to `/make_join`, while the final signature is added during +the call to `/send_join`). Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be From 3885a9446498166cc459d4dab57dd9a37727ab32 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Jul 2021 13:41:05 -0400 Subject: [PATCH 59/66] Include an additional error situation. --- proposals/3083-restricted-rooms.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 3e4a33f07b..cbb2a2684b 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -113,7 +113,9 @@ The above creates a new restriction on the relationship between the resident servers used for `/make_join` and `/send_join` -- they must now both go to the same server (since the `join_authorised_via_users_server` is added in the call to `/make_join`, while the final signature is added during -the call to `/send_join`). +the call to `/send_join`). If a request to `/send_join` is received that includes +an event from a different resident server it should return an error response with +HTTP status code of 400. Note that the homeservers whose users can issue invites are trusted to confirm that the `allow` rules were properly checked (since this cannot easily be From d9cae9bac0643f9ccb8f2d478a991beb541f8828 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Tue, 20 Jul 2021 13:42:57 -0400 Subject: [PATCH 60/66] More review comments. --- proposals/3083-restricted-rooms.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index cbb2a2684b..a2c5f66339 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -77,7 +77,7 @@ servers. A chosen resident homeserver might also be unable to issue invites (which, as below, is a pre-requisite for generating a correctly-signed join event). In this case it should return an error response with HTTP status code of 400 and an `errcode` -of `M_CANNOT_ALLOW`. The joining server should attempt to join via another +of `M_UNABLE_TO_GRANT_JOIN`. The joining server should attempt to join via another resident homeserver. From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), @@ -88,9 +88,9 @@ caveat that servers must ensure that: * The join event has a valid signature from a homeserver whose users have the power to issue invites. - When generating a join event the server should include the MXID of a local user - who could issue an invite in the content with the key - `join_authorised_via_users_server`. The actual user chosen is arbitrary. + When generating a join event for `/join` or `/make_join`, the server should + include the MXID of a local user who could issue an invite in the content with + the key `join_authorised_via_users_server`. The actual user chosen is arbitrary. This implies that: From d12886912e95277e5a8fc7a4858d7edf8a42dd43 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 21 Jul 2021 07:38:27 -0400 Subject: [PATCH 61/66] Fix typos. Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- proposals/3083-restricted-rooms.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index a2c5f66339..da21da92aa 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -57,7 +57,7 @@ Any entries in the list which do not match the expected format are ignored. Thus if all entries are invalid, the list behaves as if empty and all users without an invite are rejected. -When an homeserver receives a `/join` request from a client or a `/make_join` / +When a homeserver receives a `/join` request from a client or a `/make_join` / `/send_join` request from another homeserver, the request should only be permitted if the user is invited to this room, or is joined to one of the listed rooms. If the user is not a member of at least one of the rooms, the homeserver should return @@ -102,7 +102,7 @@ caveat that servers must ensure that: * The auth chain of the join event needs to include events which prove the homeserver can be issuing the join. This can be done by including: - * The `m.room.power_levels` event + * The `m.room.power_levels` event. * The join event of the user specified in `join_authorised_via_users_server`. It should be confirmed that the authorising user is in the room. (This @@ -182,7 +182,7 @@ generating a join event. Peeking over federation, as described in could be used to establish if the user is in any of the proper rooms. This would then delegate power out to a (potentially) untrusted server, giving that -the peek server significant power. For example, a poorly chosen peek +peek server significant power. For example, a poorly chosen peek server could lie about the room membership and add an `@evil_user:example.org` to an allowed room to gain membership to a room. @@ -193,7 +193,7 @@ the requesting homeserver to retry via another homeserver. In the above example, suppose `@bob:server.example` leaves `!users:example.org`: should they be removed from the room? Likely not, by analogy with what happens -when you switch the join rules from public to invite. Join rules currently govern +when you switch the join rules from `public` to `invite`. Join rules currently govern joins, not existing room membership. It is left to a future MSC to consider this, but some potential thoughts are @@ -209,7 +209,7 @@ Another consideration is that users may have joined via a direct invite, not via access through a room. Fixing this is thorny. Some sort of annotation on the membership events might -help. but it's unclear what the desired semantics are: +help, but it's unclear what the desired semantics are: * Assuming that users in an allowed room are *not* kicked when that room is removed from `allow`, are those users then given a pass to remain @@ -236,7 +236,7 @@ restricting access via: * MXIDs or servers. * A shared secret (room password). -These are just examples are not fully thought through for this MSC, but it should +These are just examples and are not fully thought through for this MSC, but it should be possible to add these behaviors in the future. ### Client considerations From 2e7db4ac02e4a61dd86a19991fd884c8f3abac00 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 21 Jul 2021 07:41:56 -0400 Subject: [PATCH 62/66] Clarify error conditions. Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- proposals/3083-restricted-rooms.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index da21da92aa..44f5773a28 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -66,8 +66,8 @@ an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN` It is possible for a resident homeserver (one which receives a `/make_join` / `/send_join` request) to not know if the user is in some of the allowed rooms (due to not participating in them). If the user is not in any of the allowed rooms that -are known to the homeserver it should return an error response with HTTP status code -of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should +are known to the homeserver, and the homeserver is not participating in all listed +rooms, then it should return an error response with HTTP status code of 400 with an `errcode` of `M_UNABLE_TO_AUTHORISE_JOIN`. The joining server should attempt to join via another resident homeserver. If the resident homeserver knows that the user is not in *any* of the allowed rooms it should return an error response with HTTP status code of 403 and an `errcode` of `M_FORBIDDEN`. Note that it is a From 72ffbfe0bdac92a840ea5e4745b53eba3f4e7463 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 21 Jul 2021 07:48:31 -0400 Subject: [PATCH 63/66] Rename MSC. --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 44f5773a28..4994ed06a8 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -1,4 +1,4 @@ -# Restricting room membership based on space membership +# Restricting room membership based on membership in other rooms A desirable feature is to give room admins the power to restrict membership of their room based on the membership of one or more rooms. From 31a9b2a72072633d43d6964a94d0e753c5f0d4de Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 22 Jul 2021 10:17:37 -0400 Subject: [PATCH 64/66] Clarifications. Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- proposals/3083-restricted-rooms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 4994ed06a8..a8b2af3d07 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -82,7 +82,7 @@ resident homeserver. From the perspective of the [auth rules](https://spec.matrix.org/unstable/rooms/v1/#authorization-rules), the `restricted` join rule has the same behavior as `public`, with the additional -caveat that servers must ensure that: +caveat that servers must ensure that, for `m.room.member` events with a `membership` of `join`: * The user's previous membership was `invite` or `join`, or * The join event has a valid signature from a homeserver whose users have the From db089aa1f5e7a400120194929353f037eb5f711d Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 22 Jul 2021 10:18:14 -0400 Subject: [PATCH 65/66] De-indent section. --- proposals/3083-restricted-rooms.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index a8b2af3d07..501625a561 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -92,22 +92,22 @@ caveat that servers must ensure that, for `m.room.member` events with a `members include the MXID of a local user who could issue an invite in the content with the key `join_authorised_via_users_server`. The actual user chosen is arbitrary. - This implies that: +The changes to the auth rules imply that: - * A join event issued via `/send_join` is signed by not just the requesting - server, but also the resident server.[3](#f3) +* A join event issued via `/send_join` is signed by not just the requesting + server, but also the resident server.[3](#f3) - In order for the joining server to receive the proper signatures the join - event will be returned via `/send_join` in the `event` field. - * The auth chain of the join event needs to include events which prove - the homeserver can be issuing the join. This can be done by including: + In order for the joining server to receive the proper signatures the join + event will be returned via `/send_join` in the `event` field. +* The auth chain of the join event needs to include events which prove + the homeserver can be issuing the join. This can be done by including: - * The `m.room.power_levels` event. - * The join event of the user specified in `join_authorised_via_users_server`. + * The `m.room.power_levels` event. + * The join event of the user specified in `join_authorised_via_users_server`. - It should be confirmed that the authorising user is in the room. (This - prevents situations where any homeserver could process the join, even if - they weren't in the room, under certain power level conditions.) + It should be confirmed that the authorising user is in the room. (This + prevents situations where any homeserver could process the join, even if + they weren't in the room, under certain power level conditions.) The above creates a new restriction on the relationship between the resident servers used for `/make_join` and `/send_join` -- they must now both go to From 9699aa87f632bc393b29a7fd29258e309192fb81 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Fri, 23 Jul 2021 07:19:09 -0400 Subject: [PATCH 66/66] Note unstable prefix. --- proposals/3083-restricted-rooms.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/3083-restricted-rooms.md b/proposals/3083-restricted-rooms.md index 501625a561..941e2f4837 100644 --- a/proposals/3083-restricted-rooms.md +++ b/proposals/3083-restricted-rooms.md @@ -157,6 +157,9 @@ During development, an unstable room version of `org.matrix.msc3083.v2` will be Since the room version namespaces the behaviour, the `allow` key and value, as well as the `restricted` join rule value do not need unstable prefixes. +An unstable key of `org.matrix.msc3083.v2.event` will be used in the response +from `/send_join` in place of `event` during development. + ## Alternatives It may seem that just having the `allow` key with `public` join rules is enough