From d5eee04d7ac6430719b6c9ed1549befa8a35f9f1 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 10 Apr 2024 21:22:15 +0200 Subject: [PATCH] Can block token unauthorized to access a specific route --- virtweb_backend/src/api_tokens.rs | 31 ++++++++++++------- .../src/extractors/api_auth_extractor.rs | 15 +++++++-- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/virtweb_backend/src/api_tokens.rs b/virtweb_backend/src/api_tokens.rs index c2955d7..de2591c 100644 --- a/virtweb_backend/src/api_tokens.rs +++ b/virtweb_backend/src/api_tokens.rs @@ -19,7 +19,7 @@ impl TokenID { } } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)] pub struct TokenRight { verb: TokenVerb, path: String, @@ -28,6 +28,24 @@ pub struct TokenRight { #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct TokenRights(Vec); +impl TokenRights { + pub fn check_error(&self) -> Option<&'static str> { + for r in &self.0 { + if !r.path.starts_with("/api/") { + return Some("All API rights shall start with /api/"); + } + } + None + } + + pub fn contains(&self, verb: TokenVerb, path: &str) -> bool { + self.0.contains(&TokenRight { + verb, + path: path.to_string(), + }) + } +} + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct Token { pub id: TokenID, @@ -121,17 +139,6 @@ pub struct NewToken { pub delete_after_inactivity: Option, } -impl TokenRights { - pub fn check_error(&self) -> Option<&'static str> { - for r in &self.0 { - if !r.path.starts_with("/api/") { - return Some("All API rights shall start with /api/"); - } - } - None - } -} - impl NewToken { /// Check for error in token pub fn check_error(&self) -> Option<&'static str> { diff --git a/virtweb_backend/src/extractors/api_auth_extractor.rs b/virtweb_backend/src/extractors/api_auth_extractor.rs index 604e2e4..0f22043 100644 --- a/virtweb_backend/src/extractors/api_auth_extractor.rs +++ b/virtweb_backend/src/extractors/api_auth_extractor.rs @@ -4,7 +4,7 @@ use crate::api_tokens; use crate::utils::jwt_utils; use crate::utils::time_utils::time; use actix_web::dev::Payload; -use actix_web::error::ErrorBadRequest; +use actix_web::error::{ErrorBadRequest, ErrorUnauthorized}; use actix_web::{Error, FromRequest, HttpRequest}; use std::future::Future; use std::pin::Pin; @@ -108,7 +108,16 @@ impl FromRequest for ApiAuthExtractor { return Err(ErrorBadRequest("JWT method mismatch!")); } - // TODO : check if route is authorized with token + if !token.rights.contains(claims.verb, req.path()) { + log::error!( + "Attempt to use a token for an unauthorized route! (token_id={})", + token.id.0 + ); + return Err(ErrorUnauthorized( + "Token cannot be used to query this route!", + )); + } + // TODO : check for ip restriction // TODO : manually validate all checks @@ -116,7 +125,7 @@ impl FromRequest for ApiAuthExtractor { if token.should_update_last_activity() { if let Err(e) = api_tokens::refresh_last_used(token.id).await { log::error!("Could not update token last activity! {e}"); - return Err(ErrorBadRequest("!")); + return Err(ErrorBadRequest("Couldn't refresh token last activity!")); } }