feat: support specify the browser to use

Related: #405, #407, #397
This commit is contained in:
Kevin Yue 2024-08-14 21:27:01 +08:00
parent c2a6a436a5
commit 9460d498fc
No known key found for this signature in database
GPG Key ID: 4D3A6EE977B15AC4
7 changed files with 108 additions and 13 deletions

36
Cargo.lock generated
View File

@ -1459,6 +1459,7 @@ dependencies = [
"url",
"urlencoding",
"uzers",
"which",
"whoami",
]
@ -1676,6 +1677,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "html-escape"
version = "0.2.13"
@ -2153,9 +2163,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libredox"
@ -3234,9 +3244,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.28"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags 2.4.1",
"errno",
@ -4798,6 +4808,18 @@ dependencies = [
"windows-metadata",
]
[[package]]
name = "which"
version = "6.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075"
dependencies = [
"either",
"home",
"rustix",
"winsafe",
]
[[package]]
name = "whoami"
version = "1.5.1"
@ -5104,6 +5126,12 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wry"
version = "0.24.7"

View File

@ -46,6 +46,7 @@ compile-time = "0.2"
serde_urlencoded = "0.7"
md5="0.7"
sha256="1"
which="6"
# Tauri dependencies
tauri = { version = "1.5" }

View File

@ -40,6 +40,8 @@ struct Cli {
clean: bool,
#[arg(long)]
default_browser: bool,
#[arg(long)]
external_browser: Option<String>,
}
impl Cli {
@ -59,8 +61,15 @@ impl Cli {
None => portal_prelogin(&self.server, &gp_params).await?,
};
if self.default_browser {
let browser_auth = BrowserAuthenticator::new(&saml_request);
let browser_auth = if let Some(external_browser) = &self.external_browser {
Some(BrowserAuthenticator::new_with_browser(&saml_request, external_browser))
} else if self.default_browser {
Some(BrowserAuthenticator::new(&saml_request))
} else {
None
};
if let Some(browser_auth) = browser_auth {
browser_auth.authenticate()?;
info!("Please continue the authentication process in the default browser");

View File

@ -97,6 +97,12 @@ pub(crate) struct ConnectArgs {
#[arg(long, help = "Use the default browser to authenticate")]
default_browser: bool,
#[arg(
long,
help = "Use the specified browser to authenticate, e.g., firefox, chromium, chrome, or the path to the browser"
)]
external_browser: Option<String>,
}
impl ConnectArgs {
@ -326,6 +332,11 @@ impl<'a> ConnectHandler<'a> {
match prelogin {
Prelogin::Saml(prelogin) => {
let use_default_browser = prelogin.support_default_browser() && self.args.default_browser;
let external_browser = if prelogin.support_default_browser() {
self.args.external_browser.as_deref()
} else {
None
};
let cred = SamlAuthLauncher::new(&self.args.server)
.gateway(is_gateway)
@ -338,6 +349,7 @@ impl<'a> ConnectHandler<'a> {
.ignore_tls_errors(self.shared_args.ignore_tls_errors)
.clean(self.args.clean)
.default_browser(use_default_browser)
.external_browser(external_browser)
.launch()
.await?;

View File

@ -30,6 +30,7 @@ uzers.workspace = true
serde_urlencoded.workspace = true
md5.workspace = true
sha256.workspace = true
which.workspace = true
tauri = { workspace = true, optional = true }
clap = { workspace = true, optional = true }

View File

@ -19,6 +19,7 @@ pub struct SamlAuthLauncher<'a> {
ignore_tls_errors: bool,
clean: bool,
default_browser: bool,
external_browser: Option<&'a str>,
}
impl<'a> SamlAuthLauncher<'a> {
@ -35,6 +36,7 @@ impl<'a> SamlAuthLauncher<'a> {
ignore_tls_errors: false,
clean: false,
default_browser: false,
external_browser: None,
}
}
@ -88,6 +90,11 @@ impl<'a> SamlAuthLauncher<'a> {
self
}
pub fn external_browser(mut self, external_browser: Option<&'a str>) -> Self {
self.external_browser = external_browser;
self
}
/// Launch the authenticator binary as the current user or SUDO_USER if available.
pub async fn launch(self) -> anyhow::Result<Option<Credential>> {
let mut auth_cmd = Command::new(GP_AUTH_BINARY);
@ -133,6 +140,10 @@ impl<'a> SamlAuthLauncher<'a> {
auth_cmd.arg("--default-browser");
}
if let Some(external_browser) = self.external_browser {
auth_cmd.arg("--external-browser").arg(external_browser);
}
let mut non_root_cmd = auth_cmd.into_non_root()?;
let output = non_root_cmd
.kill_on_drop(true)

View File

@ -1,20 +1,31 @@
use std::{env::temp_dir, fs, io::Write, os::unix::fs::PermissionsExt};
use std::{borrow::Cow, env::temp_dir, fs, io::Write, os::unix::fs::PermissionsExt};
use anyhow::bail;
use log::warn;
use log::{info, warn};
pub struct BrowserAuthenticator<'a> {
auth_request: &'a str,
browser: Option<&'a str>,
}
impl BrowserAuthenticator<'_> {
pub fn new(auth_request: &str) -> BrowserAuthenticator {
BrowserAuthenticator { auth_request }
BrowserAuthenticator {
auth_request,
browser: None,
}
}
pub fn new_with_browser<'a>(auth_request: &'a str, browser: &'a str) -> BrowserAuthenticator<'a> {
BrowserAuthenticator {
auth_request,
browser: Some(browser),
}
}
pub fn authenticate(&self) -> anyhow::Result<()> {
if self.auth_request.starts_with("http") {
open::that_detached(self.auth_request)?;
let path = if self.auth_request.starts_with("http") {
Cow::Borrowed(self.auth_request)
} else {
let html_file = temp_dir().join("gpauth.html");
@ -31,9 +42,31 @@ impl BrowserAuthenticator<'_> {
file.set_permissions(fs::Permissions::from_mode(0o600))?;
file.write_all(self.auth_request.as_bytes())?;
open::that_detached(html_file)?;
Cow::Owned(html_file.to_string_lossy().to_string())
};
if let Some(browser) = self.browser {
let app = find_browser_path(browser);
info!("Launching browser: {}", app);
open::with_detached(path.as_ref(), app)?;
} else {
info!("Launching the default browser...");
open::that_detached(path.as_ref())?;
}
Ok(())
}
}
fn find_browser_path(browser: &str) -> String {
if browser == "chrome" {
which::which("google-chrome-stable")
.or_else(|_| which::which("google-chrome"))
.or_else(|_| which::which("chromium"))
.map(|path| path.to_string_lossy().to_string())
.unwrap_or_else(|_| browser.to_string())
} else {
browser.into()
}
}