@@ -386,10 +386,13 @@ async fn user_password_login(
386
386
username : String ,
387
387
password : String ,
388
388
) -> Result < ( CompatSession , User ) , RouteError > {
389
+ // Try getting the localpart out of the MXID
390
+ let username = homeserver. localpart ( & username) . unwrap_or ( & username) ;
391
+
389
392
// Find the user
390
393
let user = repo
391
394
. user ( )
392
- . find_by_username ( & username)
395
+ . find_by_username ( username)
393
396
. await ?
394
397
. filter ( mas_data_model:: User :: is_valid)
395
398
. ok_or ( RouteError :: UserNotFound ) ?;
@@ -539,52 +542,43 @@ mod tests {
539
542
assert_eq ! ( body[ "errcode" ] , "M_UNRECOGNIZED" ) ;
540
543
}
541
544
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 ( ) ;
551
547
let mut repo = state. repository ( ) . await . unwrap ( ) ;
552
548
553
549
let user = repo
554
550
. 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 ( ) ) )
556
557
. await
557
558
. unwrap ( ) ;
558
559
560
+ repo. user_password ( )
561
+ . add ( & mut rng, & state. clock , & user, version, hash, None )
562
+ . await
563
+ . unwrap ( ) ;
559
564
let mxid = state. homeserver_connection . mxid ( & user. username ) ;
560
565
state
561
566
. homeserver_connection
562
567
. provision_user ( & ProvisionRequest :: new ( mxid, & user. sub ) )
563
568
. await
564
569
. unwrap ( ) ;
565
570
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
+ }
574
573
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 ( ) ;
586
580
587
- repo . save ( ) . await . unwrap ( ) ;
581
+ user_with_password ( & state , "alice" , "password" ) . await ;
588
582
589
583
// Now let's try to login with the password, without asking for a refresh token.
590
584
let request = Request :: post ( "/_matrix/client/v3/login" ) . json ( serde_json:: json!( {
@@ -662,6 +656,50 @@ mod tests {
662
656
assert_eq ! ( body, old_body) ;
663
657
}
664
658
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
+
665
703
/// Test that password logins are rate limited.
666
704
#[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
667
705
async fn test_password_login_rate_limit ( pool : PgPool ) {
0 commit comments