3737use Glpi \Application \View \TemplateRenderer ;
3838use Glpi \Exception \AuthenticationFailedException ;
3939use Glpi \Exception \Http \AccessDeniedHttpException ;
40+ use Glpi \Exception \Http \HttpException ;
4041use Glpi \Exception \SessionExpiredException ;
4142use Glpi \Http \RedirectResponse ;
4243use Session ;
@@ -62,12 +63,6 @@ public function onKernelException(ExceptionEvent $event): void
6263 }
6364
6465 $ request = $ event ->getRequest ();
65-
66- if ($ request ->isXmlHttpRequest () || $ request ->getPreferredFormat () !== 'html ' ) {
67- // Do not redirect AJAX requests nor requests that expect the response to be something else than HTML.
68- return ;
69- }
70-
7166 $ throwable = $ event ->getThrowable ();
7267
7368 $ response = null ;
@@ -79,18 +74,37 @@ public function onKernelException(ExceptionEvent $event): void
7974 ->getBoolean ('_redirected_from_profile_selector ' )
8075 ;
8176
77+ // Handle SessionExpiredException BEFORE checking if request is AJAX
78+ // This ensures that expired sessions return proper HTTP 401 response for AJAX requests
8279 if ($ throwable instanceof SessionExpiredException) {
8380 Session::destroy (); // destroy the session to prevent pesistence of unexpected data
8481
85- $ response = new RedirectResponse (
86- sprintf (
87- '%s/?redirect=%s&error=3 ' ,
88- $ request ->getBasePath (),
89- \rawurlencode ($ request ->getPathInfo () . '? ' . $ request ->getQueryString ())
90- )
91- );
92- } elseif (
93- $ throwable instanceof AccessDeniedHttpException
82+ if ($ request ->isXmlHttpRequest () || $ request ->getPreferredFormat () !== 'html ' ) {
83+ // For AJAX/JSON requests, convert the error into a HttpException
84+ $ http_exception = new HttpException (401 , 'Session expired. ' );
85+ $ http_exception ->setMessageToDisplay (__ ('Your session has expired. Please log in again. ' ));
86+ throw $ http_exception ;
87+ } else {
88+ // For HTML requests, redirect to login page (existing behavior)
89+ $ response = new RedirectResponse (
90+ sprintf (
91+ '%s/?redirect=%s&error=3 ' ,
92+ $ request ->getBasePath (),
93+ \rawurlencode ($ request ->getPathInfo () . '? ' . $ request ->getQueryString ())
94+ )
95+ );
96+ }
97+ }
98+
99+ // Skip AJAX requests for OTHER exceptions (not SessionExpiredException)
100+ if ($ response === null && ($ request ->isXmlHttpRequest () || $ request ->getPreferredFormat () !== 'html ' )) {
101+ // Do not redirect AJAX requests nor requests that expect the response to be something else than HTML.
102+ return ;
103+ }
104+
105+ if (
106+ $ response === null
107+ && $ throwable instanceof AccessDeniedHttpException
94108 && $ redirect_to_home_on_error
95109 ) {
96110 $ request = $ event ->getRequest ();
@@ -100,7 +114,9 @@ public function onKernelException(ExceptionEvent $event): void
100114 $ request ->getBasePath ()
101115 )
102116 );
103- } elseif ($ throwable instanceof AuthenticationFailedException) {
117+ }
118+
119+ if ($ response === null && $ throwable instanceof AuthenticationFailedException) {
104120 $ login_url = sprintf (
105121 '%s/front/logout.php?noAUTO=1 ' ,
106122 $ request ->getBasePath ()
0 commit comments