fix: enhance gpauth to support browser authentication

This commit is contained in:
Kevin Yue
2024-08-15 09:10:12 +00:00
parent 9317430968
commit 57e20fe478
13 changed files with 171 additions and 66 deletions

View File

@@ -1,5 +1,6 @@
[package]
name = "gpauth"
authors.workspace = true
version.workspace = true
edition.workspace = true
license.workspace = true

View File

@@ -1,3 +1,5 @@
use std::{env::temp_dir, fs, os::unix::fs::PermissionsExt};
use clap::Parser;
use gpapi::{
auth::{SamlAuthData, SamlAuthResult},
@@ -11,36 +13,68 @@ use log::{info, LevelFilter};
use serde_json::json;
use tauri::{App, AppHandle, RunEvent};
use tempfile::NamedTempFile;
use tokio::{io::AsyncReadExt, net::TcpListener};
use crate::auth_window::{portal_prelogin, AuthWindow};
const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
#[derive(Parser, Clone)]
#[command(version = VERSION)]
#[command(
version = VERSION,
author,
about = "The authentication component for the GlobalProtect VPN client, supports the SSO authentication method.",
help_template = "\
{before-help}{name} {version}
{author}
{about}
{usage-heading} {usage}
{all-args}{after-help}
See 'gpauth -h' for more information.
"
)]
struct Cli {
#[arg(help = "The portal server to authenticate")]
server: String,
#[arg(long)]
#[arg(long, help = "Treating the server as a gateway")]
gateway: bool,
#[arg(long)]
#[arg(long, help = "The SAML authentication request")]
saml_request: Option<String>,
#[arg(long, default_value = GP_USER_AGENT)]
#[arg(long, default_value = GP_USER_AGENT, help = "The user agent to use")]
user_agent: String,
#[arg(long, default_value = "Linux")]
os: Os,
#[arg(long)]
os_version: Option<String>,
#[arg(long)]
#[arg(long, help = "The HiDPI mode, useful for high-resolution screens")]
hidpi: bool,
#[arg(long)]
#[arg(long, help = "Get around the OpenSSL `unsafe legacy renegotiation` error")]
fix_openssl: bool,
#[arg(long)]
#[arg(long, help = "Ignore TLS errors")]
ignore_tls_errors: bool,
#[arg(long)]
#[arg(long, help = "Clean the cache of the embedded browser")]
clean: bool,
#[arg(long)]
#[arg(long, help = "Use the default browser for authentication")]
default_browser: bool,
#[arg(long)]
#[arg(
long,
help = "The browser to use for authentication, e.g., `default`, `firefox`, `chrome`, `chromium`, or the path to the browser executable"
)]
browser: Option<String>,
}
@@ -74,6 +108,15 @@ impl Cli {
info!("Please continue the authentication process in the default browser");
let auth_result = match wait_auth_data().await {
Ok(auth_data) => SamlAuthResult::Success(auth_data),
Err(err) => SamlAuthResult::Failure(format!("{}", err)),
};
info!("Authentication completed");
println!("{}", json!(auth_result));
return Ok(());
}
@@ -181,3 +224,35 @@ pub async fn run() {
std::process::exit(1);
}
}
async fn wait_auth_data() -> anyhow::Result<SamlAuthData> {
// Start a local server to receive the browser authentication data
let listener = TcpListener::bind("127.0.0.1:0").await?;
let port = listener.local_addr()?.port();
let port_file = temp_dir().join("gpcallback.port");
// Write the port to a file
fs::write(&port_file, port.to_string())?;
fs::set_permissions(&port_file, fs::Permissions::from_mode(0o600))?;
// Remove the previous log file
let callback_log = temp_dir().join("gpcallback.log");
let _ = fs::remove_file(&callback_log);
info!("Listening authentication data on port {}", port);
info!(
"If it hangs, please check the logs at `{}` for more information",
callback_log.display()
);
let (mut socket, _) = listener.accept().await?;
info!("Received the browser authentication data from the socket");
let mut data = String::new();
socket.read_to_string(&mut data).await?;
// Remove the port file
fs::remove_file(&port_file)?;
let auth_data = SamlAuthData::from_gpcallback(&data)?;
Ok(auth_data)
}