From fa201bd147619977b04cb77730173cb10aeb64ab Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 28 Jul 2025 23:07:54 +0000 Subject: [PATCH 1/6] Handle OIDC callback for already authenticated users Co-authored-by: contact --- src/webserver/oidc.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index d4e53ef0..c084bad8 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -252,6 +252,30 @@ where } }) } + + fn handle_authenticated_oidc_callback( + &self, + request: ServiceRequest, + ) -> LocalBoxFuture, Error>> { + Box::pin(async move { + log::debug!("Handling OIDC callback for already authenticated user"); + + // Try to get the initial URL from the state cookie + let redirect_url = match get_state_from_cookie(&request) { + Ok(state) => { + log::debug!("Found initial URL in state: {}", state.initial_url); + state.initial_url + } + Err(e) => { + log::debug!("Could not get state from cookie (user might have been redirected from elsewhere): {e}. Redirecting to /"); + "/".to_string() + } + }; + + let response = build_redirect_response(redirect_url); + Ok(request.into_response(response)) + }) + } } impl Service for OidcService @@ -268,6 +292,12 @@ where fn call(&self, request: ServiceRequest) -> Self::Future { log::trace!("Started OIDC middleware request handling"); + // Handle OIDC callback URL even for authenticated users + if request.path() == SQLPAGE_REDIRECT_URI { + log::debug!("The request is the OIDC callback for an authenticated user"); + return self.handle_authenticated_oidc_callback(request); + } + let oidc_client = Arc::clone(&self.oidc_state.client); match get_authenticated_user_info(&oidc_client, &request) { Ok(Some(claims)) => { From c8770768c6465e6c07674aaa76c27cb9286ea28d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 28 Jul 2025 23:13:40 +0000 Subject: [PATCH 2/6] Fix lifetime annotations and remove unnecessary self references Co-authored-by: contact --- src/app_config.rs | 2 +- src/template_helpers.rs | 2 +- src/webserver/oidc.rs | 9 ++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/app_config.rs b/src/app_config.rs index 6b2ef78d..9a1056a3 100644 --- a/src/app_config.rs +++ b/src/app_config.rs @@ -494,7 +494,7 @@ fn create_default_database(configuration_directory: &Path) -> String { } #[cfg(any(test, not(feature = "lambda-web")))] -fn encode_uri(path: &Path) -> std::borrow::Cow { +fn encode_uri(path: &Path) -> std::borrow::Cow<'_, str> { const ASCII_SET: &percent_encoding::AsciiSet = &percent_encoding::NON_ALPHANUMERIC .remove(b'-') .remove(b'_') diff --git a/src/template_helpers.rs b/src/template_helpers.rs index 76bb8f77..719a55e2 100644 --- a/src/template_helpers.rs +++ b/src/template_helpers.rs @@ -704,7 +704,7 @@ mod tests { } } - fn as_args(contents: &Value) -> [PathAndJson; 1] { + fn as_args(contents: &Value) -> [PathAndJson<'_>; 1] { [as_helper_arg(CONTENT_KEY, contents)] } diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index c084bad8..93975b14 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -254,12 +254,11 @@ where } fn handle_authenticated_oidc_callback( - &self, request: ServiceRequest, ) -> LocalBoxFuture, Error>> { Box::pin(async move { log::debug!("Handling OIDC callback for already authenticated user"); - + // Try to get the initial URL from the state cookie let redirect_url = match get_state_from_cookie(&request) { Ok(state) => { @@ -271,7 +270,7 @@ where "/".to_string() } }; - + let response = build_redirect_response(redirect_url); Ok(request.into_response(response)) }) @@ -295,7 +294,7 @@ where // Handle OIDC callback URL even for authenticated users if request.path() == SQLPAGE_REDIRECT_URI { log::debug!("The request is the OIDC callback for an authenticated user"); - return self.handle_authenticated_oidc_callback(request); + return Self::handle_authenticated_oidc_callback(request); } let oidc_client = Arc::clone(&self.oidc_state.client); @@ -680,7 +679,7 @@ impl OidcLoginState { } } -fn create_state_cookie(request: &ServiceRequest, auth_url: AuthUrlParams) -> Cookie { +fn create_state_cookie(request: &ServiceRequest, auth_url: AuthUrlParams) -> Cookie<'_> { let state = OidcLoginState::new(request, auth_url); let state_json = serde_json::to_string(&state).unwrap(); Cookie::build(SQLPAGE_STATE_COOKIE_NAME, state_json) From 1e455ff2854fb88b1efdac0d7d54a2cce70f8a75 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 29 Jul 2025 11:43:04 +0000 Subject: [PATCH 3/6] Move OIDC callback handling after user authentication check Co-authored-by: contact --- src/webserver/oidc.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index 93975b14..c16cb0ec 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -291,17 +291,17 @@ where fn call(&self, request: ServiceRequest) -> Self::Future { log::trace!("Started OIDC middleware request handling"); - // Handle OIDC callback URL even for authenticated users - if request.path() == SQLPAGE_REDIRECT_URI { - log::debug!("The request is the OIDC callback for an authenticated user"); - return Self::handle_authenticated_oidc_callback(request); - } - let oidc_client = Arc::clone(&self.oidc_state.client); match get_authenticated_user_info(&oidc_client, &request) { Ok(Some(claims)) => { log::trace!("Storing authenticated user info in request extensions: {claims:?}"); request.extensions_mut().insert(claims); + + // Handle OIDC callback URL for authenticated users + if request.path() == SQLPAGE_REDIRECT_URI { + log::debug!("The request is the OIDC callback for an authenticated user"); + return Self::handle_authenticated_oidc_callback(request); + } } Ok(None) => { log::trace!("No authenticated user found"); From d4c70e9d10bda54ecbf12bfde635e574627ffbad Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 29 Jul 2025 22:12:15 +0200 Subject: [PATCH 4/6] fmt --- src/webserver/oidc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index c16cb0ec..e04c1159 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -296,7 +296,7 @@ where Ok(Some(claims)) => { log::trace!("Storing authenticated user info in request extensions: {claims:?}"); request.extensions_mut().insert(claims); - + // Handle OIDC callback URL for authenticated users if request.path() == SQLPAGE_REDIRECT_URI { log::debug!("The request is the OIDC callback for an authenticated user"); From 69e2e39b561edd985c908c2c9cdd41910e2224c6 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 29 Jul 2025 22:18:54 +0200 Subject: [PATCH 5/6] fix cursor fuckup --- src/app_config.rs | 2 +- src/template_helpers.rs | 2 +- src/webserver/oidc.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app_config.rs b/src/app_config.rs index 9a1056a3..6b2ef78d 100644 --- a/src/app_config.rs +++ b/src/app_config.rs @@ -494,7 +494,7 @@ fn create_default_database(configuration_directory: &Path) -> String { } #[cfg(any(test, not(feature = "lambda-web")))] -fn encode_uri(path: &Path) -> std::borrow::Cow<'_, str> { +fn encode_uri(path: &Path) -> std::borrow::Cow { const ASCII_SET: &percent_encoding::AsciiSet = &percent_encoding::NON_ALPHANUMERIC .remove(b'-') .remove(b'_') diff --git a/src/template_helpers.rs b/src/template_helpers.rs index 719a55e2..76bb8f77 100644 --- a/src/template_helpers.rs +++ b/src/template_helpers.rs @@ -704,7 +704,7 @@ mod tests { } } - fn as_args(contents: &Value) -> [PathAndJson<'_>; 1] { + fn as_args(contents: &Value) -> [PathAndJson; 1] { [as_helper_arg(CONTENT_KEY, contents)] } diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index e04c1159..536e1f20 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -679,7 +679,7 @@ impl OidcLoginState { } } -fn create_state_cookie(request: &ServiceRequest, auth_url: AuthUrlParams) -> Cookie<'_> { +fn create_state_cookie(request: &ServiceRequest, auth_url: AuthUrlParams) -> Cookie { let state = OidcLoginState::new(request, auth_url); let state_json = serde_json::to_string(&state).unwrap(); Cookie::build(SQLPAGE_STATE_COOKIE_NAME, state_json) From bf2160f0ba22a7efc7c0fdb4f84a4d0125f4e901 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Tue, 29 Jul 2025 22:48:04 +0200 Subject: [PATCH 6/6] Move OIDC callback handler to standalone function --- src/webserver/oidc.rs | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/src/webserver/oidc.rs b/src/webserver/oidc.rs index 536e1f20..00b2781b 100644 --- a/src/webserver/oidc.rs +++ b/src/webserver/oidc.rs @@ -252,29 +252,19 @@ where } }) } +} - fn handle_authenticated_oidc_callback( - request: ServiceRequest, - ) -> LocalBoxFuture, Error>> { - Box::pin(async move { - log::debug!("Handling OIDC callback for already authenticated user"); - - // Try to get the initial URL from the state cookie - let redirect_url = match get_state_from_cookie(&request) { - Ok(state) => { - log::debug!("Found initial URL in state: {}", state.initial_url); - state.initial_url - } - Err(e) => { - log::debug!("Could not get state from cookie (user might have been redirected from elsewhere): {e}. Redirecting to /"); - "/".to_string() - } - }; - - let response = build_redirect_response(redirect_url); - Ok(request.into_response(response)) - }) - } +/// When an user has already authenticated (potentially in another tab), we ignore the callback and redirect to the initial URL. +fn handle_authenticated_oidc_callback( + request: ServiceRequest, +) -> LocalBoxFuture, Error>> { + let redirect_url = match get_state_from_cookie(&request) { + Ok(state) => state.initial_url, + Err(_) => "/".to_string(), + }; + log::debug!("OIDC callback received for authenticated user. Redirecting to {redirect_url}"); + let response = request.into_response(build_redirect_response(redirect_url)); + Box::pin(ready(Ok(response))) } impl Service for OidcService @@ -294,14 +284,11 @@ where let oidc_client = Arc::clone(&self.oidc_state.client); match get_authenticated_user_info(&oidc_client, &request) { Ok(Some(claims)) => { - log::trace!("Storing authenticated user info in request extensions: {claims:?}"); - request.extensions_mut().insert(claims); - - // Handle OIDC callback URL for authenticated users if request.path() == SQLPAGE_REDIRECT_URI { - log::debug!("The request is the OIDC callback for an authenticated user"); - return Self::handle_authenticated_oidc_callback(request); + return handle_authenticated_oidc_callback(request); } + log::trace!("Storing authenticated user info in request extensions: {claims:?}"); + request.extensions_mut().insert(claims); } Ok(None) => { log::trace!("No authenticated user found");