Support the deprecated 'user' field on the compat /login endpoint

This commit is contained in:
Quentin Gliech
2025-02-20 17:50:12 +01:00
parent 84766e3c30
commit fa0e2f4832
+65 -5
View File
@@ -4,7 +4,11 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
use axum::{extract::State, response::IntoResponse, Json};
use axum::{
extract::{rejection::JsonRejection, State},
response::IntoResponse,
Json,
};
use axum_extra::typed_header::TypedHeader;
use chrono::Duration;
use hyper::StatusCode;
@@ -104,7 +108,9 @@ pub struct RequestBody {
pub enum Credentials {
#[serde(rename = "m.login.password")]
Password {
identifier: Identifier,
identifier: Option<Identifier>,
// This property has been deprecated for a while, but some tools still use it.
user: Option<String>,
password: String,
},
@@ -145,6 +151,12 @@ pub enum RouteError {
#[error("unsupported login method")]
Unsupported,
#[error("unsupported identifier type")]
UnsupportedIdentifier,
#[error("missing property 'identifier'")]
MissingIdentifier,
#[error("user not found")]
UserNotFound,
@@ -166,6 +178,9 @@ pub enum RouteError {
#[error("invalid login token")]
InvalidLoginToken,
#[error(transparent)]
InvalidJsonBody(#[from] JsonRejection),
#[error("failed to provision device")]
ProvisionDeviceFailed(#[source] anyhow::Error),
}
@@ -188,11 +203,41 @@ impl IntoResponse for RouteError {
error: "Too many login attempts",
status: StatusCode::TOO_MANY_REQUESTS,
},
Self::InvalidJsonBody(JsonRejection::MissingJsonContentType(_)) => MatrixError {
errcode: "M_NOT_JSON",
error: "Invalid Content-Type header: expected application/json",
status: StatusCode::BAD_REQUEST,
},
Self::InvalidJsonBody(JsonRejection::JsonSyntaxError(_)) => MatrixError {
errcode: "M_NOT_JSON",
error: "Body is not a valid JSON document",
status: StatusCode::BAD_REQUEST,
},
Self::InvalidJsonBody(JsonRejection::JsonDataError(_)) => MatrixError {
errcode: "M_BAD_JSON",
error: "JSON fields are not valid",
status: StatusCode::BAD_REQUEST,
},
Self::InvalidJsonBody(_) => MatrixError {
errcode: "M_UNKNOWN",
error: "Unknown error while parsing JSON body",
status: StatusCode::BAD_REQUEST,
},
Self::Unsupported => MatrixError {
errcode: "M_UNRECOGNIZED",
errcode: "M_UNKNOWN",
error: "Invalid login type",
status: StatusCode::BAD_REQUEST,
},
Self::UnsupportedIdentifier => MatrixError {
errcode: "M_UNKNOWN",
error: "Unsupported login identifier",
status: StatusCode::BAD_REQUEST,
},
Self::MissingIdentifier => MatrixError {
errcode: "M_BAD_JSON",
error: "Missing property 'identifier",
status: StatusCode::BAD_REQUEST,
},
Self::UserNotFound | Self::NoPassword | Self::PasswordVerificationFailed(_) => {
MatrixError {
errcode: "M_FORBIDDEN",
@@ -228,17 +273,32 @@ pub(crate) async fn post(
State(limiter): State<Limiter>,
requester: RequesterFingerprint,
user_agent: Option<TypedHeader<headers::UserAgent>>,
Json(input): Json<RequestBody>,
input: Result<Json<RequestBody>, JsonRejection>,
) -> Result<impl IntoResponse, RouteError> {
let Json(input) = input?;
let user_agent = user_agent.map(|ua| UserAgent::parse(ua.as_str().to_owned()));
let (mut session, user) = match (password_manager.is_enabled(), input.credentials) {
(
true,
Credentials::Password {
identifier: Identifier::User { user },
identifier,
user,
password,
},
) => {
// This is to support both the (very) old and deprecated 'user' property, with
// the same behavior as Synapse: it takes precendence over the 'identifier' if
// provided
let user = match (identifier, user) {
(Some(Identifier::User { user }), None) | (_, Some(user)) => user,
(Some(Identifier::Unsupported), None) => {
return Err(RouteError::UnsupportedIdentifier);
}
(None, None) => {
return Err(RouteError::MissingIdentifier);
}
};
user_password_login(
&mut rng,
&clock,