Skip to content

Commit 0096076

Browse files
committed
Allow passing MXIDs in compat password logins
1 parent 463ba2e commit 0096076

File tree

1 file changed

+69
-31
lines changed

1 file changed

+69
-31
lines changed

crates/handlers/src/compat/login.rs

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,13 @@ async fn user_password_login(
386386
username: String,
387387
password: String,
388388
) -> Result<(CompatSession, User), RouteError> {
389+
// Try getting the localpart out of the MXID
390+
let username = homeserver.localpart(&username).unwrap_or(&username);
391+
389392
// Find the user
390393
let user = repo
391394
.user()
392-
.find_by_username(&username)
395+
.find_by_username(username)
393396
.await?
394397
.filter(mas_data_model::User::is_valid)
395398
.ok_or(RouteError::UserNotFound)?;
@@ -539,52 +542,43 @@ mod tests {
539542
assert_eq!(body["errcode"], "M_UNRECOGNIZED");
540543
}
541544

542-
/// Test that a user can login with a password using the Matrix
543-
/// compatibility API.
544-
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
545-
async fn test_user_password_login(pool: PgPool) {
546-
setup();
547-
let state = TestState::from_pool(pool).await.unwrap();
548-
549-
// Let's provision a user and add a password to it. This part is hard to test
550-
// with just HTTP requests, so we'll use the repository directly.
545+
async fn user_with_password(state: &TestState, username: &str, password: &str) {
546+
let mut rng = state.rng();
551547
let mut repo = state.repository().await.unwrap();
552548

553549
let user = repo
554550
.user()
555-
.add(&mut state.rng(), &state.clock, "alice".to_owned())
551+
.add(&mut rng, &state.clock, username.to_owned())
552+
.await
553+
.unwrap();
554+
let (version, hash) = state
555+
.password_manager
556+
.hash(&mut rng, Zeroizing::new(password.as_bytes().to_vec()))
556557
.await
557558
.unwrap();
558559

560+
repo.user_password()
561+
.add(&mut rng, &state.clock, &user, version, hash, None)
562+
.await
563+
.unwrap();
559564
let mxid = state.homeserver_connection.mxid(&user.username);
560565
state
561566
.homeserver_connection
562567
.provision_user(&ProvisionRequest::new(mxid, &user.sub))
563568
.await
564569
.unwrap();
565570

566-
let (version, hashed_password) = state
567-
.password_manager
568-
.hash(
569-
&mut state.rng(),
570-
Zeroizing::new("password".to_owned().into_bytes()),
571-
)
572-
.await
573-
.unwrap();
571+
repo.save().await.unwrap();
572+
}
574573

575-
repo.user_password()
576-
.add(
577-
&mut state.rng(),
578-
&state.clock,
579-
&user,
580-
version,
581-
hashed_password,
582-
None,
583-
)
584-
.await
585-
.unwrap();
574+
/// Test that a user can login with a password using the Matrix
575+
/// compatibility API.
576+
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
577+
async fn test_user_password_login(pool: PgPool) {
578+
setup();
579+
let state = TestState::from_pool(pool).await.unwrap();
586580

587-
repo.save().await.unwrap();
581+
user_with_password(&state, "alice", "password").await;
588582

589583
// Now let's try to login with the password, without asking for a refresh token.
590584
let request = Request::post("/_matrix/client/v3/login").json(serde_json::json!({
@@ -662,6 +656,50 @@ mod tests {
662656
assert_eq!(body, old_body);
663657
}
664658

659+
/// Test that a user can login with a password using the Matrix
660+
/// compatibility API, using a MXID as identifier
661+
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
662+
async fn test_user_password_login_mxid(pool: PgPool) {
663+
setup();
664+
let state = TestState::from_pool(pool).await.unwrap();
665+
666+
user_with_password(&state, "alice", "password").await;
667+
668+
// Login with a full MXID as identifier
669+
let request = Request::post("/_matrix/client/v3/login").json(serde_json::json!({
670+
"type": "m.login.password",
671+
"identifier": {
672+
"type": "m.id.user",
673+
"user": "@alice:example.com",
674+
},
675+
"password": "password",
676+
}));
677+
678+
let response = state.request(request).await;
679+
response.assert_status(StatusCode::OK);
680+
let body: ResponseBody = response.json();
681+
assert!(!body.access_token.is_empty());
682+
assert_eq!(body.device_id.as_ref().unwrap().as_str().len(), 10);
683+
assert_eq!(body.user_id, "@alice:example.com");
684+
assert_eq!(body.refresh_token, None);
685+
assert_eq!(body.expires_in_ms, None);
686+
687+
// With a MXID, but with the wrong server name
688+
let request = Request::post("/_matrix/client/v3/login").json(serde_json::json!({
689+
"type": "m.login.password",
690+
"identifier": {
691+
"type": "m.id.user",
692+
"user": "@alice:something.corp",
693+
},
694+
"password": "password",
695+
}));
696+
697+
let response = state.request(request).await;
698+
response.assert_status(StatusCode::FORBIDDEN);
699+
let body: serde_json::Value = response.json();
700+
assert_eq!(body["errcode"], "M_FORBIDDEN");
701+
}
702+
665703
/// Test that password logins are rate limited.
666704
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
667705
async fn test_password_login_rate_limit(pool: PgPool) {

0 commit comments

Comments
 (0)