mirror of
https://github.com/sadoyan/aralez.git
synced 2026-04-30 23:08:40 +08:00
Type changes, auth override policy
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -130,6 +130,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
"http",
|
"http",
|
||||||
|
"itoa",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
@@ -50,3 +50,4 @@ ctrlc = "3.5.2"
|
|||||||
port_check = "0.3.0"
|
port_check = "0.3.0"
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
http = "1.4.0"
|
http = "1.4.0"
|
||||||
|
itoa = "1.0.14"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use std::collections::HashMap;
|
|||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
// use tokio::sync::oneshot::{Receiver, Sender};
|
|
||||||
|
|
||||||
pub async fn load_configuration(d: &str, kind: &str) -> (Option<Configuration>, String) {
|
pub async fn load_configuration(d: &str, kind: &str) -> (Option<Configuration>, String) {
|
||||||
let yaml_data = match kind {
|
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);
|
info!("Applied Global Rate Limit : {} request per second", rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================================================== //
|
if let Some(pa) = &parsed.authorization {
|
||||||
if let Some(auth) = &parsed.authorization {
|
let y: InnerAuth = InnerAuth {
|
||||||
let name = auth.get("type").unwrap_or(&"".to_string()).to_string();
|
auth_type: Arc::from(pa.auth_type.clone()),
|
||||||
let creds = auth.get("creds").unwrap_or(&"".to_string()).to_string();
|
auth_cred: Arc::from(pa.auth_cred.clone()),
|
||||||
config
|
};
|
||||||
.extraparams
|
config.extraparams.authentication = Some(y);
|
||||||
.authentication
|
|
||||||
.insert(Arc::from("authorization"), vec![Arc::from(name), Arc::from(creds)]);
|
|
||||||
} else {
|
|
||||||
config.extraparams.authentication = DashMap::new();
|
|
||||||
}
|
}
|
||||||
// ======================================================================================== //
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
|
async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
|
||||||
@@ -255,12 +249,5 @@ pub fn build_headers(path_config: &Option<Vec<String>>, _config: &Configuration,
|
|||||||
hl.push((Arc::from(key.trim()), Arc::from(val.trim())));
|
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());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ pub type Headers = DashMap<Arc<str>, DashMap<Arc<str>, Vec<(Arc<str>, Arc<str>)>
|
|||||||
pub struct Extraparams {
|
pub struct Extraparams {
|
||||||
pub to_https: Option<bool>,
|
pub to_https: Option<bool>,
|
||||||
pub sticky_sessions: bool,
|
pub sticky_sessions: bool,
|
||||||
pub authentication: DashMap<Arc<str>, Vec<Arc<str>>>,
|
pub authentication: Option<InnerAuth>,
|
||||||
// pub authentication: InnerAuth,
|
|
||||||
pub rate_limit: Option<isize>,
|
pub rate_limit: Option<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ pub struct Config {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub server_headers: Option<Vec<String>>,
|
pub server_headers: Option<Vec<String>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub authorization: Option<HashMap<String, String>>,
|
pub authorization: Option<Auth>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub consul: Option<Consul>,
|
pub consul: Option<Consul>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -87,7 +86,6 @@ pub struct PathConfig {
|
|||||||
pub server_headers: Option<Vec<String>>,
|
pub server_headers: Option<Vec<String>>,
|
||||||
pub rate_limit: Option<isize>,
|
pub rate_limit: Option<isize>,
|
||||||
pub healthcheck: Option<bool>,
|
pub healthcheck: Option<bool>,
|
||||||
// pub authorization: Option<HashMap<String, String>>,
|
|
||||||
pub authorization: Option<Auth>,
|
pub authorization: Option<Auth>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@@ -140,7 +138,6 @@ pub struct InnerMap {
|
|||||||
pub to_https: bool,
|
pub to_https: bool,
|
||||||
pub rate_limit: Option<isize>,
|
pub rate_limit: Option<isize>,
|
||||||
pub healthcheck: Option<bool>,
|
pub healthcheck: Option<bool>,
|
||||||
// pub authorization: Option<DashMap<Arc<str>, Arc<str>>>,
|
|
||||||
pub authorization: Option<Arc<InnerAuth>>,
|
pub authorization: Option<Arc<InnerAuth>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +145,6 @@ pub struct InnerMap {
|
|||||||
impl InnerMap {
|
impl InnerMap {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
// address: "127.0.0.1".parse().unwrap(),
|
|
||||||
address: Arc::from("127.0.0.1"),
|
address: Arc::from("127.0.0.1"),
|
||||||
port: Default::default(),
|
port: Default::default(),
|
||||||
is_ssl: Default::default(),
|
is_ssl: Default::default(),
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use arc_swap::ArcSwap;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use axum::body::Bytes;
|
use axum::body::Bytes;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
|
// use x509_parser::asn1_rs::ToDer;
|
||||||
|
use itoa::Buffer;
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use pingora::http::{RequestHeader, ResponseHeader, StatusCode};
|
use pingora::http::{RequestHeader, ResponseHeader, StatusCode};
|
||||||
@@ -23,7 +25,6 @@ use std::fmt::Write;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
// use x509_parser::asn1_rs::ToDer;
|
|
||||||
|
|
||||||
static RATE_LIMITER: Lazy<Rate> = Lazy::new(|| Rate::new(Duration::from_secs(1)));
|
static RATE_LIMITER: Lazy<Rate> = Lazy::new(|| Rate::new(Duration::from_secs(1)));
|
||||||
static REVERSE_STORE: Lazy<DashMap<String, String>> = Lazy::new(|| DashMap::new());
|
static REVERSE_STORE: Lazy<DashMap<String, String>> = 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<bool> {
|
async fn request_filter(&self, session: &mut Session, _ctx: &mut Self::CTX) -> Result<bool> {
|
||||||
let ep = _ctx.extraparams.as_ref();
|
// let ep = _ctx.extraparams.as_ref();
|
||||||
|
if let Some(auth) = &_ctx.extraparams.authentication {
|
||||||
// ======================================================================================== //
|
let authenticated = authenticate(&auth.auth_type, &auth.auth_cred, &session);
|
||||||
println!("{:?}", ep);
|
|
||||||
if let Some(auth) = ep.authentication.get("authorization") {
|
|
||||||
let authenticated = authenticate(&auth.value()[0], &auth.value()[1], &session);
|
|
||||||
if !authenticated {
|
if !authenticated {
|
||||||
let _ = session.respond_error(401).await;
|
let _ = session.respond_error(401).await;
|
||||||
warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path());
|
warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path());
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
// ======================================================================================== //
|
|
||||||
|
|
||||||
let hostname = return_header_host_from_upstream(session, &self.ump_upst);
|
let hostname = return_header_host_from_upstream(session, &self.ump_upst);
|
||||||
_ctx.hostname = hostname;
|
_ctx.hostname = hostname;
|
||||||
let mut backend_id = None;
|
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 Some(cookies) = session.req_header().headers.get("cookie") {
|
||||||
if let Ok(cookie_str) = cookies.to_str() {
|
if let Ok(cookie_str) = cookies.to_str() {
|
||||||
for cookie in cookie_str.split(';') {
|
if let Some(pos) = cookie_str.find("backend_id=") {
|
||||||
let trimmed = cookie.trim();
|
let value = &cookie_str[pos + "backend_id=".len()..];
|
||||||
if let Some(value) = trimmed.strip_prefix("backend_id=") {
|
let end = value.find(';').unwrap_or(value.len());
|
||||||
backend_id = Some(value);
|
backend_id = Some(&value[..end]);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,23 +102,28 @@ impl ProxyHttp for LB {
|
|||||||
match optioninnermap {
|
match optioninnermap {
|
||||||
None => return Ok(false),
|
None => return Ok(false),
|
||||||
Some(ref innermap) => {
|
Some(ref innermap) => {
|
||||||
|
// Inner auth works only if global is disabled.
|
||||||
if let Some(auth) = &innermap.authorization {
|
if let Some(auth) = &innermap.authorization {
|
||||||
let authenticated = authenticate(&auth.auth_type, &auth.auth_cred, &session);
|
if _ctx.extraparams.authentication.is_none() {
|
||||||
if !authenticated {
|
let authenticated = authenticate(&auth.auth_type, &auth.auth_cred, &session);
|
||||||
let _ = session.respond_error(401).await;
|
if !authenticated {
|
||||||
warn!("Forbidden: {:?}, {}", session.client_addr(), session.req_header().uri.path());
|
let _ = session.respond_error(401).await;
|
||||||
return Ok(true);
|
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 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);
|
let curr_window_requests = RATE_LIMITER.observe(&rate_key, 1);
|
||||||
if curr_window_requests > rate {
|
if curr_window_requests > rate {
|
||||||
let mut header = ResponseHeader::build(429, None).unwrap();
|
let mut buf = Buffer::new();
|
||||||
header.insert_header("X-Rate-Limit-Limit", rate.to_string()).unwrap();
|
let rate_str = buf.format(rate);
|
||||||
header.insert_header("X-Rate-Limit-Remaining", "0").unwrap();
|
let mut header = ResponseHeader::build(429, None)?;
|
||||||
header.insert_header("X-Rate-Limit-Reset", "1").unwrap();
|
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.set_keepalive(None);
|
||||||
session.write_response_header(Box::new(header), true).await?;
|
session.write_response_header(Box::new(header), true).await?;
|
||||||
debug!("Rate limited: {:?}, {}", rate_key, rate);
|
debug!("Rate limited: {:?}, {}", rate_key, rate);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ pub fn run() {
|
|||||||
let ec_config = Arc::new(ArcSwap::from_pointee(Extraparams {
|
let ec_config = Arc::new(ArcSwap::from_pointee(Extraparams {
|
||||||
to_https: None,
|
to_https: None,
|
||||||
sticky_sessions: false,
|
sticky_sessions: false,
|
||||||
authentication: DashMap::new(),
|
authentication: None,
|
||||||
rate_limit: None,
|
rate_limit: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user