From 48f24e6ca1d05fa1c960ac35a5b16f5ad9511b8d Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Thu, 25 Apr 2024 18:51:42 +0200 Subject: [PATCH] Managed to query VirtWeb API --- remote_backend/Cargo.lock | 13 +++++ remote_backend/Cargo.toml | 6 ++- remote_backend/src/app_config.rs | 10 +++- remote_backend/src/lib.rs | 2 + remote_backend/src/main.rs | 3 ++ remote_backend/src/utils.rs | 14 ++++++ remote_backend/src/virtweb_client.rs | 71 ++++++++++++++++++++++++++++ 7 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 remote_backend/src/utils.rs create mode 100644 remote_backend/src/virtweb_client.rs diff --git a/remote_backend/Cargo.lock b/remote_backend/Cargo.lock index a82bebe..e41ffd8 100644 --- a/remote_backend/Cargo.lock +++ b/remote_backend/Cargo.lock @@ -1648,13 +1648,17 @@ version = "0.1.0" dependencies = [ "actix-remote-ip", "actix-web", + "anyhow", "basic-jwt", "clap", "env_logger", "lazy_static", "light-openid", "log", + "reqwest", "serde", + "thiserror", + "uuid", ] [[package]] @@ -2269,6 +2273,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/remote_backend/Cargo.toml b/remote_backend/Cargo.toml index 3c1705f..95f5f3f 100644 --- a/remote_backend/Cargo.toml +++ b/remote_backend/Cargo.toml @@ -14,4 +14,8 @@ light-openid = { version = "1.0.2", features = ["crypto-wrapper"] } basic-jwt = "0.2.0" actix-remote-ip = "0.1.0" lazy_static = "1.4.0" -actix-web = "4.5.1" \ No newline at end of file +actix-web = "4.5.1" +anyhow = "1.0.82" +reqwest = { version = "0.12.4", features = ["json"] } +thiserror = "1.0.59" +uuid = { version = "1.8.0", features = ["v4"] } \ No newline at end of file diff --git a/remote_backend/src/app_config.rs b/remote_backend/src/app_config.rs index ad59dfe..ad37e95 100644 --- a/remote_backend/src/app_config.rs +++ b/remote_backend/src/app_config.rs @@ -1,3 +1,4 @@ +use basic_jwt::JWTPrivateKey; use clap::Parser; /// VirtWeb backend API @@ -58,7 +59,7 @@ pub struct AppConfig { /// VirtWeb API token private key #[arg(long, env)] - pub virtweb_token_private_key: String, + virtweb_token_private_key: String, } lazy_static::lazy_static! { @@ -119,6 +120,13 @@ impl AppConfig { self.oidc_redirect_url .replace("APP_ORIGIN", &self.website_origin) } + + /// Get VirtWeb token private key + pub fn token_private_key(&self) -> JWTPrivateKey { + JWTPrivateKey::ES384 { + r#priv: self.virtweb_token_private_key.to_string(), + } + } } #[derive(Debug, Clone, serde::Serialize)] diff --git a/remote_backend/src/lib.rs b/remote_backend/src/lib.rs index 62a6f82..b8a566c 100644 --- a/remote_backend/src/lib.rs +++ b/remote_backend/src/lib.rs @@ -1 +1,3 @@ pub mod app_config; +pub mod utils; +pub mod virtweb_client; diff --git a/remote_backend/src/main.rs b/remote_backend/src/main.rs index 985854a..084904d 100644 --- a/remote_backend/src/main.rs +++ b/remote_backend/src/main.rs @@ -4,6 +4,7 @@ use actix_web::web::Data; use actix_web::{App, HttpServer}; use light_openid::basic_state_manager::BasicStateManager; use remote_backend::app_config::AppConfig; +use remote_backend::virtweb_client; #[actix_web::main] async fn main() -> std::io::Result<()> { @@ -11,6 +12,8 @@ async fn main() -> std::io::Result<()> { let state_manager = Data::new(BasicStateManager::new()); + println!("{:#?}", virtweb_client::get_token_rights().await.unwrap()); + HttpServer::new(move || { App::new() .wrap(Logger::default()) diff --git a/remote_backend/src/utils.rs b/remote_backend/src/utils.rs new file mode 100644 index 0000000..9435e8f --- /dev/null +++ b/remote_backend/src/utils.rs @@ -0,0 +1,14 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + +/// Get the current time since epoch +/// +/// ``` +/// use remote_backend::utils::time; +/// let time = time(); +/// ``` +pub fn time() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() +} diff --git a/remote_backend/src/virtweb_client.rs b/remote_backend/src/virtweb_client.rs new file mode 100644 index 0000000..c8378e1 --- /dev/null +++ b/remote_backend/src/virtweb_client.rs @@ -0,0 +1,71 @@ +use crate::app_config::AppConfig; +use crate::utils::time; +use std::fmt::Display; +use thiserror::Error; +use uuid::Uuid; + +#[derive(Error, Debug)] +pub enum VirtWebClientError { + #[error("Invalid status code from VirtWeb: {0}")] + InvalidStatusCode(u16), +} + +#[derive(serde::Serialize, Debug)] +pub struct TokenClaims { + pub sub: String, + pub iat: u64, + pub exp: u64, + pub verb: String, + pub path: String, + pub nonce: String, +} + +#[derive(serde::Deserialize, Debug)] +pub struct TokenRight { + verb: String, + path: String, +} + +pub type TokenRights = Vec; + +#[derive(serde::Deserialize)] +struct TokenInfo { + rights: TokenRights, +} + +/// Perform a request on the API +async fn request(uri: D) -> anyhow::Result { + let url = format!("{}{}", AppConfig::get().virtweb_base_url, uri); + log::debug!("Will query {uri}..."); + + let jwt = TokenClaims { + sub: AppConfig::get().virtweb_token_id.to_string(), + iat: time() - 60 * 2, + exp: time() + 60 * 3, + verb: "GET".to_string(), + path: uri.to_string(), + nonce: Uuid::new_v4().to_string(), + }; + let jwt = AppConfig::get().token_private_key().sign_jwt(&jwt)?; + + let res = reqwest::Client::new() + .get(url) + .header("x-token-id", &AppConfig::get().virtweb_token_id) + .header("x-token-content", jwt) + .send() + .await?; + + if !res.status().is_success() { + return Err(VirtWebClientError::InvalidStatusCode(res.status().as_u16()).into()); + } + + Ok(res.json().await?) +} + +/// Get current token rights +pub async fn get_token_rights() -> anyhow::Result { + let res: TokenInfo = + request(format!("/api/token/{}", AppConfig::get().virtweb_token_id)).await?; + + Ok(res.rights) +}