mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
CLI and kanidm_client changes to handle errors and TLS validation changes (#2127)
* pulling out exitcode, adding hyper dep to handle errors (was already transitively there due to reqwest) * adding better error handling, more options for client things
This commit is contained in:
parent
4aee3365aa
commit
9b2fab7bb1
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -1456,12 +1456,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exitcode"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
|
@ -2849,6 +2843,7 @@ dependencies = [
|
|||
name = "kanidm_client"
|
||||
version = "1.1.0-rc.14-dev"
|
||||
dependencies = [
|
||||
"hyper",
|
||||
"kanidm_proto",
|
||||
"reqwest",
|
||||
"serde",
|
||||
|
@ -2917,7 +2912,6 @@ dependencies = [
|
|||
"compact_jwt",
|
||||
"cursive",
|
||||
"dialoguer",
|
||||
"exitcode",
|
||||
"futures-concurrency",
|
||||
"kanidm_build_profiles",
|
||||
"kanidm_client",
|
||||
|
|
|
@ -18,9 +18,16 @@ kanidm_proto = { workspace = true }
|
|||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
time = { workspace = true, features = ["serde", "std"] }
|
||||
tokio = { workspace = true, features = ["rt", "net", "time", "macros", "sync", "signal"] }
|
||||
tokio = { workspace = true, features = [
|
||||
"rt",
|
||||
"net",
|
||||
"time",
|
||||
"macros",
|
||||
"sync",
|
||||
"signal",
|
||||
] }
|
||||
toml = { workspace = true }
|
||||
uuid = { workspace = true, features = ["serde", "v4"] }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
webauthn-rs-proto = { workspace = true, features = ["wasm"] }
|
||||
|
||||
hyper = { workspace = true }
|
||||
|
|
|
@ -66,6 +66,7 @@ pub enum ClientError {
|
|||
SystemError,
|
||||
ConfigParseIssue(String),
|
||||
CertParseIssue(String),
|
||||
UntrustedCertificate(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
|
@ -468,6 +469,23 @@ fn test_make_url() {
|
|||
);
|
||||
}
|
||||
|
||||
/// This is probably pretty jank but it works and was pulled from here:
|
||||
/// <https://github.com/seanmonstar/reqwest/issues/1602#issuecomment-1220996681>
|
||||
fn find_reqwest_error_source<E: std::error::Error + 'static>(
|
||||
orig: &dyn std::error::Error,
|
||||
) -> Option<&E> {
|
||||
let mut cause = orig.source();
|
||||
while let Some(err) = cause {
|
||||
if let Some(typed) = err.downcast_ref::<E>() {
|
||||
return Some(typed);
|
||||
}
|
||||
cause = err.source();
|
||||
}
|
||||
|
||||
// else
|
||||
None
|
||||
}
|
||||
|
||||
impl KanidmClient {
|
||||
pub fn get_origin(&self) -> &Url {
|
||||
&self.origin
|
||||
|
@ -541,6 +559,28 @@ impl KanidmClient {
|
|||
*guard = false;
|
||||
}
|
||||
|
||||
/// You've got the response from a reqwest and you want to turn it into a `ClientError`
|
||||
fn handle_response_error(&self, error: reqwest::Error) -> ClientError {
|
||||
if error.is_connect() {
|
||||
if find_reqwest_error_source::<std::io::Error>(&error).is_some() {
|
||||
// TODO: one day handle IO errors better
|
||||
trace!("Got an IO error! {:?}", &error);
|
||||
return ClientError::Transport(error);
|
||||
}
|
||||
if let Some(hyper_error) = find_reqwest_error_source::<hyper::Error>(&error) {
|
||||
// hyper errors can be *anything* depending on the underlying client libraries
|
||||
// ref: https://github.com/hyperium/hyper/blob/9feb70e9249d9fb99634ec96f83566e6bb3b3128/src/error.rs#L26C2-L26C2
|
||||
if format!("{:?}", hyper_error)
|
||||
.to_lowercase()
|
||||
.contains("certificate")
|
||||
{
|
||||
return ClientError::UntrustedCertificate(format!("{}", hyper_error));
|
||||
}
|
||||
}
|
||||
}
|
||||
ClientError::Transport(error)
|
||||
}
|
||||
|
||||
async fn perform_simple_post_request<R: Serialize, T: DeserializeOwned>(
|
||||
&self,
|
||||
dest: &str,
|
||||
|
@ -554,7 +594,10 @@ impl KanidmClient {
|
|||
.body(req_string)
|
||||
.header(CONTENT_TYPE, APPLICATION_JSON);
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -617,7 +660,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -677,7 +723,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -730,7 +779,7 @@ impl KanidmClient {
|
|||
.body(req_string)
|
||||
.send()
|
||||
.await
|
||||
.map_err(ClientError::Transport)?;
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -781,7 +830,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -825,7 +877,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -870,7 +925,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -920,7 +978,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
@ -1390,7 +1451,10 @@ impl KanidmClient {
|
|||
}
|
||||
};
|
||||
|
||||
let response = response.send().await.map_err(ClientError::Transport)?;
|
||||
let response = response
|
||||
.send()
|
||||
.await
|
||||
.map_err(|err| self.handle_response_error(err))?;
|
||||
|
||||
self.expect_version(&response).await;
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ uuid = { workspace=true }
|
|||
zxcvbn = { workspace = true }
|
||||
lazy_static.workspace = true
|
||||
regex.workspace = true
|
||||
exitcode = "1.1.2"
|
||||
|
||||
[dependencies.cursive]
|
||||
version = "0.20.0"
|
||||
|
|
|
@ -62,20 +62,32 @@ impl CommonOpt {
|
|||
let client_builder = match ca_path {
|
||||
Some(p) => {
|
||||
debug!("Adding trusted CA cert {:?}", p);
|
||||
client_builder
|
||||
let client_builder = client_builder
|
||||
.add_root_certificate_filepath(p)
|
||||
.unwrap_or_else(|e| {
|
||||
error!("Failed to add ca certificate -- {:?}", e);
|
||||
std::process::exit(1);
|
||||
})
|
||||
});
|
||||
|
||||
debug!(
|
||||
"After attempting to add trusted CA cert, client builder state: {:?}",
|
||||
client_builder
|
||||
);
|
||||
client_builder
|
||||
}
|
||||
None => client_builder,
|
||||
};
|
||||
|
||||
debug!(
|
||||
"Post attempting to add trusted CA cert, client builder state: {:?}",
|
||||
client_builder
|
||||
let client_builder = match self.skip_hostname_verification {
|
||||
true => {
|
||||
warn!(
|
||||
"Accepting invalid hostnames on the certificate for {:?}",
|
||||
&self.addr
|
||||
);
|
||||
client_builder.danger_accept_invalid_hostnames(true)
|
||||
}
|
||||
false => client_builder,
|
||||
};
|
||||
|
||||
client_builder.build().unwrap_or_else(|e| {
|
||||
error!("Failed to build client instance -- {:?}", e);
|
||||
|
@ -176,7 +188,7 @@ impl CommonOpt {
|
|||
match prompt_for_username_get_values() {
|
||||
Ok(tuple) => tuple,
|
||||
Err(msg) => {
|
||||
error!("{}", msg);
|
||||
error!("Error: {}", msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,13 +56,21 @@ pub(crate) fn handle_client_error(response: ClientError, _output_mode: &OutputMo
|
|||
"Internal Server Error in response:{:?} {:?}",
|
||||
error_msg, message
|
||||
);
|
||||
std::process::exit(exitcode::SOFTWARE);
|
||||
std::process::exit(1);
|
||||
} else if status == StatusCode::NOT_FOUND {
|
||||
error!("Item not found:{:?} {:?}", error_msg, message)
|
||||
} else {
|
||||
error!("HTTP Error: {}{} {:?}", status, error_msg, message);
|
||||
}
|
||||
}
|
||||
ClientError::Transport(e) => {
|
||||
error!("HTTP-Transport Related Error: {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
ClientError::UntrustedCertificate(e) => {
|
||||
error!("Untrusted Certificate Error: {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
_ => {
|
||||
eprintln!("{:?}", response);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,13 @@ pub struct CommonOpt {
|
|||
/// Log format (still in very early development)
|
||||
#[clap(short, long = "output", env = "KANIDM_OUTPUT", default_value = "text")]
|
||||
output_mode: OutputMode,
|
||||
/// Skip hostname verification
|
||||
#[clap(
|
||||
long = "skip-hostname-verification",
|
||||
env = "KANIDM_SKIP_HOSTNAME_VERIFICATION",
|
||||
default_value_t = false
|
||||
)]
|
||||
skip_hostname_verification: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
|
|
Loading…
Reference in a new issue