Merge 50cc4f4bb6
into d6edcbd946
commit
61fc49b6d8
@ -0,0 +1,175 @@
|
||||
# MSC4056: Role-Based Access Control (mk II)
|
||||
|
||||
A common request in Matrix is the ability to assign a set of permissions to a set of users without
|
||||
having to give inherited permissions. Power levels currently provide an ability to define roles,
|
||||
though each higher power level inherits the permissions from under it. A more formal Role-Based
|
||||
Access Control (RBAC) mechanism would allow a user to inherit permissions from another role while
|
||||
having specifics be negated, unlike power levels.
|
||||
|
||||
This proposal aims to improve upon the learnings of [MSC2812](https://github.com/matrix-org/matrix-spec-proposals/pull/2812),
|
||||
particularly around the decentralization and state resolution components. The specific permissions
|
||||
supported by roles are left out of scope in this version of the proposal.
|
||||
|
||||
MSC2812 fails to operate when state resolution is considered due to how it is structured. In isolation,
|
||||
the MSC offers a sturdy framework for RBAC, but when two changes utilizing a role are in conflict,
|
||||
state resolution will fail to pick a "winning" change. This proposal addresses the problem by applying
|
||||
a power level structure over top of roles, providing a deliberate hierarchy of roles.
|
||||
|
||||
**TODO: Insert text about why RBAC is cool/wanted, and why we've avoided it in the past (NTFS hell,
|
||||
flight console UX, etc)**
|
||||
|
||||
## Potential issues
|
||||
|
||||
*Author's note: This section is up here to be clear about which problems are considered TODO items.*
|
||||
|
||||
This MSC does *not* have:
|
||||
|
||||
* Backwards compatibility with existing clients/tooling.
|
||||
* Explicit permissions a role could have. It is assumed for now that the permissions implied by power
|
||||
levels are maintained at a minimum. For example, ability to send an event of a given type.
|
||||
* A complete solution. It outlines a framework at the moment.
|
||||
|
||||
## Proposal
|
||||
|
||||
In a future room version, due to dramatic changes relating to how rooms work, we do the following.
|
||||
|
||||
`m.room.power_levels` is stripped of its usefulness. Clients MAY send it, but it will be treated as
|
||||
any other random event. Servers MAY optionally decide to prevent clients from sending it by accident
|
||||
in applicable room versions.
|
||||
|
||||
A new `m.role` state event is introduced, with `state_key` being an arbitrary opaque string. The
|
||||
`state_key` becomes the "Role ID". The `content` for the role is as follows:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"profile": {
|
||||
// display name, avatar, colour, etc? Use extensible events content blocks where reasonable.
|
||||
},
|
||||
"permissions": {
|
||||
// TODO: Replace example with actual permission (m.invite or whatever)
|
||||
"org.example.my_permission": true,
|
||||
"org.example.another": {
|
||||
"is_complicated_type": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`m.profile` is inspired by [MSC3949](https://github.com/matrix-org/matrix-spec-proposals/pull/3949),
|
||||
where allowing a user to define such characteristics is clearly desirable. `m.permissions` are the
|
||||
permissions themselves (which may be non-boolean values).
|
||||
|
||||
The users "affected" by this role are described in a second new state event: `m.role_map` with an
|
||||
empty string `state_key`. The `content` being:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"role_id": {
|
||||
"users": ["@alice:example.org"],
|
||||
"order": 1
|
||||
},
|
||||
"another_role_id": {
|
||||
"users": ["@bob:example.org"],
|
||||
"order": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each role MUST have a distinct `order` number. Roles with higher `order` override conflicting permissions
|
||||
from lower `order` roles. For example, given the following:
|
||||
|
||||
* "Role A" with `order: 1` and permission `first: true, second: true`.
|
||||
* "Role B" with `order: 2` and permissions `first: false, third: true`.
|
||||
|
||||
... a user with both roles would have permissions `first: false, second: true, third: true`. `first` is
|
||||
overridden by the `order: 2` role, but `second` and `third` are not conflicting.
|
||||
|
||||
When an event is sent by a user, it MUST reference the `m.role_map` and `m.role` events applicable
|
||||
to the `sender` from that map as `auth_events`.
|
||||
|
||||
MSC2812 has a fundamental flaw in how it authorizes events, preventing it from working reliably in
|
||||
a decentralized environment. When a user with Role A is trying to ban a user, and the target user
|
||||
is removing that permission from Role A at the same time, the conflict becomes impossible to predict
|
||||
because state resolution will ultimately tiebreak on event ID. This unexpected behaviour can be (at
|
||||
best) confusing for users.
|
||||
|
||||
This MSC fixes that flaw by retaining a concept of "power level", but only applying it to the roles
|
||||
themselves through `order`. When state resolution is attempting to resolve a power struggle, it would
|
||||
first determine which role has higher `order`, then let that event "win" the conflict. In the cases
|
||||
where the two involved users have the *same* role, timestamps and event IDs are used as tiebreaks,
|
||||
like with any other event. In other words, a user's power level is effectively the highest `order`
|
||||
role they possess with the required permission(s).
|
||||
|
||||
When the users involved in a conflict are at the same effective power level, it is less surprising
|
||||
to those users that a conflict would be resolved by timestamp or "flip of a coin" (event ID ordering).
|
||||
For other cases however, users will typically have an implied hierarchy in mind even if `order` didn't
|
||||
exist, leading to an expectation that users with "Admin" have "more power" than those with "Moderator".
|
||||
The `order` field formalizes the user preference (and therefore expectation).
|
||||
|
||||
For the above reasons relating to state resolution, we intentionally mix user assignment and ordering
|
||||
into the same event type. Ideally, the `order` (and possibly even assignment) would be done on the
|
||||
`m.role` events themselves, however in a conflicted set of state it becomes difficult or impossible
|
||||
to enforce "one role per order number" during event authorization.
|
||||
|
||||
### Detailed authorization rule changes
|
||||
|
||||
**TODO**
|
||||
|
||||
### Detailed state resolution changes
|
||||
|
||||
**TODO**
|
||||
|
||||
### Detailed redaction algorithm changes
|
||||
|
||||
**TODO**
|
||||
|
||||
### Test vectors
|
||||
|
||||
**TODO**
|
||||
|
||||
## Potential issues
|
||||
|
||||
**TODO: Complete more of this section.**
|
||||
|
||||
* A limited number of roles can be used and assigned, as `m.role_map` will be subject to size restrictions.
|
||||
* This MSC is intentionally does not support per-user role ordering. This is a complicated feature to
|
||||
represent (when considering state resolution), and is empirically not used by Discord. A future room
|
||||
version may introduce such a feature.
|
||||
|
||||
## Alternatives
|
||||
|
||||
[MSC2812](https://github.com/matrix-org/matrix-spec-proposals/pull/2812) is the primary alternative to
|
||||
this MSC. [MSC3073](https://github.com/matrix-org/matrix-spec-proposals/pull/3073) inherits from MSC2812
|
||||
and is subject to the same issues described by this proposal. MSC3073 does introduce per-user role
|
||||
ordering, though not in a way compatible with state resolution/conflicts.
|
||||
|
||||
[MSC3949](https://github.com/matrix-org/matrix-spec-proposals/pull/3949) aims to introduce the "profile
|
||||
information" for a role without introducing RBAC itself. This proposal inherits the ideas of MSC3949.
|
||||
|
||||
No other significant alternatives are considered. Some minor representation details are possible, however
|
||||
clients like Discord are generally seen as the "gold standard" for user-facing RBAC implementation. Those
|
||||
clients don't make use of many theorized alternatives.
|
||||
|
||||
## Security considerations
|
||||
|
||||
**TODO**
|
||||
|
||||
If `m.role_map` uses a role ID which doesn't exist and assigns users to it, those users will never be able
|
||||
to send events because the `auth_events` will never be complete. This needs to be fixed before this MSC
|
||||
enters FCP, at least for `m.room.member` and similar power events.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this proposal is not incorporated into a stable room version, implementations should use `org.matrix.msc4056`
|
||||
as an unstable room version, using [room version 11](https://spec.matrix.org/v1.8/rooms/v11/) as a base. The
|
||||
event types are also prefixed in this room version.
|
||||
|
||||
| Stable | Unstable |
|
||||
|--------|----------|
|
||||
| `m.role` | `org.matrix.msc4056.role` |
|
||||
| `m.role_map` | `org.matrix.msc4056.role_map` |
|
||||
|
||||
## Dependencies
|
||||
|
||||
As of writing, this MSC is being evaluated as a potential feature for use in the MIMI working group at
|
||||
the IETF through the Spec Core Team's efforts.
|
Loading…
Reference in New Issue