From 036304c6863f7758aaf08c479e5dd283984a8c56 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 22 Nov 2023 07:20:12 -0600 Subject: [PATCH] wip: user/login: request signed cert --- src/user/cert.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ src/user/mod.rs | 3 ++- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/user/cert.rs diff --git a/src/user/cert.rs b/src/user/cert.rs new file mode 100644 index 0000000..26a4f13 --- /dev/null +++ b/src/user/cert.rs @@ -0,0 +1,63 @@ +use std::path::Path; + +use reqwest::multipart::{Form, Part}; +use reqwest::{StatusCode, Url}; +use tracing::{debug, error, info}; + +pub async fn sign_key(token: &str) -> Result<(), Box> { + let url = crate::get_sshca_server_url()?; + + let pubkey = Path::new("/home/dustin/.ssh/id_ed25519.pub"); + let pubkey_path = pubkey.to_owned(); + let pubkey = std::fs::read_to_string(&pubkey_path)?; + + let mut url = + Url::parse(&url).map_err(|e| format!("Invalid URL: {}", e))?; + url.path_segments_mut() + .map_err(|_| "Invalid URL: missing host")? + .pop_if_empty() + .push("user") + .push("sign"); + + let form = Form::new().part( + "pubkey", + Part::bytes(pubkey.into_bytes()).file_name( + pubkey_path + .file_name() + .ok_or("Invalid public key file path")? + .to_str() + .ok_or("Invalid public key file path")? + .to_string(), + ), + ); + + let client = reqwest::Client::new(); + info!( + "Requesting SSH user certificate for {} with key {}", + "-", + pubkey_path.display() + ); + debug!("Request: POST {}", url); + let res = client + .post(url) + .header("Authorization", format!("Bearer {}", token)) + .multipart(form) + .send() + .await?; + debug!("Response: {:?} {}", &res.version(), &res.status()); + match res.error_for_status_ref() { + Ok(_) => (), + Err(e) if e.status() == Some(StatusCode::BAD_REQUEST) => { + let msg = res.text().await.unwrap_or_else(|e| e.to_string()); + error!("{}: {}", e, msg); + return Err(format!("{}\n{}", e, msg).into()); + } + Err(e) => { + error!("{}", e); + return Err(e.into()); + } + }; + let cert = res.text().await?; + println!("{}", cert); + Ok(()) +} diff --git a/src/user/mod.rs b/src/user/mod.rs index 24a3cd5..737a7aa 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -2,6 +2,7 @@ //! //! The `sshca user` sub-command handles user-based operations, such //! as signing an SSH user certificate. +mod cert; mod login; use std::time::Duration; @@ -54,6 +55,6 @@ async fn login(args: LoginArgs) -> MainResult { let url = super::get_sshca_server_url()?; let config = login::get_oidc_config(&url).await?; let token = login::login(config, listen, timeout).await?; - println!("{}", token); + cert::sign_key(&token).await.unwrap(); Ok(()) }