@@ -168,14 +168,19 @@ pub(crate) async fn post(
168
168
return Ok ( ( cookie_jar, Html ( content) ) . into_response ( ) ) ;
169
169
}
170
170
171
+ // Extract the localpart of the MXID, fallback to the bare username
172
+ let username = homeserver
173
+ . localpart ( & form. username )
174
+ . unwrap_or ( & form. username ) ;
175
+
171
176
match login (
172
177
password_manager,
173
178
& mut repo,
174
179
rng,
175
180
& clock,
176
181
limiter,
177
182
requester,
178
- & form . username ,
183
+ username,
179
184
& form. password ,
180
185
user_agent,
181
186
)
@@ -479,30 +484,34 @@ mod test {
479
484
. contains( & escape_html( & second_provider_login. path_and_query( ) ) ) ) ;
480
485
}
481
486
482
- #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
483
- async fn test_password_login ( pool : PgPool ) {
484
- setup ( ) ;
485
- let state = TestState :: from_pool ( pool) . await . unwrap ( ) ;
487
+ async fn user_with_password ( state : & TestState , username : & str , password : & str ) {
486
488
let mut rng = state. rng ( ) ;
487
- let cookies = CookieHelper :: new ( ) ;
488
-
489
- // Provision a user with a password
490
489
let mut repo = state. repository ( ) . await . unwrap ( ) ;
491
490
let user = repo
492
491
. user ( )
493
- . add ( & mut rng, & state. clock , "john" . to_owned ( ) )
492
+ . add ( & mut rng, & state. clock , username . to_owned ( ) )
494
493
. await
495
494
. unwrap ( ) ;
496
495
let ( version, hash) = state
497
496
. password_manager
498
- . hash ( & mut rng, Zeroizing :: new ( "hunter2" . as_bytes ( ) . to_vec ( ) ) )
497
+ . hash ( & mut rng, Zeroizing :: new ( password . as_bytes ( ) . to_vec ( ) ) )
499
498
. await
500
499
. unwrap ( ) ;
501
500
repo. user_password ( )
502
501
. add ( & mut rng, & state. clock , & user, version, hash, None )
503
502
. await
504
503
. unwrap ( ) ;
505
504
repo. save ( ) . await . unwrap ( ) ;
505
+ }
506
+
507
+ #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
508
+ async fn test_password_login ( pool : PgPool ) {
509
+ setup ( ) ;
510
+ let state = TestState :: from_pool ( pool) . await . unwrap ( ) ;
511
+ let cookies = CookieHelper :: new ( ) ;
512
+
513
+ // Provision a user with a password
514
+ user_with_password ( & state, "john" , "hunter2" ) . await ;
506
515
507
516
// Render the login page to get a CSRF token
508
517
let request = Request :: get ( "/login" ) . empty ( ) ;
@@ -542,6 +551,93 @@ mod test {
542
551
assert ! ( response. body( ) . contains( "john" ) ) ;
543
552
}
544
553
554
+ #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
555
+ async fn test_password_login_with_mxid ( pool : PgPool ) {
556
+ setup ( ) ;
557
+ let state = TestState :: from_pool ( pool) . await . unwrap ( ) ;
558
+ let cookies = CookieHelper :: new ( ) ;
559
+
560
+ // Provision a user with a password
561
+ user_with_password ( & state, "john" , "hunter2" ) . await ;
562
+
563
+ // Render the login page to get a CSRF token
564
+ let request = Request :: get ( "/login" ) . empty ( ) ;
565
+ let request = cookies. with_cookies ( request) ;
566
+ let response = state. request ( request) . await ;
567
+ cookies. save_cookies ( & response) ;
568
+ response. assert_status ( StatusCode :: OK ) ;
569
+ response. assert_header_value ( CONTENT_TYPE , "text/html; charset=utf-8" ) ;
570
+ // Extract the CSRF token from the response body
571
+ let csrf_token = response
572
+ . body ( )
573
+ . split ( "name=\" csrf\" value=\" " )
574
+ . nth ( 1 )
575
+ . unwrap ( )
576
+ . split ( '\"' )
577
+ . next ( )
578
+ . unwrap ( ) ;
579
+
580
+ // Submit the login form
581
+ let request = Request :: post ( "/login" ) . form ( serde_json:: json!( {
582
+ "csrf" : csrf_token,
583
+ "username" : "@john:example.com" ,
584
+ "password" : "hunter2" ,
585
+ } ) ) ;
586
+ let request = cookies. with_cookies ( request) ;
587
+ let response = state. request ( request) . await ;
588
+ cookies. save_cookies ( & response) ;
589
+ response. assert_status ( StatusCode :: SEE_OTHER ) ;
590
+
591
+ // Now if we get to the home page, we should see the user's username
592
+ let request = Request :: get ( "/" ) . empty ( ) ;
593
+ let request = cookies. with_cookies ( request) ;
594
+ let response = state. request ( request) . await ;
595
+ cookies. save_cookies ( & response) ;
596
+ response. assert_status ( StatusCode :: OK ) ;
597
+ response. assert_header_value ( CONTENT_TYPE , "text/html; charset=utf-8" ) ;
598
+ assert ! ( response. body( ) . contains( "john" ) ) ;
599
+ }
600
+
601
+ #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
602
+ async fn test_password_login_with_mxid_wrong_server ( pool : PgPool ) {
603
+ setup ( ) ;
604
+ let state = TestState :: from_pool ( pool) . await . unwrap ( ) ;
605
+ let cookies = CookieHelper :: new ( ) ;
606
+
607
+ // Provision a user with a password
608
+ user_with_password ( & state, "john" , "hunter2" ) . await ;
609
+
610
+ // Render the login page to get a CSRF token
611
+ let request = Request :: get ( "/login" ) . empty ( ) ;
612
+ let request = cookies. with_cookies ( request) ;
613
+ let response = state. request ( request) . await ;
614
+ cookies. save_cookies ( & response) ;
615
+ response. assert_status ( StatusCode :: OK ) ;
616
+ response. assert_header_value ( CONTENT_TYPE , "text/html; charset=utf-8" ) ;
617
+ // Extract the CSRF token from the response body
618
+ let csrf_token = response
619
+ . body ( )
620
+ . split ( "name=\" csrf\" value=\" " )
621
+ . nth ( 1 )
622
+ . unwrap ( )
623
+ . split ( '\"' )
624
+ . next ( )
625
+ . unwrap ( ) ;
626
+
627
+ // Submit the login form
628
+ let request = Request :: post ( "/login" ) . form ( serde_json:: json!( {
629
+ "csrf" : csrf_token,
630
+ "username" : "@john:something.corp" ,
631
+ "password" : "hunter2" ,
632
+ } ) ) ;
633
+ let request = cookies. with_cookies ( request) ;
634
+ let response = state. request ( request) . await ;
635
+
636
+ // This shouldn't have worked, we're back on the login page
637
+ response. assert_status ( StatusCode :: OK ) ;
638
+ assert ! ( response. body( ) . contains( "Invalid credentials" ) ) ;
639
+ }
640
+
545
641
#[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
546
642
async fn test_password_login_rate_limit ( pool : PgPool ) {
547
643
setup ( ) ;
0 commit comments