@@ -420,7 +420,7 @@ let destroy_db_session ~__context ~self =
420420(* CP-703: ensure that activate sessions are invalidated in a bounded time *)
421421(* in response to external authentication/directory services updates, such as *)
422422(* e.g. group membership changes, or even account disabled *)
423- let revalidate_external_session ~__context ~ session =
423+ let revalidate_external_session ~__context acc session =
424424 Context. with_tracing ~__context __FUNCTION__ @@ fun __context ->
425425 try
426426 (* guard: we only want to revalidate external sessions, where is_local_superuser is false *)
@@ -430,8 +430,7 @@ let revalidate_external_session ~__context ~session =
430430 (Db.Session. get_is_local_superuser ~__context ~self: session
431431 || Xapi_database.Db_backend. is_session_registered (Ref. string_of session)
432432 )
433- then (
434- (* 1. is the external authentication disabled in the pool? *)
433+ then (* 1. is the external authentication disabled in the pool? *)
435434 let master = Helpers. get_master ~__context in
436435 let auth_type = Db.Host. get_external_auth_type ~__context ~self: master in
437436 if auth_type = " " then (
@@ -442,31 +441,49 @@ let revalidate_external_session ~__context ~session =
442441 (trackid session)
443442 in
444443 debug " %s" msg ;
445- destroy_db_session ~__context ~self: session
444+ destroy_db_session ~__context ~self: session ;
445+ acc
446446 ) else
447447 (* otherwise, we try to revalidate it against the external authentication service *)
448448 let session_lifespan = 60.0 *. 30.0 in
449449 (* allowed session lifespan = 30 minutes *)
450450 let random_lifespan = Random. float 60.0 *. 10.0 in
451451
452- (* extra random (up to 10min) lifespan to spread access to external directory *)
453-
454452 (* 2. has the external session expired/does it need revalidation? *)
455453 let session_last_validation_time =
456454 Date. to_unix_time
457455 (Db.Session. get_validation_time ~__context ~self: session)
458456 in
459457 let now = Date. now () in
460- let session_needs_revalidation =
458+ let session_timeout =
461459 Date. to_unix_time now
462460 > session_last_validation_time +. session_lifespan +. random_lifespan
463461 in
464- if session_needs_revalidation then (
462+
463+ (* extra random (up to 10min) lifespan to spread access to external directory *)
464+ let authenticated_user_sid =
465+ Db.Session. get_auth_user_sid ~__context ~self: session
466+ in
467+ let user_validated =
468+ (* acc is [(sid, check_result)] , true for check pass, false for check failed *)
469+ match List. assoc_opt authenticated_user_sid acc with
470+ | None ->
471+ false
472+ | Some v ->
473+ if v = false && session_timeout then (
474+ debug
475+ " Destory session %s as previous check for user %s not pass"
476+ (trackid session) authenticated_user_sid ;
477+ destroy_db_session ~__context ~self: session
478+ ) ;
479+ debug " Skip check session %s as previous check for user %s exists"
480+ (trackid session) authenticated_user_sid ;
481+ true
482+ in
483+
484+ if session_timeout && not user_validated then (
465485 (* if so, then:*)
466486 debug " session %s needs revalidation" (trackid session) ;
467- let authenticated_user_sid =
468- Db.Session. get_auth_user_sid ~__context ~self: session
469- in
470487
471488 (* 2a. revalidate external authentication *)
472489
@@ -480,7 +497,8 @@ let revalidate_external_session ~__context ~session =
480497 %s"
481498 authenticated_user_sid (trackid session) ;
482499 (* we must destroy the session in this case *)
483- destroy_db_session ~__context ~self: session
500+ destroy_db_session ~__context ~self: session ;
501+ (authenticated_user_sid, false ) :: acc
484502 ) else
485503 try
486504 (* if the user is not in the external directory service anymore, this call raises Not_found *)
@@ -517,7 +535,8 @@ let revalidate_external_session ~__context ~session =
517535 in
518536 debug " %s" msg ;
519537 (* we must destroy the session in this case *)
520- destroy_db_session ~__context ~self: session
538+ destroy_db_session ~__context ~self: session ;
539+ (authenticated_user_sid, false ) :: acc
521540 ) else (
522541 (* non-empty intersection: externally-authenticated subject still has login rights in the pool *)
523542
@@ -544,7 +563,9 @@ let revalidate_external_session ~__context ~session =
544563 ~value: subject_in_intersection ;
545564 debug " updated subject for session %s, sid %s "
546565 (trackid session) authenticated_user_sid
547- )
566+ ) ;
567+ debug " end revalidation of session %s " (trackid session) ;
568+ (authenticated_user_sid, true ) :: acc
548569 with Not_found ->
549570 (* subject ref for intersection's sid does not exist in our metadata!!! *)
550571 (* this should never happen, it's an internal metadata inconsistency between steps 2b and 2c *)
@@ -556,7 +577,8 @@ let revalidate_external_session ~__context ~session =
556577 in
557578 debug " %s" msg ;
558579 (* we must destroy the session in this case *)
559- destroy_db_session ~__context ~self: session
580+ destroy_db_session ~__context ~self: session ;
581+ (authenticated_user_sid, false ) :: acc
560582 )
561583 with Auth_signature. Subject_cannot_be_resolved | Not_found ->
562584 (* user was not found in external directory in order to obtain group membership *)
@@ -569,15 +591,18 @@ let revalidate_external_session ~__context ~session =
569591 in
570592 debug " %s" msg ;
571593 (* user is not in the external directory anymore: we must destroy the session in this case *)
572- destroy_db_session ~__context ~self: session
573- ) ;
574- debug " end revalidation of session %s " (trackid session)
575- )
594+ destroy_db_session ~__context ~self: session ;
595+ (authenticated_user_sid, false ) :: acc
596+ ) else
597+ acc
598+ else
599+ acc
576600 with e ->
577601 (* unexpected exception: we absorb it and print out a debug line *)
578602 debug " Unexpected exception while revalidating session %s: %s"
579603 (trackid session)
580- (ExnHelper. string_of_exn e)
604+ (ExnHelper. string_of_exn e) ;
605+ acc
581606
582607(* CP-703: ensure that activate sessions are invalidated in a bounded time *)
583608(* in response to external authentication/directory services updates, such as *)
@@ -587,21 +612,16 @@ let revalidate_all_sessions ~__context =
587612 try
588613 debug " revalidating all external sessions in the local host" ;
589614 (* obtain all sessions in the pool *)
590- let sessions = Db.Session. get_all ~__context in
615+ Db.Session. get_all ~__context
591616 (* filter out those sessions where is_local_superuser or client_certificate is true *)
592617 (* we only want to revalidate the sessions created using the external authentication service *)
593- let external_sessions =
594- List. filter
595- (fun session ->
596- (not (Db.Session. get_is_local_superuser ~__context ~self: session))
597- && not (Db.Session. get_client_certificate ~__context ~self: session)
598- )
599- sessions
600- in
601- (* revalidate each external session *)
602- List. iter
603- (fun session -> revalidate_external_session ~__context ~session )
604- external_sessions
618+ |> List. filter (fun session ->
619+ (not (Db.Session. get_is_local_superuser ~__context ~self: session))
620+ && not (Db.Session. get_client_certificate ~__context ~self: session)
621+ )
622+ |> (* revalidate each external session *)
623+ List. fold_left (revalidate_external_session ~__context) []
624+ |> ignore
605625 with e ->
606626 (* unexpected exception: we absorb it and print out a debug line *)
607627 debug " Unexpected exception while revalidating external sessions: %s"
0 commit comments