@@ -629,7 +629,9 @@ async fn test_device_token_request_ttl(cptestctx: &ControlPlaneTestContext) {
629
629
}
630
630
631
631
#[ nexus_test]
632
- async fn test_admin_logout_deletes_tokens ( cptestctx : & ControlPlaneTestContext ) {
632
+ async fn test_admin_logout_deletes_tokens_and_sessions (
633
+ cptestctx : & ControlPlaneTestContext ,
634
+ ) {
633
635
let testctx = & cptestctx. external_client ;
634
636
635
637
// create a user have a user ID on hand to use in the authn_as
@@ -639,7 +641,7 @@ async fn test_admin_logout_deletes_tokens(cptestctx: &ControlPlaneTestContext) {
639
641
testctx,
640
642
& test_suite_silo,
641
643
& "user1" . parse ( ) . unwrap ( ) ,
642
- test_params:: UserPassword :: LoginDisallowed ,
644
+ test_params:: UserPassword :: Password ( "password1" . to_string ( ) ) ,
643
645
)
644
646
. await ;
645
647
let user2 = create_local_user (
@@ -650,16 +652,22 @@ async fn test_admin_logout_deletes_tokens(cptestctx: &ControlPlaneTestContext) {
650
652
)
651
653
. await ;
652
654
653
- // no tokens for user 1 yet
654
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
655
+ // no tokens or sessions for user 1 yet
656
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
655
657
assert ! ( tokens. is_empty( ) ) ;
658
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
659
+ assert ! ( sessions. is_empty( ) ) ;
656
660
657
- // create a token for user1
661
+ // create a token and session for user1
658
662
get_device_token ( testctx, AuthnMode :: SiloUser ( user1. id ) ) . await ;
663
+ create_session_for_user ( testctx, "test-suite-silo" , "user1" , "password1" )
664
+ . await ;
659
665
660
- // now there is a token for user1
661
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
666
+ // now there is a token and session for user1
667
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
662
668
assert_eq ! ( tokens. len( ) , 1 ) ;
669
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
670
+ assert_eq ! ( sessions. len( ) , 1 ) ;
663
671
664
672
let logout_url = format ! ( "/v1/users/{}/logout" , user1. id) ;
665
673
@@ -674,8 +682,10 @@ async fn test_admin_logout_deletes_tokens(cptestctx: &ControlPlaneTestContext) {
674
682
. await
675
683
. expect ( "User has no perms, can't delete another user's tokens" ) ;
676
684
677
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
685
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
678
686
assert_eq ! ( tokens. len( ) , 1 ) ;
687
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
688
+ assert_eq ! ( sessions. len( ) , 1 ) ;
679
689
680
690
// user 1 can hit the logout endpoint for themselves
681
691
NexusRequest :: new (
@@ -688,15 +698,23 @@ async fn test_admin_logout_deletes_tokens(cptestctx: &ControlPlaneTestContext) {
688
698
. await
689
699
. expect ( "User 1 should be able to delete their own tokens" ) ;
690
700
691
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
701
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
692
702
assert ! ( tokens. is_empty( ) ) ;
703
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
704
+ assert ! ( sessions. is_empty( ) ) ;
693
705
694
- // create another couple of tokens for user1
706
+ // create another couple of tokens and sessions for user1
695
707
get_device_token ( testctx, AuthnMode :: SiloUser ( user1. id ) ) . await ;
696
708
get_device_token ( testctx, AuthnMode :: SiloUser ( user1. id ) ) . await ;
709
+ create_session_for_user ( testctx, "test-suite-silo" , "user1" , "password1" )
710
+ . await ;
711
+ create_session_for_user ( testctx, "test-suite-silo" , "user1" , "password1" )
712
+ . await ;
697
713
698
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
714
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
699
715
assert_eq ! ( tokens. len( ) , 2 ) ;
716
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
717
+ assert_eq ! ( sessions. len( ) , 2 ) ;
700
718
701
719
// make user 2 fleet admin to show that fleet admin does not inherit
702
720
// the appropriate role due to being fleet admin alone
@@ -719,8 +737,10 @@ async fn test_admin_logout_deletes_tokens(cptestctx: &ControlPlaneTestContext) {
719
737
. await
720
738
. expect ( "Fleet admin is not sufficient to delete another user's tokens" ) ;
721
739
722
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
740
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
723
741
assert_eq ! ( tokens. len( ) , 2 ) ;
742
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
743
+ assert_eq ! ( sessions. len( ) , 2 ) ;
724
744
725
745
// make user 2 a silo admin so they can delete user 1's tokens
726
746
grant_iam (
@@ -743,8 +763,10 @@ async fn test_admin_logout_deletes_tokens(cptestctx: &ControlPlaneTestContext) {
743
763
. expect ( "Silo admin should be able to delete user 1's tokens" ) ;
744
764
745
765
// they're gone!
746
- let tokens = get_user_tokens ( testctx, user1. id ) . await ;
766
+ let tokens = list_user_tokens ( testctx, user1. id ) . await ;
747
767
assert ! ( tokens. is_empty( ) ) ;
768
+ let sessions = list_user_sessions ( testctx, user1. id ) . await ;
769
+ assert ! ( sessions. is_empty( ) ) ;
748
770
}
749
771
750
772
async fn get_tokens_priv (
@@ -757,7 +779,7 @@ async fn get_tokens_priv(
757
779
. items
758
780
}
759
781
760
- async fn get_user_tokens (
782
+ async fn list_user_tokens (
761
783
testctx : & ClientTestContext ,
762
784
user_id : Uuid ,
763
785
) -> Vec < views:: DeviceAccessToken > {
@@ -768,6 +790,38 @@ async fn get_user_tokens(
768
790
. items
769
791
}
770
792
793
+ async fn list_user_sessions (
794
+ testctx : & ClientTestContext ,
795
+ user_id : Uuid ,
796
+ ) -> Vec < views:: ConsoleSession > {
797
+ let url = format ! ( "/v1/users/{}/sessions" , user_id) ;
798
+ NexusRequest :: object_get ( testctx, & url)
799
+ . authn_as ( AuthnMode :: SiloUser ( user_id) )
800
+ . execute_and_parse_unwrap :: < ResultsPage < views:: ConsoleSession > > ( )
801
+ . await
802
+ . items
803
+ }
804
+
805
+ async fn create_session_for_user (
806
+ testctx : & ClientTestContext ,
807
+ silo_name : & str ,
808
+ username : & str ,
809
+ password : & str ,
810
+ ) {
811
+ let url = format ! ( "/v1/login/{}/local" , silo_name) ;
812
+ let credentials = test_params:: UsernamePasswordCredentials {
813
+ username : username. parse ( ) . unwrap ( ) ,
814
+ password : password. to_string ( ) ,
815
+ } ;
816
+ let _login = RequestBuilder :: new ( & testctx, Method :: POST , & url)
817
+ . body ( Some ( & credentials) )
818
+ . expect_status ( Some ( StatusCode :: NO_CONTENT ) )
819
+ . execute ( )
820
+ . await
821
+ . expect ( "failed to log in" ) ;
822
+ // We don't need to extract the token, just creating the session is enough
823
+ }
824
+
771
825
async fn get_tokens_unpriv (
772
826
testctx : & ClientTestContext ,
773
827
) -> Vec < views:: DeviceAccessToken > {
0 commit comments