Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 32 additions & 55 deletions crates/cli/src/commands/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::process::ExitCode;
use anyhow::Context;
use clap::Parser;
use figment::Figment;
use hyper::StatusCode;
use mas_config::{ConfigurationSection, RootConfig};
use mas_http::RequestBuilderExt;
use tracing::{error, info, info_span, warn};
Expand Down Expand Up @@ -43,7 +44,7 @@ impl Options {
r"The homeserver host in the config (`matrix.homeserver`) is not a valid domain.
See {DOCS_BASE}/setup/homeserver.html",
)?;
let admin_token = config.matrix.secret().await?;
let secret = config.matrix.secret().await?;
let hs_api = config.matrix.endpoint;

if !issuer.starts_with("https://") {
Expand Down Expand Up @@ -99,17 +100,14 @@ Make sure that the MAS config contains:

http:
public_base: {issuer:?}
# Or, if the issuer is different from the public base:
issuer: {issuer:?}

And in the Synapse config:

experimental_features:
msc3861:
enabled: true
# This must exactly match:
issuer: {issuer:?}
# ...
matrix_authentication_service:
enabled: true
# This must point to where MAS is reachable by Synapse
endpoint: {issuer:?}
# ...

See {DOCS_BASE}/setup/homeserver.html
"#
Expand All @@ -128,11 +126,10 @@ Check the well-known document at "{well_known_uri}"
Check the well-known document at "{well_known_uri}"
Make sure Synapse has delegated auth enabled:

experimental_features:
msc3861:
enabled: true
issuer: {issuer:?}
# ...
matrix_authentication_service:
enabled: true
endpoint: {issuer:?}
# ...

If it is not Synapse handling the well-known document, update it to include the following:

Expand Down Expand Up @@ -283,70 +280,50 @@ Error details: {e}
),
}

// Try to reach the admin API on an unauthorized endpoint
let server_version = hs_api.join("/_synapse/admin/v1/server_version")?;
let result = http_client.get(server_version.as_str()).send_traced().await;
match result {
Ok(response) => {
let status = response.status();
if status.is_success() {
info!(r#"✅ The Synapse admin API is reachable at "{server_version}"."#);
} else {
error!(
r#"❌ A Synapse admin API endpoint at "{server_version}" replied with {status}.
Make sure MAS can reach the admin API, and that the homeserver is running.
"#
);
}
}
Err(e) => error!(
r#"❌ Can't reach the Synapse admin API at "{server_version}".
Make sure MAS can reach the admin API, and that the homeserver is running.

Comment on lines -286 to -305
Copy link
Member

Choose a reason for hiding this comment

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

Why is this no longer useful? Doesn't MAS still need to use Synapse's Admin API in several cases?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's using a dedicated API now, and doesn't have full admin access anymore

Copy link
Member Author

Choose a reason for hiding this comment

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

This is also now just testing for the dedicated MAS API, which should cover both the 'it's unreachable' and the 'it's the wrong secret' cases

Error details: {e}
"#
),
}

// Try to reach an authenticated admin API endpoint
let background_updates = hs_api.join("/_synapse/admin/v1/background_updates/status")?;
// Try to reach an authenticated MAS API endpoint
let mas_api = hs_api.join("/_synapse/mas/is_localpart_available")?;
let result = http_client
.get(background_updates.as_str())
.bearer_auth(&admin_token)
.get(mas_api.as_str())
.bearer_auth(&secret)
.send_traced()
.await;
match result {
Ok(response) => {
let status = response.status();
if status.is_success() {
// We intentionally omit the required 'localpart' parameter
// in this request. If authentication is successful, Synapse
// returns a 400 Bad Request because of the missing
// parameter. If authentication fails, Synapse will return a
// 403 Forbidden. If the MAS integration isn't enabled,
// Synapse will return a 404 Not found.
if status == StatusCode::BAD_REQUEST {
info!(
r#"✅ The Synapse admin API is reachable with authentication at "{background_updates}"."#
r#"✅ The Synapse MAS API is reachable with authentication at "{mas_api}"."#
);
} else {
error!(
r#"❌ A Synapse admin API endpoint at "{background_updates}" replied with {status}.
r#"❌ A Synapse MAS API endpoint at "{mas_api}" replied with {status}.
Make sure the homeserver is running, and that the MAS config has the correct `matrix.secret`.
It should match the `admin_token` set in the Synapse config.
It should match the `secret` set in the Synapse config.

experimental_features:
msc3861:
enabled: true
issuer: {issuer}
# This must exactly match the secret in the MAS config:
admin_token: {admin_token:?}
matrix_authentication_service:
enabled: true
endpoint: {issuer:?}
# This must exactly match the secret in the MAS config:
secret: {secret:?}

And in the MAS config:

matrix:
homeserver: "{matrix_domain}"
endpoint: "{hs_api}"
secret: {admin_token:?}
secret: {secret:?}
"#
);
}
}
Err(e) => error!(
r#"❌ Can't reach the Synapse admin API at "{background_updates}".
r#"❌ Can't reach the Synapse MAS API at "{mas_api}".
Make sure the homeserver is running, and that the MAS config has the correct `matrix.secret`.

Error details: {e}
Expand Down
82 changes: 34 additions & 48 deletions docs/setup/homeserver.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,46 @@
# Homeserver configuration

The `matrix-authentication-service` is designed to be run alongside a Matrix homeserver.
It currently only supports [Synapse](https://github.com/element-hq/synapse) through the experimental OAuth delegation feature.
It currently only supports [Synapse](https://github.com/element-hq/synapse) version 1.136.0 or later.
The authentication service needs to be able to call the Synapse admin API to provision users through a shared secret, and Synapse needs to be able to call the service to verify access tokens using the OAuth 2.0 token introspection endpoint.

## Provision a client for the Homeserver to use

In the [`clients`](../reference/configuration.md#clients) section of the configuration file, add a new client with the following properties:

- `client_id`: a unique identifier for the client. It must be a valid [ULID](https://github.com/ulid/spec), and it happens that `0000000000000000000SYNAPSE` is a valid ULID.
- `client_auth_method`: set to `client_secret_basic`. Other methods are possible, but this is the easiest to set up.
- `client_secret`: a shared secret used for the homeserver to authenticate

```yaml
clients:
- client_id: 0000000000000000000SYNAPSE
client_auth_method: client_secret_basic
client_secret: "SomeRandomSecret"
```

**Don't forget to sync the configuration file** with the database after adding the client, using the [`config sync`](../reference/cli/config.md#config-sync---prune---dry-run) command.

## Configure the connection to the homeserver

In the [`matrix`](../reference/configuration.md#matrix) section of the configuration file, add the following properties:

- `kind`: the type of homeserver to connect to, currently only `synapse` is supported
- `homeserver`: corresponds to the `server_name` in the Synapse configuration file
- `secret`: a shared secret the service will use to call the homeserver admin API
- `secret`: a shared secret the service will use to call the homeserver MAS API
- `endpoint`: the URL to which the homeserver is accessible from the service

```yaml
matrix:
homeserver: localhost:8008
secret: "AnotherRandomSecret"
kind: synapse
homeserver: example.com
endpoint: "http://localhost:8008"
secret: "AVeryRandomSecretPleaseUseSomethingSecure"
# Alternatively, using a file:
#secret_path: /path/to/secret.txt
```

## Configure the homeserver to delegate authentication to the service

Set up the delegated authentication feature in the Synapse configuration in the `experimental_features` section:
Set up the delegated authentication feature **in the Synapse configuration** in the `matrix_authentication_service` section:

```yaml
experimental_features:
msc3861:
enabled: true

# Synapse will call `{issuer}/.well-known/openid-configuration` to get the OIDC configuration
issuer: http://localhost:8080/

# Matches the `client_id` in the auth service config
client_id: 0000000000000000000SYNAPSE
# Matches the `client_auth_method` in the auth service config
client_auth_method: client_secret_basic
# Matches the `client_secret` in the auth service config
client_secret: "SomeRandomSecret"

# Matches the `matrix.secret` in the auth service config
admin_token: "AnotherRandomSecret"

# URL to advertise to clients where users can self-manage their account
# Defaults to the URL advertised by MAS, e.g. `https://{public_mas_domain}/account/`
#account_management_url: "http://localhost:8080/account/"

# URL which Synapse will use to introspect access tokens
# Defaults to the URL advertised by MAS, e.g. `https://{public_mas_domain}/oauth2/introspect`
# This is useful to override if Synapse has a way to call the auth service's
# introspection endpoint directly, skipping intermediate reverse proxies
#introspection_endpoint: "http://localhost:8080/oauth2/introspect"
matrix_authentication_service:
enabled: true
endpoint: http://localhost:8080/
secret: "AVeryRandomSecretPleaseUseSomethingSecure"
# Alternatively, using a file:
#secret_file: /path/to/secret.txt
```

The `endpoint` property should be set to the URL of the authentication service.
This can be an internal URL, to avoid unnecessary round-trips.

The `secret` property must match in both the Synapse configuration and the Matrix Authentication Service configuration.

## Set up the compatibility layer

The service exposes a compatibility layer to allow legacy clients to authenticate using the service.
Expand All @@ -81,3 +53,17 @@ The following Matrix Client-Server API endpoints need to be handled by the authe
- [`/_matrix/client/*/refresh`](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3refresh)

See the [reverse proxy configuration](./reverse-proxy.md) guide for more information.


## Migrating from the experimental MSC3861 feature

If you are migrating from the experimental MSC3861 feature in Synapse, you will need to migrate the `experimental_features.msc3861` section of the Synapse configuration to the `matrix_authentication_service` section.

To do so, you need to:

- Remove the `experimental_features.msc3861` section from the Synapse configuration
- Add the `matrix_authentication_service` section to the Synapse configuration with:
- `enabled: true`
- `endpoint` set to the URL of the authentication service
- `secret` set to the same secret as the `admin_token` that was set in the `msc3861` section
- Optionally, remove the client provisioned for Synapse in the `clients` section of the MAS configuration
Loading