Skip to content

Commit 92377bf

Browse files
committed
CA-414418: Perf: save user validate result and apply to sessions
For all sessions created by external/AD users, session revalidate will check whether the users are still acitve, and kick off the session accordingly. However, xapi check the user for every session. The problem here is lots of session are created by only a few users. (for the case of CVAD and ControlUP). This would cause lot of duplicated check for the same user again and again, which is slow and waste lots of resources. To fix the issue, [(user_sid, check_result)] is defined for every round of check. The check result is saved so later check for the session with same user can just be applied. Signed-off-by: Lin Liu <[email protected]>
1 parent b0e2b5b commit 92377bf

File tree

1 file changed

+53
-33
lines changed

1 file changed

+53
-33
lines changed

ocaml/xapi/xapi_session.ml

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)