Skip to content

MSC4124: Simple Server Authorization #4124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
164 changes: 164 additions & 0 deletions proposals/4124-server-auth-simple.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# MSC4124: Simple server authorization

This MSC proposes simple authorization rules that consider the origin
server of a given event, with the aim of replacing `m.room.server_acl`.
Comment on lines +3 to +4
Copy link
Member

Choose a reason for hiding this comment

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

This could do with a paragraph or two before this one which describes how server ACLs work today, and why they're insufficient.

For example:

[Server ACLs] in Matrix operate as a network firewall described by the room, requiring participation from all joined servers to be fully enforced. As they are not applied to the room model though, leaks can occur where a server not enforcing the ACLs (typically due to simply not implementing them) "pulls" events from banned servers into the room via prev_events. When an event referencing the banner server's events is sent over federation, the remote servers in turn fetch the banned events and present them to users.

Workarounds currently include banning/kicking all users from a banned server, and monitoring for leaks to potentially ban servers not enforcing the ACLs. These solutions require a room moderator to be highly knowledgeable on how ACLs actually work, which is rarely the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have now added a giant context section, but maybe this section should be moved to matrix-org/matrix-spec#928? what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that the section should be moved to the issue because it's independent to the proposal, but the proposal should be modified to keep referring back to it. But I want to hear from you before I do that.

Copy link
Member

Choose a reason for hiding this comment

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

Proposals should have enough context to be understood in isolation, as issues may be edited or mutated after the MSC is accepted. #4126 is an example for incorporating issue context into the proposal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, in that case I will add each point to the issue and make a shorter reference to them.


This is a compromising MSC based on [MSC4099](https://github.com/matrix-org/matrix-spec-proposals/pull/4099)
that tries to use concepts even more inline current authorization events
This MSC was also created in reaction to [MSC2870](https://github.com/matrix-org/matrix-spec-proposals/pull/2870),
that describes itself as stop gap to cover what the MSC has described
short comings of `m.room.server_acl`. We also agree that MSC2870 is
a stop gap and that the `m.room.server_acl` has severe shortcomings,
but we take the view that after 4 years of proposed stop-gaping,
there is enough time to introduce a more complete solution.
Comment on lines +8 to +13
Copy link
Member

Choose a reason for hiding this comment

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

The language around MSC2870 here feels a bit strong. I'd suggest something along the lines of this:

Suggested change
This MSC was also created in reaction to [MSC2870](https://github.com/matrix-org/matrix-spec-proposals/pull/2870),
that describes itself as stop gap to cover what the MSC has described
short comings of `m.room.server_acl`. We also agree that MSC2870 is
a stop gap and that the `m.room.server_acl` has severe shortcomings,
but we take the view that after 4 years of proposed stop-gaping,
there is enough time to introduce a more complete solution.
[MSC2870](https://github.com/matrix-org/matrix-spec-proposals/pull/2870)
describes a mechanism to help prevent rooms from breaking when a
room moderator redacts a server ACL event, and notes that such a
mechanism should be considered temporary until another MSC can replace
the server ACLs system with something more built into the room model.
This MSC is one variation on that future proposal.


Related issues:
- https://github.com/matrix-org/matrix-spec/issues/928

## Proposal
Copy link
Member

Choose a reason for hiding this comment

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

Overall I think some sequence diagrams and example events would be helpful here. It's not clear to me what causes a server to try knocking (is it based on user action? which actions?), or how the various events really interact with each other.

Copy link
Contributor Author

@Gnuxie Gnuxie Apr 10, 2024

Choose a reason for hiding this comment

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

Yes, that's a really good idea, I'll try find the way other MSCs embed diagrams

Edit: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams

Copy link
Contributor Author

@Gnuxie Gnuxie Apr 10, 2024

Choose a reason for hiding this comment

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

I've added diagrams for room creation and joining a room, are there any other scenarios you think will be helpful to show on a diagram?

Copy link
Member

Choose a reason for hiding this comment

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

The diagrams look like a great start, thank you! Could we get some examples of what the flows look like when the knock rule isn't passive?

Separately, some words on what Bob's user experience looks like would be good. This won't be a normative section, but helps ensure the proposal has considered user impact in its decisions.


### The `m.server.knock` authorization rule

This rule is be inserted after rule 3 in version 11, the check
for `m.room.create`'s content field `m.federate`.

1. If the type is `m.server.knock`:
1. If the `state_key` does not contain the server name for the
origin server, reject.
2. If there is existing state for the origin server's `m.server.knock`, reject.
3. If the origin server's current participation is `permitted`, allow.
4. If the `m.server.knock_rule` is `deny`, reject.
5. If the origin server's current participation is `deny`, reject.
6. Otherwise allow.

The purpose of this rule is to allow a server to send a knock
event, even if the `sender` has no membership event.

The purpose of rule 1.2 is to prevent denied servers from ever being
given the ability to craft any event whatsoever in a room that has always
had the `active` `m.server.knock_rule`.
This is because an `m.server.participation` event set to `deny` will
usually be topologically older than an `m.server.knock` due to the
`m.server.participation` usually referencing a recent
`m.room.power_levels` event. And so `m.server.knock` events could
be crafted by malicious servers without restriction without
rule 1.2.

### The `m.server.participation` authorization rule

This rule is to be inserted before rule 4 in version 11,
the check for `m.room.member`, and after the `m.server.knock` rule
described in this proposal.

1. If the origin server's current `participation` state is not `permitted`:
1. If the `participation` state is `deny`, reject.
2. If the `m.server.knock_rule` is `deny`, reject.
3. If the `m.server.knock_rule` is anything other than `passive`, reject.

### The `m.server.participation` authorization event, `state_key: ${origin_server_name}`

This is an authorization event that is used to authorize events
originating from the server named in the `state_key`.

`participation` can be one of `permitted` or `deny`.
`participation` is protected from redaction.

A denied server must not be sent a `m.server.participation` event unless
the targeted server is already present within the room, or it has
an existing `m.server.knock` event.
This is to prevent malicious servers being made aware of rooms that
they have not yet discovered.

A `reason` field can be present alongside `participation` in order to
explain the reason why a server has been `denied`.
This reason is to be shown to a joining, or previously present
server, so that the server's users can understand why they are not
being allowed to participate.

### The `m.server.knock_rule` event, `state_key: ''`

This event has one field, `rule` which can be one of the following:

- `deny`: Users are unable to send the `m.server.knock` event
unless there is an existing `m.server.participation` event for the
server.
- `passive`: Users can send the `m.server.knock` event without
corresponding membership or server participation.
- `active`: Users can send the `m.server.knock` event but
cannot send any other event without a corresponding
participation of `permitted`.

`rule` is protected from redaction.

The `passive` state allows for rooms to operate as they do today,
new servers can freely join a room and start sending events without
prior approval from the administrators

The `active` state allows for a much safer way to run public Matrix rooms,
new servers can join a room, send the `m.server.knock` event
but cannot do more until a room administrator permits the new joiner with
an `m.server.participation` event. We expect that in practice automated
tooling will perform a simple reputation check and immediately permit
a new server to participate. This is an essential part of the proposal
as the `active` mechanism eliminates a current shortfall that
`m.room.server_acl` is a purely reactive tool in a join wave attack.

### The `m.server.knock` event, `state_key: ${origin_server_name}`

This event has no fields, because it can only be sent once, and
therefore cannot be edited if the wrong or malicious information
is provided.

The intent of the event is to only let the room administrators
explicitly aware of the server's existence.

### The `make_server_knock` handshake
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If someone can find a way to avoid the handshake, that would be great.

The only reason why it is included is because we use the signing of the m.server.knock template to verify the origin of the event. And it stops other servers creating m.server.knock events for servers that do not exist or servers that are not wanting to send a knock event to the room.


This MSC requires a very simple clone of the `make_knock` handshake
for the purpose of signing and creating the `m.server.knock` event.

The details of this handshake are left outside the scope of the MSC,
as it may be decided that an API providing an agnostic unification of
`make_knock` and `make_join` should be used instead that signs
both the membership event and the `m.server.knock` event templates.

We believe that the open choice here should not alone be a reason
to block this MSC from consideration. But we will follow up
with a clone of the `make_knock` handshake if requested.

## Potential issues

### Racing with `m.server.knock_rule`?

We will embed `m.server.knock_rule` in `m.room.create` if it
someone raises concerns about a potential race condition or other issue
about this conflicting with `m.server.participation`. However, stating
that there might be without elaboration is not helpful, I'd need to
know how the race works. If there is insistence, then we will embed
within the `m.room.create` event.

### Soft failure of backfilled messages

Servers that had `participation` of `permitted` that are later
denied via `deny`, will have their historical messages soft failed by
servers which later join.

This should be addressed with [MSC4104](https://github.com/matrix-org/matrix-spec-proposals/pull/4104).

## Alternatives

- [MSC4099](https://github.com/matrix-org/matrix-spec-proposals/pull/4099) Participation based authorization for servers in the Matrix DAG
- [MSC3953](https://github.com/matrix-org/matrix-spec-proposals/pull/3953) Server capability DAG

## Security considerations

None considered.

## Unstable prefix

`me.marewolf.msc4124.*`

## Dependencies

No direct dependencies
See `make_server_knock` handshake.