Enhancements and Bug Fixes: Align Pre-login Behavior, TLS Error Ignorance, GUI Auto-Launch, and Documentation Improvements (#291)

This commit is contained in:
Kevin Yue
2024-01-21 10:43:47 +08:00
committed by GitHub
parent 03f8c98cb5
commit 8bc4049a0f
17 changed files with 323 additions and 204 deletions

View File

@@ -6,7 +6,7 @@ edition.workspace = true
license.workspace = true
[dependencies]
gpapi = { path = "../../crates/gpapi" }
gpapi = { path = "../../crates/gpapi", features = ["clap"] }
openconnect = { path = "../../crates/openconnect" }
anyhow.workspace = true
clap.workspace = true

View File

@@ -16,6 +16,11 @@ const VERSION: &str = concat!(
")"
);
pub(crate) struct SharedArgs {
pub(crate) fix_openssl: bool,
pub(crate) ignore_tls_errors: bool,
}
#[derive(Subcommand)]
enum CliCommand {
#[command(about = "Connect to a portal server")]
@@ -40,6 +45,8 @@ enum CliCommand {
{usage-heading} {usage}
{all-args}{after-help}
See 'gpclient help <command>' for more information on a specific command.
"
)]
struct Cli {
@@ -51,6 +58,8 @@ struct Cli {
help = "Get around the OpenSSL `unsafe legacy renegotiation` error"
)]
fix_openssl: bool,
#[arg(long, help = "Ignore the TLS errors")]
ignore_tls_errors: bool,
}
impl Cli {
@@ -67,9 +76,17 @@ impl Cli {
// The temp file will be dropped automatically when the file handle is dropped
// So, declare it here to ensure it's not dropped
let _file = self.fix_openssl()?;
let shared_args = SharedArgs {
fix_openssl: self.fix_openssl,
ignore_tls_errors: self.ignore_tls_errors,
};
if self.ignore_tls_errors {
info!("TLS errors will be ignored");
}
match &self.command {
CliCommand::Connect(args) => ConnectHandler::new(args, self.fix_openssl).handle().await,
CliCommand::Connect(args) => ConnectHandler::new(args, &shared_args).handle().await,
CliCommand::Disconnect => DisconnectHandler::new().handle(),
CliCommand::LaunchGui(args) => LaunchGuiHandler::new(args).handle().await,
}
@@ -89,13 +106,24 @@ pub(crate) async fn run() {
if let Err(err) = cli.run().await {
eprintln!("\nError: {}", err);
if err.to_string().contains("unsafe legacy renegotiation") && !cli.fix_openssl {
let err = err.to_string();
if err.contains("unsafe legacy renegotiation") && !cli.fix_openssl {
eprintln!("\nRe-run it with the `--fix-openssl` option to work around this issue, e.g.:\n");
// Print the command
let args = std::env::args().collect::<Vec<_>>();
eprintln!("{} --fix-openssl {}\n", args[0], args[1..].join(" "));
}
if err.contains("certificate verify failed") {
eprintln!(
"\nRe-run it with the `--ignore-tls-errors` option to ignore the certificate error, e.g.:\n"
);
// Print the command
let args = std::env::args().collect::<Vec<_>>();
eprintln!("{} --ignore-tls-errors {}\n", args[0], args[1..].join(" "));
}
std::process::exit(1);
}
}

View File

@@ -2,9 +2,10 @@ use std::{fs, sync::Arc};
use clap::Args;
use gpapi::{
clap::args::Os,
credential::{Credential, PasswordCredential},
gateway::gateway_login,
gp_params::GpParams,
gp_params::{ClientOs, GpParams},
portal::{prelogin, retrieve_config, Prelogin},
process::auth_launcher::SamlAuthLauncher,
utils::{self, shutdown_signal},
@@ -14,7 +15,7 @@ use inquire::{Password, PasswordDisplayMode, Select, Text};
use log::info;
use openconnect::Vpn;
use crate::GP_CLIENT_LOCK_FILE;
use crate::{cli::SharedArgs, GP_CLIENT_LOCK_FILE};
#[derive(Args)]
pub(crate) struct ConnectArgs {
@@ -36,6 +37,10 @@ pub(crate) struct ConnectArgs {
script: Option<String>,
#[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, help = "The HiDPI mode, useful for high resolution screens")]
hidpi: bool,
#[arg(long, help = "Do not reuse the remembered authentication cookie")]
@@ -44,12 +49,12 @@ pub(crate) struct ConnectArgs {
pub(crate) struct ConnectHandler<'a> {
args: &'a ConnectArgs,
fix_openssl: bool,
shared_args: &'a SharedArgs,
}
impl<'a> ConnectHandler<'a> {
pub(crate) fn new(args: &'a ConnectArgs, fix_openssl: bool) -> Self {
Self { args, fix_openssl }
pub(crate) fn new(args: &'a ConnectArgs, shared_args: &'a SharedArgs) -> Self {
Self { args, shared_args }
}
pub(crate) async fn handle(&self) -> anyhow::Result<()> {
@@ -57,9 +62,12 @@ impl<'a> ConnectHandler<'a> {
let gp_params = GpParams::builder()
.user_agent(&self.args.user_agent)
.client_os(ClientOs::from(&self.args.os))
.os_version(self.args.os_version.clone())
.ignore_tls_errors(self.shared_args.ignore_tls_errors)
.build();
let prelogin = prelogin(&portal, &self.args.user_agent).await?;
let prelogin = prelogin(&portal, &gp_params).await?;
let portal_credential = self.obtain_portal_credential(&prelogin).await?;
let mut portal_config = retrieve_config(&portal, &portal_credential, &gp_params).await?;
@@ -114,10 +122,13 @@ impl<'a> ConnectHandler<'a> {
match prelogin {
Prelogin::Saml(prelogin) => {
SamlAuthLauncher::new(&self.args.server)
.user_agent(&self.args.user_agent)
.saml_request(prelogin.saml_request())
.user_agent(&self.args.user_agent)
.os(self.args.os.as_str())
.os_version(self.args.os_version.as_deref())
.hidpi(self.args.hidpi)
.fix_openssl(self.fix_openssl)
.fix_openssl(self.shared_args.fix_openssl)
.ignore_tls_errors(self.shared_args.ignore_tls_errors)
.clean(self.args.clean)
.launch()
.await