From b945d0f1426c524177aaeb2aa3c1278c443a30dc Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Tue, 21 Nov 2023 21:31:43 -0600 Subject: [PATCH] server: Move SignKeyError to error module The `SignKeyError` enum will also be used by the request handler for signing SSH user certificates. Thus, I am moving it to its own module where it can be accessed from both places. --- src/server/error.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++ src/server/host.rs | 73 +++---------------------------------------- src/server/mod.rs | 1 + 3 files changed, 81 insertions(+), 68 deletions(-) create mode 100644 src/server/error.rs diff --git a/src/server/error.rs b/src/server/error.rs new file mode 100644 index 0000000..01d09c6 --- /dev/null +++ b/src/server/error.rs @@ -0,0 +1,75 @@ +//! SSHCA HTTP server errors +use axum::extract::multipart::MultipartError; +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; +use tracing::{debug, error}; + +use crate::ca; + +/// Error encountered while signing a key +pub enum SignKeyError { + /// Failed to parse HTTP multipart form request + Multipart(MultipartError), + /// Error handing SSH certificate + Cert(ca::CertError), + /// Error loading SSH private key file + LoadPrivateKey(ca::LoadKeyError), + /// Error parsing SSH public key + ParsePublicKey(ca::LoadKeyError), + /// Unsupported SSH key algorithm + UnsupportedAlgorithm(String), + /// No SSH public key included in request + NoKey, +} + +impl From for SignKeyError { + fn from(e: MultipartError) -> Self { + Self::Multipart(e) + } +} + +impl From for SignKeyError { + fn from(e: ca::CertError) -> Self { + Self::Cert(e) + } +} + +impl IntoResponse for SignKeyError { + fn into_response(self) -> Response { + match self { + Self::Multipart(e) => { + debug!("Error reading request: {}", e); + let body = e.to_string(); + (StatusCode::BAD_REQUEST, body).into_response() + } + Self::Cert(e) => { + error!("Failed to sign certificate: {}", e); + let body = "Service Unavailable"; + (StatusCode::SERVICE_UNAVAILABLE, body).into_response() + } + Self::LoadPrivateKey(e) => { + error!("Error loading CA private key: {}", e); + let body = "Service Unavailable"; + (StatusCode::SERVICE_UNAVAILABLE, body).into_response() + } + Self::ParsePublicKey(e) => { + error!("Error parsing public keykey: {}", e); + let body = e.to_string(); + (StatusCode::BAD_REQUEST, body).into_response() + } + Self::UnsupportedAlgorithm(a) => { + debug!("Requested certificate for unsupported key algorithm \"{}\"", a); + let body = format!("Unsupported key algorithm: {}", a); + (StatusCode::BAD_REQUEST, body).into_response() + } + Self::NoKey => { + debug!("No SSH public key provided in request"); + ( + StatusCode::BAD_REQUEST, + "No SSH public key provided in request", + ) + .into_response() + } + } + } +} diff --git a/src/server/host.rs b/src/server/host.rs index 7933818..33f5fea 100644 --- a/src/server/host.rs +++ b/src/server/host.rs @@ -3,24 +3,23 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use axum::async_trait; +use axum::extract::multipart::Multipart; use axum::extract::FromRequestParts; +use axum::extract::State; use axum::headers::authorization::Bearer; use axum::headers::{Authorization, Host}; use axum::http::request::Parts; -use axum::extract::multipart::{Multipart, MultipartError}; -use axum::extract::State; -use axum::http::StatusCode; -use axum::response::{IntoResponse, Response}; use axum::{RequestPartsExt, TypedHeader}; use serde::Serialize; use ssh_key::Algorithm; -use tracing::{debug, error, info, warn}; +use tracing::{debug, info, warn}; use uuid::Uuid; +use super::error::SignKeyError; +use super::{AuthError, Context}; use crate::auth::{self, HostClaims}; use crate::ca; use crate::machine_id; -use super::{AuthError, Context}; #[derive(Serialize)] pub struct SignKeyResponse { @@ -29,67 +28,6 @@ pub struct SignKeyResponse { certificates: HashMap, } -pub enum SignKeyError { - Multipart(MultipartError), - Cert(ca::CertError), - LoadPrivateKey(ca::LoadKeyError), - ParsePublicKey(ca::LoadKeyError), - UnsupportedAlgorithm(String), - NoKey, -} - -impl From for SignKeyError { - fn from(e: MultipartError) -> Self { - Self::Multipart(e) - } -} - -impl From for SignKeyError { - fn from(e: ca::CertError) -> Self { - Self::Cert(e) - } -} - -impl IntoResponse for SignKeyError { - fn into_response(self) -> Response { - match self { - Self::Multipart(e) => { - debug!("Error reading request: {}", e); - let body = e.to_string(); - (StatusCode::BAD_REQUEST, body).into_response() - } - Self::Cert(e) => { - error!("Failed to sign certificate: {}", e); - let body = "Service Unavailable"; - (StatusCode::SERVICE_UNAVAILABLE, body).into_response() - } - Self::LoadPrivateKey(e) => { - error!("Error loading CA private key: {}", e); - let body = "Service Unavailable"; - (StatusCode::SERVICE_UNAVAILABLE, body).into_response() - } - Self::ParsePublicKey(e) => { - error!("Error parsing public keykey: {}", e); - let body = e.to_string(); - (StatusCode::BAD_REQUEST, body).into_response() - } - Self::UnsupportedAlgorithm(a) => { - debug!("Requested certificate for unsupported key algorithm \"{}\"", a); - let body = format!("Unsupported key algorithm: {}", a); - (StatusCode::BAD_REQUEST, body).into_response() - } - Self::NoKey => { - debug!("No SSH public key provided in request"); - ( - StatusCode::BAD_REQUEST, - "No SSH public key provided in request", - ) - .into_response() - } - } - } -} - #[async_trait] impl FromRequestParts> for HostClaims { type Rejection = AuthError; @@ -154,7 +92,6 @@ async fn get_machine_id(hostname: &str, ctx: &super::State) -> Option { Some(machine_id) } - #[derive(Default)] struct SignKeyRequest { hostname: String, diff --git a/src/server/mod.rs b/src/server/mod.rs index 2bbd888..f93c6fe 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,3 +1,4 @@ +mod error; mod host; mod user;