From 94b1f777343b9411cbb56e265f6da2f1a51e8bd0 Mon Sep 17 00:00:00 2001 From: Ara Sadoyan Date: Wed, 4 Mar 2026 12:35:45 +0100 Subject: [PATCH] Type changes, auth override policy --- Cargo.lock | 1 + Cargo.toml | 1 + src/utils/parceyaml.rs | 25 +++++--------------- src/utils/structs.rs | 8 ++----- src/web/proxyhttp.rs | 53 +++++++++++++++++++++--------------------- src/web/start.rs | 2 +- 6 files changed, 37 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b603479..576160b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,6 +130,7 @@ dependencies = [ "env_logger", "futures", "http", + "itoa", "jsonwebtoken", "lazy_static", "log", diff --git a/Cargo.toml b/Cargo.toml index c33647d..b4c60ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,3 +50,4 @@ ctrlc = "3.5.2" port_check = "0.3.0" serde_json = "1.0.149" http = "1.4.0" +itoa = "1.0.14" diff --git a/src/utils/parceyaml.rs b/src/utils/parceyaml.rs index ae9359d..4a5b650 100644 --- a/src/utils/parceyaml.rs +++ b/src/utils/parceyaml.rs @@ -8,7 +8,6 @@ use std::collections::HashMap; use std::sync::atomic::AtomicUsize; use std::sync::Arc; use std::{env, fs}; -// use tokio::sync::oneshot::{Receiver, Sender}; pub async fn load_configuration(d: &str, kind: &str) -> (Option, String) { let yaml_data = match kind { @@ -100,18 +99,13 @@ async fn populate_headers_and_auth(config: &mut Configuration, parsed: &Config) info!("Applied Global Rate Limit : {} request per second", rate); } - // ======================================================================================== // - if let Some(auth) = &parsed.authorization { - let name = auth.get("type").unwrap_or(&"".to_string()).to_string(); - let creds = auth.get("creds").unwrap_or(&"".to_string()).to_string(); - config - .extraparams - .authentication - .insert(Arc::from("authorization"), vec![Arc::from(name), Arc::from(creds)]); - } else { - config.extraparams.authentication = DashMap::new(); + if let Some(pa) = &parsed.authorization { + let y: InnerAuth = InnerAuth { + auth_type: Arc::from(pa.auth_type.clone()), + auth_cred: Arc::from(pa.auth_cred.clone()), + }; + config.extraparams.authentication = Some(y); } - // ======================================================================================== // } async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) { @@ -255,12 +249,5 @@ pub fn build_headers(path_config: &Option>, _config: &Configuration, hl.push((Arc::from(key.trim()), Arc::from(val.trim()))); } } - // if let Some(push) = config.client_headers.get("GLOBAL_HEADERS") { - // for k in push.iter() { - // for x in k.value() { - // hl.push(x.to_owned()); - // } - // } - // } } } diff --git a/src/utils/structs.rs b/src/utils/structs.rs index 6d83c07..73bbf7e 100644 --- a/src/utils/structs.rs +++ b/src/utils/structs.rs @@ -13,8 +13,7 @@ pub type Headers = DashMap, DashMap, Vec<(Arc, Arc)> pub struct Extraparams { pub to_https: Option, pub sticky_sessions: bool, - pub authentication: DashMap, Vec>>, - // pub authentication: InnerAuth, + pub authentication: Option, pub rate_limit: Option, } @@ -57,7 +56,7 @@ pub struct Config { #[serde(default)] pub server_headers: Option>, #[serde(default)] - pub authorization: Option>, + pub authorization: Option, #[serde(default)] pub consul: Option, #[serde(default)] @@ -87,7 +86,6 @@ pub struct PathConfig { pub server_headers: Option>, pub rate_limit: Option, pub healthcheck: Option, - // pub authorization: Option>, pub authorization: Option, } #[derive(Debug, Default)] @@ -140,7 +138,6 @@ pub struct InnerMap { pub to_https: bool, pub rate_limit: Option, pub healthcheck: Option, - // pub authorization: Option, Arc>>, pub authorization: Option>, } @@ -148,7 +145,6 @@ pub struct InnerMap { impl InnerMap { pub fn new() -> Self { Self { - // address: "127.0.0.1".parse().unwrap(), address: Arc::from("127.0.0.1"), port: Default::default(), is_ssl: Default::default(), diff --git a/src/web/proxyhttp.rs b/src/web/proxyhttp.rs index 93e4098..10f39d6 100644 --- a/src/web/proxyhttp.rs +++ b/src/web/proxyhttp.rs @@ -6,6 +6,8 @@ use arc_swap::ArcSwap; use async_trait::async_trait; use axum::body::Bytes; use dashmap::DashMap; +// use x509_parser::asn1_rs::ToDer; +use itoa::Buffer; use log::{debug, error, warn}; use once_cell::sync::Lazy; use pingora::http::{RequestHeader, ResponseHeader, StatusCode}; @@ -23,7 +25,6 @@ use std::fmt::Write; use std::sync::Arc; use std::time::Duration; use tokio::time::Instant; -// use x509_parser::asn1_rs::ToDer; static RATE_LIMITER: Lazy = Lazy::new(|| Rate::new(Duration::from_secs(1))); static REVERSE_STORE: Lazy> = Lazy::new(|| DashMap::new()); @@ -69,33 +70,26 @@ impl ProxyHttp for LB { } } async fn request_filter(&self, session: &mut Session, _ctx: &mut Self::CTX) -> Result { - let ep = _ctx.extraparams.as_ref(); - - // ======================================================================================== // - println!("{:?}", ep); - if let Some(auth) = ep.authentication.get("authorization") { - let authenticated = authenticate(&auth.value()[0], &auth.value()[1], &session); + // let ep = _ctx.extraparams.as_ref(); + if let Some(auth) = &_ctx.extraparams.authentication { + let authenticated = authenticate(&auth.auth_type, &auth.auth_cred, &session); if !authenticated { let _ = session.respond_error(401).await; warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path()); return Ok(true); } - }; - // ======================================================================================== // - + } let hostname = return_header_host_from_upstream(session, &self.ump_upst); _ctx.hostname = hostname; let mut backend_id = None; - if ep.sticky_sessions { + if _ctx.extraparams.sticky_sessions { if let Some(cookies) = session.req_header().headers.get("cookie") { if let Ok(cookie_str) = cookies.to_str() { - for cookie in cookie_str.split(';') { - let trimmed = cookie.trim(); - if let Some(value) = trimmed.strip_prefix("backend_id=") { - backend_id = Some(value); - break; - } + if let Some(pos) = cookie_str.find("backend_id=") { + let value = &cookie_str[pos + "backend_id=".len()..]; + let end = value.find(';').unwrap_or(value.len()); + backend_id = Some(&value[..end]); } } } @@ -108,23 +102,28 @@ impl ProxyHttp for LB { match optioninnermap { None => return Ok(false), Some(ref innermap) => { + // Inner auth works only if global is disabled. if let Some(auth) = &innermap.authorization { - let authenticated = authenticate(&auth.auth_type, &auth.auth_cred, &session); - if !authenticated { - let _ = session.respond_error(401).await; - warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path()); - return Ok(true); + if _ctx.extraparams.authentication.is_none() { + let authenticated = authenticate(&auth.auth_type, &auth.auth_cred, &session); + if !authenticated { + let _ = session.respond_error(401).await; + warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path()); + return Ok(true); + } } } - if let Some(rate) = innermap.rate_limit.or(ep.rate_limit) { + if let Some(rate) = innermap.rate_limit.or(_ctx.extraparams.rate_limit) { let rate_key = session.client_addr().and_then(|addr| addr.as_inet()).map(|inet| inet.ip()); let curr_window_requests = RATE_LIMITER.observe(&rate_key, 1); if curr_window_requests > rate { - let mut header = ResponseHeader::build(429, None).unwrap(); - header.insert_header("X-Rate-Limit-Limit", rate.to_string()).unwrap(); - header.insert_header("X-Rate-Limit-Remaining", "0").unwrap(); - header.insert_header("X-Rate-Limit-Reset", "1").unwrap(); + let mut buf = Buffer::new(); + let rate_str = buf.format(rate); + let mut header = ResponseHeader::build(429, None)?; + header.insert_header("X-Rate-Limit-Limit", rate_str)?; + header.insert_header("X-Rate-Limit-Remaining", "0")?; + header.insert_header("X-Rate-Limit-Reset", "1")?; session.set_keepalive(None); session.write_response_header(Box::new(header), true).await?; debug!("Rate limited: {:?}, {}", rate_key, rate); diff --git a/src/web/start.rs b/src/web/start.rs index 8f0ae41..833882a 100644 --- a/src/web/start.rs +++ b/src/web/start.rs @@ -33,7 +33,7 @@ pub fn run() { let ec_config = Arc::new(ArcSwap::from_pointee(Extraparams { to_https: None, sticky_sessions: false, - authentication: DashMap::new(), + authentication: None, rate_limit: None, }));