Merge branch 'rav/msc1730/work' into rav/proposal/cs_api_in_login
This commit is contained in:
commit
a9c4ea690d
5 changed files with 147 additions and 122 deletions
|
@ -1,111 +1,108 @@
|
|||
# MSC1730: Mechanism for redirecting to an alternative server during login
|
||||
|
||||
Complex homeserver deployments may consist of several homeserver instances,
|
||||
where the HS to be used for a user session is determined at login time. The HS
|
||||
might be chosen based on any of a number of factors, such as the individual
|
||||
user, or a simple round-robin to load-balance.
|
||||
## Background/requirements
|
||||
|
||||
One solution to this is for users to log in via a "portal server", which
|
||||
accepts the login request, and picks the server accordingly. This proposal
|
||||
suggests adding a field to the `/login` response which tells clients which
|
||||
endpoint they should use for the client-server (C-S) API after login.
|
||||
This is a proposal for a mechanism for handling the following situation.
|
||||
|
||||
A large, loosely-coupled organisation wants its members to be able to
|
||||
communicate with one another via Matrix. The organisation consists of several
|
||||
departments which are cooperative but prefer to host their own infrastructure.
|
||||
|
||||
The organisation has an existing single-sign-on system which covers the entire
|
||||
organisation, and which they would like their members to use when
|
||||
authenticating to the Matrix system.
|
||||
|
||||
## Proposal
|
||||
|
||||
The response to `POST /_matrix/client/r0/login` currently includes the fields
|
||||
`user_id`, `access_token`, `device_id`, and the deprecated `home_server`.
|
||||
|
||||
We should add to this a `base_cs_url` field, which SHOULD be returned by
|
||||
compliant homeservers, which gives a base URL for the client-server API.
|
||||
We will add to this the the field `well_known`, which has the same format as
|
||||
the [`/.well-known/matrix/client`
|
||||
object](https://matrix.org/docs/spec/client_server/r0.4.0.html#get-well-known-matrix-client).
|
||||
|
||||
As with
|
||||
[.well-known](https://matrix.org/docs/spec/client_server/r0.4.0.html#well-known-uri),
|
||||
clients would then add `/_matrix/client/...` to this URL to form valid C-S
|
||||
endpoints.
|
||||
Servers MAY add this field to the login response if they wish to redirect
|
||||
clients to an alternative homeserver after login. Clients SHOULD use the
|
||||
provided `well_known` object to reconfigure themselves, optionally validating the
|
||||
URLs within.
|
||||
|
||||
One way that this could be used is that the portal server proxies the `/login`
|
||||
request, and passes it on to the target HS, as shown in the sequence diagram below:
|
||||
## Application
|
||||
|
||||
Let's imagine for this description that our organisation is the University of
|
||||
Canadialand, which is divided into departments including Engineering, History,
|
||||
Physics, and so on.
|
||||
|
||||
Central University IT currently host a SAML2-based single-sign-on system, which
|
||||
asks users to select their department, and then defers to the departmental
|
||||
authentication system to authenticate them. Note that the users do not have a
|
||||
globally-unique identifier.
|
||||
|
||||
University IT now sets up a Matrix Homeserver instance, which they host at
|
||||
`https://matrix.ac.cdl`. They run a publicity campaign encouraging university
|
||||
members to use the service by configuring off-the-shelf Matrix clients to use
|
||||
the homeserver at `https://matrix.ac.cdl`. They may also release customised
|
||||
clients configured to use that URL by default.
|
||||
|
||||
However, the departments actually want to host their own homeservers; these
|
||||
might be at `https://matrix.eng.ac.cdl`, `https://matrix.hist.ac.cdl`, etc. The
|
||||
central IT homeserver therefore redirects clients to the departmental
|
||||
homeserver after login.
|
||||
|
||||
A complete login flow is as shown in the following sequence diagram:
|
||||
|
||||

|
||||
|
||||
Alternatively, the portal server could redirect the original `login` request to
|
||||
the target HS with a `307 Temporary Redirect` response:
|
||||
|
||||

|
||||
|
||||
(Note that the deprecated `home_server` field gives the `server_name` of the
|
||||
relevant homeserver, which may be quite different to the location of the C-S
|
||||
API, so is not of use here. Further we cannot repurpose it, because (a) this
|
||||
might break existing clients; (b) it spells homeserver wrong.)
|
||||
|
||||
### Notes on proxying vs redirecting
|
||||
|
||||
Proxying the `/login` request as shown in the first sequence diagram above
|
||||
leads to the following concerns:
|
||||
|
||||
* The target homeserver sees the request coming from the portal server rather
|
||||
than the client, so that the wrong IP address will be recorded against the
|
||||
user's session. (This might be a problem for, for example, IP locking the
|
||||
session, and might affect the `last_seen_ip` field returned by `GET
|
||||
/_matrix/client/r0/devices`.)
|
||||
|
||||
This can be mitigated to some extent via the use of an `X-Forwarded-For`
|
||||
header, but that then requires the portal server to authenticate itself with
|
||||
the target homeserver in some way.
|
||||
|
||||
* It causes additional complexity in the portal server, which must now be
|
||||
responsible for making outbound HTTP requests.
|
||||
|
||||
* It potentially leads to a privacy leak, since the portal server could snoop
|
||||
on the returned access token. (Given that the portal server must be trusted
|
||||
to some extent in this architecture, it is unclear how much of a concern this
|
||||
really is.)
|
||||
|
||||
On the other hand, redirecting it with a `307` response may reduce flexibility,
|
||||
or require more state to be managed on the portal server [1]. Furthermore
|
||||
support for `307` redirects among user-agents may vary
|
||||
([RFC2616](https://tools.ietf.org/html/rfc2616#section-10.3.8) said "If the 307
|
||||
status code is received in response to a request other than GET or HEAD, the
|
||||
user agent MUST NOT automatically redirect the request unless it can be
|
||||
confirmed by the user", though this appears to have been dropped by
|
||||
[RFC7231](https://tools.ietf.org/html/rfc7231#section-6.4.7) and I am unaware
|
||||
of any current browsers which do not follow `307` redirects.)
|
||||
|
||||
In any case, this is an implementation decision; portal servers can use
|
||||
whichever method best suits their needs.
|
||||
Note that this flow is complicated by the out-of-band SAML2 authentication. We
|
||||
envisage that a similar technique could also be used for a standard
|
||||
username/password authentication, however.
|
||||
|
||||
## Rejected solutions
|
||||
|
||||
Alternative solutions might include:
|
||||
|
||||
### Have all users on one homeserver
|
||||
|
||||
In many situtations, it might be more appropriate to have a single homeserver,
|
||||
so users' MXids would look like `@user:ac.cdl` instead of
|
||||
`@user:eng.ac.cdl`.
|
||||
|
||||
However, there are circumstances where separate homeservers are required:
|
||||
|
||||
### Tell users the C-S API for their home homeserver
|
||||
|
||||
We could tell Engineering users to configure their clients with
|
||||
`https://matrix.eng.ac.cdl`, History users to use `https://matrix.hist.ac.cdl`,
|
||||
etc.
|
||||
|
||||
The problems with this are:
|
||||
|
||||
* Each department must issue its own documentation and publicity advising how
|
||||
to configure a Matrix client
|
||||
|
||||
* It becomes impractical to distribute preconfigured clients.
|
||||
|
||||
### Proxy all C-S endpoints
|
||||
|
||||
It would be possible for the portal to proxy all C-S interaction, as well as
|
||||
`/login`, directing requests to the right server for the user.
|
||||
It would be possible for the the central homeserver to proxy all C-S
|
||||
interaction, as well as `/login`, directing requests to the right server for
|
||||
the user.
|
||||
|
||||
This is unsatisfactory due to the additional latency imposed, the load on the
|
||||
portal server, and the fact that it makes the portal a single point of failure
|
||||
for the entire system.
|
||||
central homeserver, and the fact that it makes the central server a single
|
||||
point of failure for the entire system.
|
||||
|
||||
### Perform a .well-known lookup after login
|
||||
### Require clients to perform a .well-known lookup after login
|
||||
|
||||
Once clients know the server name of the homeserver they should be using
|
||||
(having extracted it from the `/login` response), they could perform a
|
||||
`.well-known` lookup on the target server to locate its C-S API.
|
||||
We could require clients to do a .well-known lookup on the domain of their MXID
|
||||
once they have discovered it from the `/login` response.
|
||||
|
||||
This has the advantage of reusing existing mechanisms, but has the following
|
||||
problems:
|
||||
This has the following problems:
|
||||
|
||||
* Clients are currently required to do a `.well-known` lookup *before* login,
|
||||
so that they can find the correct endpoint for the `/login` API. That means
|
||||
they will have to do *two* `.well-known` lookups - one before and one after
|
||||
login.
|
||||
* In most cases this `.well-known` lookup will be entirely redundant. It adds
|
||||
latency and overhead, and complicates client implementations.
|
||||
|
||||
This adds latency and overhead, and complicates client implementations.
|
||||
|
||||
* It complicates deployment, since each target server has to support a
|
||||
`.well-known` lookup. (This is somewhat weak: target servers should
|
||||
support `.well-known` lookups anyway.)
|
||||
* It complicates deployment, since each department has to host a `.well-known`
|
||||
file at their root domain.
|
||||
|
||||
### Add an alternative redirection mechanism in the login flow
|
||||
|
||||
|
@ -117,12 +114,33 @@ endpoint for all future C-S interaction.
|
|||
|
||||
This approach would complicate client implementations.
|
||||
|
||||
### Modify the single-sign-on flow
|
||||
|
||||
[1] The reason more state is needed is as follows: because the portal is now
|
||||
redirecting the login rather than proxying it, it cannot modify the login
|
||||
dictionary. This is a problem for the single-sign-on flow, which culminates in
|
||||
an `m.login.token` login. The only way that the portal can identify a given
|
||||
user session - and thus know where to redirect to - is via the login token, and
|
||||
of course, it cannot modify that token without making it invalid for the target
|
||||
HS. It therefore has to use the login token as a session identifier, and store
|
||||
session state..
|
||||
It would be possible to modify the single-sign-on flow to allow an alternative
|
||||
homeserver to be specified for the final `m.login.token`-based call to
|
||||
`/login` (and subsequent C-S API calls).
|
||||
|
||||
This is discussed in more detail in
|
||||
[MSC1731](https://github.com/matrix-org/matrix-doc/blob/rav/proposals/homeserver_in_sso_login/proposals/1731-redirect-in-sso-login.md).
|
||||
|
||||
It has the disadvantage of limiting the solution to SSO logins. The solution
|
||||
presented in this proposal also extends to password-based logins.
|
||||
|
||||
### Use a 3pid login flow
|
||||
|
||||
It has been suggested that we could use a login flow based on third-party
|
||||
identifiers.
|
||||
|
||||
In the current ecosystem, to do a 3pid login, clients must still be configured
|
||||
to send their `/login` request to a particular homeserver, which will then take
|
||||
them through an authentication process. We are therefore still left with the
|
||||
problem that we need to switch homeservers between login and initial sync.
|
||||
|
||||
An alternative would be for clients to somehow know that they should go through
|
||||
the single-sign-on process *before* choosing a homeserver, and for the
|
||||
output of the single-sign-on process to indicate the homeserver to use. This
|
||||
would require either substantially customised Matrix clients, or substantial
|
||||
modifications to the login flow in Matrix, possibly involving authenticating
|
||||
against an identity server. The latter is something which could be considered,
|
||||
but the scope of the changes required make it impractical in the short/medium
|
||||
term.
|
||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 13 KiB |
|
@ -1,18 +0,0 @@
|
|||
participantspacing equal
|
||||
|
||||
Client->Portal:""POST /_matrix/client/r0/login
|
||||
activate Portal
|
||||
Portal-->Client:""307"" redirect
|
||||
deactivate Portal
|
||||
|
||||
Client->Target HS:""POST /_matrix/client/r0/login
|
||||
activate Target HS
|
||||
Target HS->Client:""{"base_cs_url": "http://targeths",\n"access_token": "...", ...}
|
||||
deactivate Target HS
|
||||
|
||||
Client->Target HS: ""/_matrix/client/versions
|
||||
activate Target HS
|
||||
Target HS-->Client: ""{"versions": [...]}
|
||||
deactivate Target HS
|
||||
|
||||
Client<->Target HS: Further C-S APIs
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 35 KiB |
|
@ -1,17 +1,43 @@
|
|||
# https://sequencediagram.org/
|
||||
|
||||
participantspacing equal
|
||||
participant Client
|
||||
participant matrix.ac.cdl
|
||||
participant SAML2 SSO system
|
||||
participant matrix.eng.ac.cdl
|
||||
|
||||
Client->Portal:""POST /_matrix/client/r0/login
|
||||
activate Portal
|
||||
Portal->Target HS:""POST /_matrix/client/r0/login
|
||||
activate Target HS
|
||||
Target HS-->Portal:""{"base_cs_url": "http://targeths",\n"access_token": "...", ...}
|
||||
deactivate Target HS
|
||||
Portal->Client:""{"base_cs_url": "http://targeths",\n"access_token": "...", ...}
|
||||
deactivate Portal
|
||||
activate Client
|
||||
|
||||
Client->Target HS: ""/_matrix/client/versions
|
||||
activate Target HS
|
||||
Target HS-->Client: ""{"versions": [...]}
|
||||
deactivate Target HS
|
||||
|
||||
Client<->Target HS: Further C-S APIs
|
||||
Client->matrix.ac.cdl:""GET /_matrix/client/r0/login""
|
||||
activate matrix.ac.cdl
|
||||
Client<--matrix.ac.cdl:"""type": "m.login.sso"""
|
||||
deactivate matrix.ac.cdl
|
||||
# Start SSO flow: displayed in browser for web clients, or via fallback auth in embeddedbrowser for others
|
||||
Client->matrix.ac.cdl:""GET /_matrix/client/r0/login/sso/redirect\n--?redirectUrl=<clienturl>--""
|
||||
activate matrix.ac.cdl
|
||||
matrix.ac.cdl->matrix.ac.cdl:Generate SAML request
|
||||
Client<--matrix.ac.cdl:302 to SSO system
|
||||
deactivate matrix.ac.cdl
|
||||
Client->SAML2 SSO system:""GET /single-sign-on\n--?SAMLRequest=<request>&RelayState=<clienturl>--""
|
||||
activate SAML2 SSO system
|
||||
Client<-->SAML2 SSO system: auth credentials
|
||||
SAML2 SSO system-->Client:auto-submitting HTML form including SAML Response
|
||||
deactivate SAML2 SSO system
|
||||
Client->matrix.ac.cdl:""POST /SAML2\n--SAMLResponse=<response>\nRelayState=<params>
|
||||
activate matrix.ac.cdl
|
||||
matrix.ac.cdl->matrix.ac.cdl:map user to HS
|
||||
Client<--matrix.ac.cdl:auto-submitting HTML form for target HS
|
||||
deactivate matrix.ac.cdl
|
||||
Client->matrix.eng.ac.cdl:""POST /SAML2\n--SAMLResponse=<response>\nRelayState=<clienturl>
|
||||
activate matrix.eng.ac.cdl
|
||||
Client<--matrix.eng.ac.cdl:302 to clienturl with\n""--?loginToken=<token>
|
||||
deactivate matrix.eng.ac.cdl
|
||||
Client->matrix.ac.cdl:""POST /_matrix/client/r0/login\n--{"type": "m.login.token","token": "<token>"}
|
||||
activate matrix.ac.cdl
|
||||
matrix.ac.cdl->matrix.eng.ac.cdl:""POST /_matrix/client/r0/login\n--{"type": "m.login.token", "token": "<token>"}
|
||||
activate matrix.eng.ac.cdl
|
||||
matrix.ac.cdl<--matrix.eng.ac.cdl:""--{"user_id": "@user:eng.ac.cdl", "access_token": "abc123",\n "well_known": {"m.homeserver": "..."}}
|
||||
deactivate matrix.eng.ac.cdl
|
||||
Client<--matrix.ac.cdl:""--{"user_id": "@user:eng.ac.cdl",\n "access_token": "abc123",\n "well-known": {"m.homeserver": "..."}}
|
||||
deactivate matrix.ac.cdl
|
||||
Client<-#0000FF>matrix.eng.ac.cdl: Matrix
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue