From 82c2ed6a479e510f33a7c0c60c9f17dea3a6799e 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 00000000..c65b1ca8 --- /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 f71e48c0acb8f1d9d0a294859db3de6e776ffef0 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 c65b1ca8..1121ebf6 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 4143f9ddcbbf183955353e142996f128fc0edf1d 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 1121ebf6..b8e3198b 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 ebae487451b2dae7394149710944bd2eb6b9fb6f 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 b8e3198b..b9945e35 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 b2b21e986ddae5bc7612d9b3600c2df2c1b1394f 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 b9945e35..979b19b0 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 85003eb7845e5ebfda28449225f7e42525a88538 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 979b19b0..909a1534 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 0992a4d60fb855016f0e919923c1072ff012aa2b 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 909a1534..f7846aed 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 933c50480c9377c100da984ebe42f5a6954289ae 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 f7846aed..d6f4ee33 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 35ce0b8f9152fe298fba14680ad77fca09cc800e 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 d6f4ee33..daa08e69 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 4051810241375a40c86b5d17911700b76114648c 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 daa08e69..71a0cd6b 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 6686696e66b9d6305c5198fcbc1ff6c0f3a24fc4 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 71a0cd6b..a3e5bd2e 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 ef02f82afb5244dac455282157b89513a99255a6 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 a3e5bd2e..76852998 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 7994a1e85a3fd1344015eab2e41530c1c4516b05 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 76852998..c21e4078 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 959c6aa8161132123b273d3864755e8a6abfa9a9 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 c21e4078..be507cb5 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 6919bbf80cd952a24b8168d1aac2a01a96699c85 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 be507cb5..aa8f25e7 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 084e6225c5d42b54f746068e55f424bc65fd8af5 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 aa8f25e7..5399fb4c 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 31cdf835b8417eff1966fbe3c53e37eb29306c87 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 5399fb4c..62d4029c 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 963aa4066579756a865c8b001b28a66086b35a52 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 62d4029c..b3daba6d 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 5c6e76a63b980d4689a1bbb9429c3371a14c1852 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 b3daba6d..9146c457 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 955160c750a4bc94406fe2edad09bf7f9b39372e 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 9146c457..fda81592 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 486026a71182bd8d97f0584799a44219faa80ecc 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 fda81592..506067c5 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 5d1bebedf05a9c4a01d96e856a1ee58bc128853e 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 506067c5..85ef353c 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 06f0d622a97fc969d99a91d95d8f215384155815 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 85ef353c..b3637140 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 51650b63f22183af9cc0a1a939e1143423af0bcd 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 b3637140..d3b0e4a0 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 4afe946defdea69a222b7e2f3d2c8d22c8625056 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 d3b0e4a0..ec2893b1 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 d63e39c4aff63222d6494c02dca95d9be69f0a1e 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 ec2893b1..e3415cbe 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 066f25fd82f7712cb2ce56d7deab5ce267af153c 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 e3415cbe..b13589cd 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 e3692edd0910d816574caeb27fae23d4cdbcab91 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 b13589cd..936470b9 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 cd78eed3f1f8fb90833778a13876d36087ee3cc3 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 936470b9..053adca8 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 d445b0785548c499968e5550b5fd7785c9d32eb4 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 053adca8..bd5b506e 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 53bae34457f3124fd829253cd8b1684a17d10b6f 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 bd5b506e..8af446ca 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 f4e2d925e3ad396412a65c31e676e1f22a3c3104 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 8af446ca..8107a993 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 3377d55c281168a36742cead581dc2a79bfcb248 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 8107a993..1aae6d42 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 2171d175e835ab8c08048388c0fa03b7e14092db 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 1aae6d42..9adad0b6 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 ba63bedec0fa0a83fcde7ea9597a3eeabe335df2 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 9adad0b6..63d290aa 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 289c64035f8715ac882af509c65475619d9350ad 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 63d290aa..6e30f09e 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 2749a952513180f7d49640006ed687b02f3030a3 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 6e30f09e..b33c4f0c 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 750be83313e79649d0870e2b53f3a02dbe986894 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 b33c4f0c..a77c3638 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 75fc073bfcda0f3e8c4b1c3a44ec31097e1db26d 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 a77c3638..bd6b0a7e 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 84178b1d39f428a23d2100d3f345e8d246fe8c74 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 bd6b0a7e..19ea0ab9 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 48674a33532b6c3d30893a32d5bad227b0ec058f 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 19ea0ab9..7389cacb 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 1f7481bfbdb0bea353f99ab3ceb2d70093a8a25d 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 7389cacb..b9e3660e 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 7aeca9ccb64de17c25de32ed2c28ae37bea393cb 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 b9e3660e..60d54290 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 e93accf19895874f7baf549ed60f8ad9888944d0 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 60d54290..6f45b68b 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 aed1e2313117617c5221b14ca5b5350188e0c194 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 6f45b68b..93095247 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 12a39f66df43fbfeeb5e9c3661233510257749ec 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 93095247..5a23a9db 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 04c88f584c87d0842c54110c0ba3031fbdd1e4cc 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 5a23a9db..3e0f0f7c 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 c42e89a4d40cac4c7186647606cd5618a499a4e9 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 3e0f0f7c..bf67cd11 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 72f564c236a342688f1216b8614085af79658603 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 bf67cd11..91bf5f5b 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 248cb8b3100943be84579a7fa96a9889770ae07c 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 91bf5f5b..89103c0d 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 2bc4e86cb48f9e6d59e94380d9da288179287833 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 89103c0d..063251d9 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 cff5a8728ef74df91ef1fa04526974867f43a724 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 063251d9..dadff376 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 6b6aa2449a6597ae7e9e42ec1e92ab3aadddcabf 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 dadff376..d739c48e 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 d329c216c41e9b1fce643ae4da0f7a219c87ef2b 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 d739c48e..8e7c82fe 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 27bee1bad8ebcc31411ec68026b44cf32b9755b3 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 8e7c82fe..83073f21 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 67e558da524acdc1c497afa314d8a3eb9810de0f 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 83073f21..923477dc 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 c6f0119b13db38c140b54bfcb6fbc5d9ed9c58a4 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 923477dc..8c1f5b6b 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 58ccb86a347e52b9061afaa2f789fbb56877d5c5 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 8c1f5b6b..3e4a33f0 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 977146baf5a6239c240a6fa0042b297656f1c086 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 3e4a33f0..cbb2a268 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 72961e6f296388552cfc06cb2fc5a37bfc452460 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 cbb2a268..a2c5f663 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 d399653cab95136a876ee78d475da87d95693e9f 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 a2c5f663..da21da92 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 c79d1ac350afe14d85d3d43f204815bb11e4519e 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 da21da92..44f5773a 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 7cecb84afee2fa40e5043495bbd1ada10c4c3b76 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 44f5773a..4994ed06 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 fd0c90964400b5cc05dfb24b2163fbefa8cfc197 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 4994ed06..a8b2af3d 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 dcd6de59cdca0fb47162dde8ffa4a5f096641463 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 a8b2af3d..501625a5 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 7ff569f2524fe9e33707da018f57a8c235e5b9d4 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 501625a5..941e2f48 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