@@ -398,19 +398,24 @@ let is_subject_suspended ~__context ~cache subject_identifier =
398
398
debug " Subject identifier %s is suspended" subject_identifier ;
399
399
(is_suspended, subject_name)
400
400
401
+ let reusable_pool_session = Atomic. make Ref. null
402
+
401
403
let destroy_db_session ~__context ~self =
402
404
Context. with_tracing ~__context __FUNCTION__ @@ fun __context ->
403
- Xapi_event. on_session_deleted self ;
404
- (* unregister from the event system *)
405
- (* This info line is important for tracking, auditability and client accountability purposes on XenServer *)
406
- (* Never print the session id nor uuid: they are secret values that should be known only to the user that *)
407
- (* logged in. Instead, we print a non-invertible hash as the tracking id for the session id *)
408
- (* see also task creation in context.ml *)
409
- (* CP-982: create tracking id in log files to link username to actions *)
410
- info " Session.destroy %s" (trackid self) ;
411
- Rbac_audit. session_destroy ~__context ~session_id: self ;
412
- (try Db.Session. destroy ~__context ~self with _ -> () ) ;
413
- Rbac. destroy_session_permissions_tbl ~session_id: self
405
+ if self <> Atomic. get reusable_pool_session then (
406
+ Xapi_event. on_session_deleted self ;
407
+ (* unregister from the event system *)
408
+ (* This info line is important for tracking, auditability and client accountability purposes on XenServer *)
409
+ (* Never print the session id nor uuid: they are secret values that should be known only to the user that *)
410
+ (* logged in. Instead, we print a non-invertible hash as the tracking id for the session id *)
411
+ (* see also task creation in context.ml *)
412
+ (* CP-982: create tracking id in log files to link username to actions *)
413
+ info " Session.destroy %s" (trackid self) ;
414
+ Rbac_audit. session_destroy ~__context ~session_id: self ;
415
+ (try Db.Session. destroy ~__context ~self with _ -> () ) ;
416
+ Rbac. destroy_session_permissions_tbl ~session_id: self
417
+ ) else
418
+ info " Skipping Session.destroy for reusable pool session %s" (trackid self)
414
419
415
420
(* CP-703: ensure that activate sessions are invalidated in a bounded time *)
416
421
(* in response to external authentication/directory services updates, such as *)
@@ -610,8 +615,8 @@ let revalidate_all_sessions ~__context =
610
615
debug " Unexpected exception while revalidating external sessions: %s"
611
616
(ExnHelper. string_of_exn e)
612
617
613
- let login_no_password_common ~__context ~uname ~originator ~host ~ pool
614
- ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name
618
+ let login_no_password_common_create_session ~__context ~uname ~originator ~host
619
+ ~pool ~ is_local_superuser ~subject ~auth_user_sid ~auth_user_name
615
620
~rbac_permissions ~db_ref ~client_certificate =
616
621
Context. with_tracing ~originator ~__context __FUNCTION__ @@ fun __context ->
617
622
let create_session () =
@@ -661,6 +666,59 @@ let login_no_password_common ~__context ~uname ~originator ~host ~pool
661
666
ignore (Client.Pool. get_all ~rpc ~session_id ) ;
662
667
session_id
663
668
669
+ let login_no_password_common ~__context ~uname ~originator ~host ~pool
670
+ ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name
671
+ ~rbac_permissions ~db_ref ~client_certificate =
672
+ Context. with_tracing ~originator ~__context __FUNCTION__ @@ fun __context ->
673
+ let is_valid_session session_id =
674
+ match (session_id, ! Xapi_globs. validate_reusable_pool_session) with
675
+ | session , _ when session = Ref. null ->
676
+ false
677
+ | _ , false ->
678
+ true
679
+ | session_id , true -> (
680
+ try
681
+ (* Call an API function to check the session is still valid *)
682
+ let rpc = Helpers. make_rpc ~__context in
683
+ ignore (Client.Pool. get_all ~rpc ~session_id ) ;
684
+ true
685
+ with Api_errors. Server_error (err , _ ) ->
686
+ debug " %s: Invalid session: %s" __FUNCTION__ err ;
687
+ false
688
+ )
689
+ in
690
+ let create_session () =
691
+ login_no_password_common_create_session ~__context ~uname ~originator ~host
692
+ ~pool ~is_local_superuser ~subject ~auth_user_sid ~auth_user_name
693
+ ~rbac_permissions ~db_ref ~client_certificate
694
+ in
695
+ let rec get_session () =
696
+ let session = Atomic. get reusable_pool_session in
697
+ if is_valid_session session then (
698
+ (* Check if the session changed during validation.
699
+ Use our version regardless to avoid being stuck in a loop of session creation *)
700
+ if Atomic. get reusable_pool_session <> session then
701
+ debug " reusable_pool_session has changed, using the original anyway" ;
702
+ session
703
+ ) else
704
+ let new_session = create_session () in
705
+ if Atomic. compare_and_set reusable_pool_session session new_session then
706
+ new_session
707
+ else (
708
+ (* someone else raced with us and created a session, destroy ours and attempt to use theirs *)
709
+ destroy_db_session ~__context ~self: new_session ;
710
+ (get_session [@ tailcall]) ()
711
+ )
712
+ in
713
+ if
714
+ (originator, pool, is_local_superuser, uname)
715
+ = (xapi_internal_originator, true , true , None )
716
+ && ! Xapi_globs. reuse_pool_sessions
717
+ then
718
+ get_session ()
719
+ else
720
+ create_session ()
721
+
664
722
(* XXX: only used internally by the code which grants the guest access to the API.
665
723
Needs to be protected by a proper access control system *)
666
724
let login_no_password ~__context ~uname ~host ~pool ~is_local_superuser ~subject
0 commit comments