diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/errors.rs | 12 | ||||
-rw-r--r-- | src/handlers/auth.rs | 34 | ||||
-rw-r--r-- | src/handlers/mod.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 21 |
4 files changed, 67 insertions, 1 deletions
diff --git a/src/errors.rs b/src/errors.rs index e0a6df9..cbec046 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -20,7 +20,16 @@ pub enum ServiceError { Reqwest(#[from] reqwest::Error), #[error("Command error: {0}")] - Command(#[from] std::io::Error) + Command(#[from] std::io::Error), + + #[error("Not authorized")] + NotAuthorized, + + #[error("Generic: {0}")] + Generic(String), + + #[error("Paseto: {0}")] + Paseto(#[from] pasetors::errors::Error), } pub type StringResult<T = &'static str> = std::result::Result<T, ServiceError>; @@ -35,6 +44,7 @@ impl IntoResponse for ServiceError { let status = match self { ServiceError::NotFound => StatusCode::NOT_FOUND, + ServiceError::NotAuthorized => StatusCode::UNAUTHORIZED, _ => StatusCode::INTERNAL_SERVER_ERROR, }; Response::builder() diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs new file mode 100644 index 0000000..a9ac394 --- /dev/null +++ b/src/handlers/auth.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; + +use axum::{extract::Query, Extension}; +use axum_macros::debug_handler; +use pasetors::{claims::Claims, keys::{AsymmetricKeyPair, Generate}, version4::V4}; +use uuid::Uuid; + +use crate::{errors::{NoneResult, ServiceError}, State}; + + +/** + * Takes in a request to create a new token with a secret key that gets printed + * to stdout and, if it matches, returns a valid PASETO token that can be used + * for future authentication + */ +#[debug_handler] +pub async fn begin(Query(params): Query<HashMap<String, String>>, Extension(state): Extension<State>) -> NoneResult { + if let Some(k) = params.get("key") { + if k == &state.gen_key { + let mut claims = Claims::new()?; + claims.non_expiring(); + claims.audience("solard")?; + claims.add_additional("uuid", Uuid::new_v4().to_string())?; + + let kp = AsymmetricKeyPair::<V4>::generate()?; + } else { + return Err(ServiceError::NotAuthorized); + } + } else { + return Err(ServiceError::Generic("No key supplied".to_string())); + } + + Ok(()) +} diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 591f76e..8f8224e 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -1 +1,2 @@ pub mod planets; +pub mod auth; diff --git a/src/main.rs b/src/main.rs index 4dc78a6..3f889cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use axum::{ Json, Router, Extension }; +use rand::{thread_rng, Rng, distributions::Alphanumeric}; use serde::{Deserialize, Serialize}; use solarlib::star::Star; use std::{net::SocketAddr, time::Duration, str::FromStr, sync::Arc}; @@ -20,8 +21,11 @@ mod errors; mod handlers; +#[derive(Clone)] pub struct State { pub hw_url: String, + pub secret_key: String, + pub gen_key: String, } #[tokio::main] @@ -36,10 +40,25 @@ async fn main() { .with(tracing_subscriber::fmt::layer()) .init(); + let rand_key: String = thread_rng() + .sample_iter(&Alphanumeric) + .take(30) + .map(char::from) + .collect(); + let shared_state = Arc::new(State { hw_url: std::env::var("HOMEWORLD_URL").expect("No Homeworld URL set"), + secret_key: std::env::var("SECRET_KEY").unwrap_or("bad-key".to_string()), + gen_key: rand_key, }); + if shared_state.secret_key == "bad-key" { + tracing::warn!("No secret key set! This is a bad idea."); + tracing::warn!("Using default of `bad-key`"); + } + + tracing::info!("Random Key: {}", shared_state.gen_key); + let app = Router::new() .route("/health", get(health_check)) .route("/planets/list", get(handlers::planets::list)) @@ -52,6 +71,8 @@ async fn main() { .route("/planets/:uuid/reboot", post(handlers::planets::reboot)) .route("/planets/:uuid/reboot/hard", post(handlers::planets::force_reboot)) .route("/planets/:uuid/destroy", post(handlers::planets::no_planet)) + // Authentication + .route("/auth/begin", post(handlers::auth::begin)) .layer( ServiceBuilder::new() .layer(HandleErrorLayer::new(|error: BoxError| async move { if error.is::<tower::timeout::error::Elapsed>() { |