From 75db9e162f59829268f01d50e049bfd7960c79a5 Mon Sep 17 00:00:00 2001 From: Kevin Yue Date: Sun, 28 May 2023 18:56:25 +0800 Subject: [PATCH] refactor: refine the SAML login workflow --- gpgui/src-tauri/src/auth.rs | 86 +++++++++++++++++++++++++++---------- gpgui/src-tauri/src/main.rs | 9 +++- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/gpgui/src-tauri/src/auth.rs b/gpgui/src-tauri/src/auth.rs index 8b8f938..00f753d 100644 --- a/gpgui/src-tauri/src/auth.rs +++ b/gpgui/src-tauri/src/auth.rs @@ -6,10 +6,10 @@ use tauri::EventHandler; use tauri::{AppHandle, Manager, Window, WindowBuilder, WindowEvent::CloseRequested, WindowUrl}; use tokio::sync::{mpsc, Mutex}; use tokio::time::timeout; -use webkit2gtk::{ - gio::Cancellable, glib::GString, traits::WebViewExt, LoadEvent, URIResponseExt, WebResource, - WebResourceExt, -}; +use webkit2gtk::gio::Cancellable; +use webkit2gtk::glib::GString; +use webkit2gtk::traits::{URIResponseExt, WebViewExt}; +use webkit2gtk::{CookieManagerExt, LoadEvent, WebContextExt, WebResource, WebResourceExt}; const AUTH_WINDOW_LABEL: &str = "auth_window"; const AUTH_ERROR_EVENT: &str = "auth-error"; @@ -96,11 +96,14 @@ enum AuthEvent { pub(crate) async fn saml_login( auth_request: AuthRequest, ua: &str, + clear_cookies: bool, app_handle: &AppHandle, ) -> tauri::Result> { + info!("Starting SAML login"); + let (event_tx, event_rx) = mpsc::channel::(8); let window = build_window(app_handle, ua)?; - setup_webview(&window, event_tx.clone())?; + setup_webview(&window, clear_cookies, event_tx.clone())?; let handler = setup_window(&window, event_tx); let result = process(&window, auth_request, event_rx).await; @@ -121,11 +124,19 @@ fn build_window(app_handle: &AppHandle, ua: &str) -> tauri::Result { } // Setup webview events -fn setup_webview(window: &Window, event_tx: mpsc::Sender) -> tauri::Result<()> { +fn setup_webview( + window: &Window, + clear_cookies: bool, + event_tx: mpsc::Sender, +) -> tauri::Result<()> { window.with_webview(move |wv| { let wv = wv.inner(); let event_tx = event_tx.clone(); + if clear_cookies { + clear_webview_cookies(&wv); + } + wv.connect_load_changed(move |wv, event| { if LoadEvent::Finished != event { return; @@ -172,8 +183,6 @@ fn setup_window(window: &Window, event_tx: mpsc::Sender) -> EventHand window.listen_global(AUTH_REQUEST_EVENT, move |event| { if let Ok(payload) = TryInto::::try_into(event.payload()) { - debug!("---------Received auth request"); - let event_tx = event_tx.clone(); let _ = tokio::spawn(async move { if let Err(err) = event_tx.send(AuthEvent::Request(payload)).await { @@ -189,6 +198,8 @@ async fn process( auth_request: AuthRequest, event_rx: mpsc::Receiver, ) -> tauri::Result> { + info!("Processing auth request: {:?}", auth_request); + process_request(window, auth_request)?; let handle = tokio::spawn(show_window_after_timeout(window.clone())); @@ -205,9 +216,11 @@ fn process_request(window: &Window, auth_request: AuthRequest) -> tauri::Result< let wv = wv.inner(); if is_post { // Load SAML request as HTML if POST binding is used + info!("Loading SAML request as HTML"); wv.load_html(&saml_request, None); } else { // Redirect to SAML request URL if REDIRECT binding is used + info!("Redirecting to SAML request URL"); wv.load_uri(&saml_request); } }) @@ -215,7 +228,10 @@ fn process_request(window: &Window, auth_request: AuthRequest) -> tauri::Result< async fn show_window_after_timeout(window: Window) { tokio::time::sleep(Duration::from_secs(FALLBACK_SHOW_WINDOW_TIMEOUT)).await; - info!("Showing window after timeout expired: {} seconds", FALLBACK_SHOW_WINDOW_TIMEOUT); + info!( + "Showing window after timeout ({:?} seconds)", + FALLBACK_SHOW_WINDOW_TIMEOUT + ); show_window(&window); } @@ -223,6 +239,8 @@ async fn process_auth_event( window: &Window, mut event_rx: mpsc::Receiver, ) -> Option { + info!("Processing auth event..."); + let (cancel_timeout_tx, cancel_timeout_rx) = mpsc::channel::<()>(1); let cancel_timeout_rx = Arc::new(Mutex::new(cancel_timeout_rx)); @@ -236,10 +254,12 @@ async fn process_auth_event( } } AuthEvent::Success(auth_data) => { + info!("Got auth data successfully, closing window"); close_window(window); return Some(auth_data); } AuthEvent::Cancel => { + info!("User cancelled the authentication process, closing window"); close_window(window); return None; } @@ -255,6 +275,16 @@ async fn process_auth_event( } } AuthEvent::Error(AuthError::TokenNotFound) => { + let window_visible = window.is_visible().unwrap_or(false); + if window_visible { + continue; + } + + info!( + "Token not found, showing window in {} seconds", + SHOW_WINDOW_TIMEOUT + ); + let cancel_timeout_rx = cancel_timeout_rx.clone(); tokio::spawn(handle_token_not_found(window.clone(), cancel_timeout_rx)); } @@ -269,17 +299,16 @@ async fn process_auth_event( async fn handle_token_not_found(window: Window, cancel_timeout_rx: Arc>>) { match cancel_timeout_rx.try_lock() { Ok(mut cancel_timeout_rx) => { - debug!("Scheduling timeout to show window"); let duration = Duration::from_secs(SHOW_WINDOW_TIMEOUT); if let Err(_) = timeout(duration, cancel_timeout_rx.recv()).await { info!("Timeout expired, showing window"); show_window(&window); } else { - debug!("Showing window timeout cancelled"); + info!("Showing window timeout cancelled"); } } Err(_) => { - debug!("Timeout already scheduled, skipping"); + debug!("Window will be shown by another task, skipping"); } } } @@ -289,7 +318,7 @@ async fn handle_token_not_found(window: Window, cancel_timeout_rx: Arc) { if let Some(response) = main_res.response() { if let Some(auth_data) = read_auth_data_from_response(&response) { - info!("Got auth data from HTTP headers: {:?}", auth_data); + debug!("Got auth data from HTTP headers: {:?}", auth_data); send_auth_data(&event_tx, auth_data); return; } @@ -301,7 +330,7 @@ fn parse_auth_data(main_res: &WebResource, event_tx: mpsc::Sender) { let html = String::from_utf8_lossy(&data); match read_auth_data_from_html(&html) { Ok(auth_data) => { - info!("Got auth data from HTML: {:?}", auth_data); + debug!("Got auth data from HTML: {:?}", auth_data); send_auth_data(&event_tx, auth_data); } Err(err) => { @@ -372,15 +401,14 @@ fn send_auth_data(event_tx: &mpsc::Sender, auth_data: AuthData) { } fn show_window(window: &Window) { - match window.is_visible() { - Ok(true) => { - debug!("Window is already visible"); - } - _ => { - if let Err(err) = window.show() { - warn!("Error showing window: {}", err); - } - } + let visible = window.is_visible().unwrap_or(false); + if visible { + debug!("Window is already visible, skipping"); + return; + } + + if let Err(err) = window.show() { + warn!("Error showing window: {}", err); } } @@ -389,3 +417,15 @@ fn close_window(window: &Window) { warn!("Error closing window: {}", err); } } + +fn clear_webview_cookies(wv: &webkit2gtk::WebView) { + if let Some(context) = wv.context() { + if let Some(cookie_manager) = context.cookie_manager() { + #[allow(deprecated)] + cookie_manager.delete_all_cookies(); + info!("Cookies cleared"); + return; + } + } + warn!("No cookie manager found"); +} diff --git a/gpgui/src-tauri/src/main.rs b/gpgui/src-tauri/src/main.rs index addabcf..6588776 100644 --- a/gpgui/src-tauri/src/main.rs +++ b/gpgui/src-tauri/src/main.rs @@ -40,7 +40,14 @@ async fn saml_login( app_handle: AppHandle, ) -> tauri::Result> { let ua = "PAN GlobalProtect"; - auth::saml_login(AuthRequest::new(binding, request), ua, &app_handle).await + let clear_cookies = false; + auth::saml_login( + AuthRequest::new(binding, request), + ua, + clear_cookies, + &app_handle, + ) + .await } #[derive(Debug, Clone, Serialize)]