From 7323852a7e26ff1bcef4cbe926a307522c820e15 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Sat, 29 Apr 2023 09:19:10 +0200 Subject: [PATCH] Use crypto wrapper & state manager from light-openid --- Cargo.lock | 10 ++--- Cargo.toml | 7 +--- src/crypto_wrapper.rs | 97 ------------------------------------------- src/lib.rs | 3 -- src/main.rs | 19 +++++---- src/state_manager.rs | 72 -------------------------------- src/time_utils.rs | 9 ---- 7 files changed, 19 insertions(+), 198 deletions(-) delete mode 100644 src/crypto_wrapper.rs delete mode 100644 src/state_manager.rs delete mode 100644 src/time_utils.rs diff --git a/Cargo.lock b/Cargo.lock index eeb7dc5..9bff78c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1043,12 +1043,15 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "light-openid" -version = "0.1.0-alpha" +version = "0.3.0-alpha" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1745cac605f9565d6fffdcf9b18ee6e51d95b16a8304533fc88e06e30537dc6f" +checksum = "7e5cec4a7a2327170125f62ce851e730ff9c44ad32389c20652ff7dcb9f719cf" dependencies = [ + "aes-gcm", "base64", + "bincode", "log", + "rand", "reqwest", "serde", "serde_json", @@ -1199,9 +1202,7 @@ name = "oidc-test-client" version = "0.1.0" dependencies = [ "actix-web", - "aes-gcm", "askama", - "base64", "bincode", "clap", "env_logger", @@ -1209,7 +1210,6 @@ dependencies = [ "lazy_static", "light-openid", "log", - "rand", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 27d4563..65d43d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -light-openid = "0.1.0-alpha" +light-openid = { version = "0.3.0-alpha", features=["crypto-wrapper"] } log = "0.4.17" env_logger = "0.10.0" clap = { version = "4.2.4", features = ["derive", "env"] } @@ -17,7 +17,4 @@ serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" reqwest = { version = "0.11.16", features = ["json"] } futures-util = "0.3.28" -aes-gcm = "0.10.1" -base64 = "0.21.0" -rand = "0.8.5" -bincode = {version="2.0.0-rc.3",features=["serde"]} \ No newline at end of file +bincode = "2.0.0-rc.3" \ No newline at end of file diff --git a/src/crypto_wrapper.rs b/src/crypto_wrapper.rs deleted file mode 100644 index e7fef4b..0000000 --- a/src/crypto_wrapper.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::io::ErrorKind; - -use crate::Res; -use aes_gcm::aead::{Aead, OsRng}; -use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce}; -use base64::engine::general_purpose::STANDARD as BASE64_STANDARD; -use base64::Engine as _; -use bincode::{Decode, Encode}; -use rand::Rng; - -const NONCE_LEN: usize = 12; - -pub struct CryptoWrapper { - key: Key, -} - -impl CryptoWrapper { - /// Generate a new memory wrapper - pub fn new_random() -> Self { - Self { - key: Aes256Gcm::generate_key(&mut OsRng), - } - } - - /// Encrypt some data - pub fn encrypt(&self, data: &T) -> Res { - let aes_key = Aes256Gcm::new(&self.key); - let nonce_bytes = rand::thread_rng().gen::<[u8; NONCE_LEN]>(); - - let serialized_data = bincode::encode_to_vec(data, bincode::config::standard())?; - - let mut enc = aes_key - .encrypt(Nonce::from_slice(&nonce_bytes), serialized_data.as_slice()) - .unwrap(); - enc.extend_from_slice(&nonce_bytes); - - Ok(BASE64_STANDARD.encode(enc)) - } - - /// Decrypt some data previously encrypted using the [`CryptoWrapper::encrypt`] method - pub fn decrypt(&self, input: &str) -> Res { - let bytes = BASE64_STANDARD.decode(input)?; - - if bytes.len() < NONCE_LEN { - return Err(Box::new(std::io::Error::new( - ErrorKind::Other, - "Input string is smaller than nonce!", - ))); - } - - let (enc, nonce) = bytes.split_at(bytes.len() - NONCE_LEN); - assert_eq!(nonce.len(), NONCE_LEN); - - let aes_key = Aes256Gcm::new(&self.key); - - let dec = match aes_key.decrypt(Nonce::from_slice(nonce), enc) { - Ok(d) => d, - Err(e) => { - log::error!("Failed to decrypt wrapped data! {:#?}", e); - return Err(Box::new(std::io::Error::new( - ErrorKind::Other, - "Failed to decrypt wrapped data!", - ))); - } - }; - - Ok(bincode::decode_from_slice(&dec, bincode::config::standard())?.0) - } -} - -#[cfg(test)] -mod test { - use crate::crypto_wrapper::CryptoWrapper; - use bincode::{Decode, Encode}; - - #[derive(Encode, Decode, Eq, PartialEq, Debug)] - struct Message(String); - - #[test] - fn encrypt_and_decrypt() { - let wrapper = CryptoWrapper::new_random(); - let msg = Message("Pierre was here".to_string()); - let enc = wrapper.encrypt(&msg).unwrap(); - let dec: Message = wrapper.decrypt(&enc).unwrap(); - - assert_eq!(dec, msg) - } - - #[test] - fn encrypt_and_decrypt_invalid() { - let wrapper_1 = CryptoWrapper::new_random(); - let wrapper_2 = CryptoWrapper::new_random(); - let msg = Message("Pierre was here".to_string()); - let enc = wrapper_1.encrypt(&msg).unwrap(); - wrapper_2.decrypt::(&enc).unwrap_err(); - } -} diff --git a/src/lib.rs b/src/lib.rs index 664e496..8a74ab8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,4 @@ use std::error::Error; pub type Res = Result>; pub mod app_config; -pub mod crypto_wrapper; pub mod remote_ip; -pub mod state_manager; -pub mod time_utils; diff --git a/src/main.rs b/src/main.rs index 150b4f6..3b10045 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ use actix_web::middleware::Logger; use actix_web::{get, web, App, HttpResponse, HttpServer}; use askama::Template; +use light_openid::basic_state_manager::BasicStateManager; use light_openid::primitives::OpenIDConfig; use oidc_test_client::app_config::AppConfig; use oidc_test_client::remote_ip::RemoteIP; -use oidc_test_client::state_manager::StateManager; #[get("/assets/bootstrap.min.css")] async fn bootstrap() -> HttpResponse { @@ -60,7 +60,7 @@ async fn home() -> HttpResponse { } #[get("/start")] -async fn start(remote_ip: RemoteIP) -> HttpResponse { +async fn start(remote_ip: RemoteIP, state_manager: web::Data) -> HttpResponse { let config = match OpenIDConfig::load_from_url(&AppConfig::get().configuration_url).await { Ok(c) => c, Err(e) => { @@ -69,7 +69,7 @@ async fn start(remote_ip: RemoteIP) -> HttpResponse { } }; - let state = match StateManager::gen_state(&remote_ip) { + let state = match state_manager.gen_state(remote_ip.0) { Ok(s) => s, Err(e) => { log::error!("Failed to generate state! {:?}", e); @@ -95,9 +95,13 @@ struct RedirectQuery { } #[get("/redirect")] -async fn redirect(remote_ip: RemoteIP, query: web::Query) -> HttpResponse { +async fn redirect( + remote_ip: RemoteIP, + query: web::Query, + state_manager: web::Data, +) -> HttpResponse { // First, validate state - if let Err(e) = StateManager::validate_state(&remote_ip, &query.state) { + if let Err(e) = state_manager.validate_state(remote_ip.0, &query.state) { log::error!("Failed to validate state {}: {:?}", query.state, e); return ErrorTemplate::build("State could not be validated!"); } @@ -158,13 +162,14 @@ async fn main() -> std::io::Result<()> { env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); log::info!("Init state manager"); - StateManager::init(); + let state_manager = web::Data::new(BasicStateManager::new()); log::info!("Will listen on {}", AppConfig::get().listen_addr); - HttpServer::new(|| { + HttpServer::new(move || { App::new() .wrap(Logger::default()) + .app_data(state_manager.clone()) .service(bootstrap) .service(cover) .service(home) diff --git a/src/state_manager.rs b/src/state_manager.rs deleted file mode 100644 index b92f208..0000000 --- a/src/state_manager.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::error::Error; -use std::fmt; - -use crate::crypto_wrapper::CryptoWrapper; -use crate::remote_ip::RemoteIP; -use crate::time_utils::time; -use crate::Res; -use bincode::{Decode, Encode}; -use std::net::IpAddr; - -pub struct StateManager; - -static mut WRAPPER: Option = None; - -#[derive(Encode, Decode, Debug)] -struct State { - ip: IpAddr, - expire: u64, -} - -impl State { - pub fn new(ip: IpAddr) -> Self { - Self { - ip, - expire: time() + 15 * 60, - } - } -} - -#[derive(Debug, Copy, Clone)] -enum StateError { - InvalidIp, - Expired, -} - -impl Error for StateError {} - -impl fmt::Display for StateError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "StateManager error {:?}", self) - } -} - -impl StateManager { - pub fn init() { - unsafe { - WRAPPER = Some(CryptoWrapper::new_random()); - } - } - - /// Generate a new state - pub fn gen_state(ip: &RemoteIP) -> Res { - let state = State::new(ip.0); - - unsafe { WRAPPER.as_ref().unwrap() }.encrypt(&state) - } - - /// Validate generated state - pub fn validate_state(ip: &RemoteIP, state: &str) -> Res { - let state: State = unsafe { WRAPPER.as_ref().unwrap() }.decrypt(state)?; - - if state.ip != ip.0 { - return Err(Box::new(StateError::InvalidIp)); - } - - if state.expire < time() { - return Err(Box::new(StateError::Expired)); - } - - Ok(()) - } -} diff --git a/src/time_utils.rs b/src/time_utils.rs deleted file mode 100644 index adcccfb..0000000 --- a/src/time_utils.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::time::{SystemTime, UNIX_EPOCH}; - -/// Get current time since epoch -pub fn time() -> u64 { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() -}