Path level authentication

This commit is contained in:
Ara Sadoyan
2026-03-03 19:35:16 +01:00
parent 3afa2f209f
commit 9d986f9a28
7 changed files with 77 additions and 15 deletions

View File

@@ -57,22 +57,23 @@ fn validate(auth: &dyn AuthValidator, session: &Session) -> bool {
auth.validate(session)
}
pub fn authenticate(c: &[Arc<str>], session: &Session) -> bool {
match &*c[0] {
// pub fn authenticate(c: &[Arc<str>], session: &Session) -> bool {
pub fn authenticate(auth_type: &Arc<str>, credentials: &Arc<str>, session: &Session) -> bool {
match &*auth_type.clone() {
"basic" => {
let auth = BasicAuth(&*c[1]);
let auth = BasicAuth(&*credentials.clone());
validate(&auth, session)
}
"apikey" => {
let auth = ApiKeyAuth(&*c[1]);
let auth = ApiKeyAuth(&*credentials.clone());
validate(&auth, session)
}
"jwt" => {
let auth = JwtAuth(&*c[1]);
let auth = JwtAuth(&*credentials.clone());
validate(&auth, session)
}
_ => {
println!("Unsupported authentication mechanism : {}", c[0]);
println!("Unsupported authentication mechanism : {}", auth_type);
false
}
}

View File

@@ -70,6 +70,7 @@ async fn build_upstreams(fullist: &UpstreamsDashMap, method: &str, client: &Clie
to_https: upstream.to_https,
rate_limit: upstream.rate_limit,
healthcheck: upstream.healthcheck,
authorization: upstream.authorization.clone(),
};
if scheme.healthcheck.unwrap_or(true) {

View File

@@ -35,6 +35,7 @@ pub async fn for_consul(url: String, token: Option<String>, conf: &ServiceMappin
to_https: conf.to_https.unwrap_or(false),
rate_limit: conf.rate_limit,
healthcheck: None,
authorization: None,
});
inner_vec.push(to_add);
}
@@ -68,6 +69,7 @@ pub async fn for_kuber(url: &str, token: &str, conf: &ServiceMapping) -> Option<
to_https: conf.to_https.unwrap_or(false),
rate_limit: conf.rate_limit,
healthcheck: None,
authorization: None,
});
inner_vec.push(to_add);
}

View File

@@ -34,7 +34,10 @@ pub async fn load_configuration(d: &str, kind: &str) -> (Option<Configuration>,
};
let parsed: Config = match serde_yaml::from_str(&yaml_data) {
Ok(cfg) => cfg,
Ok(cfg) => {
// println!("{:#?}", cfg);
cfg
}
Err(e) => {
error!("Failed to parse upstreams file: {}", e);
return (None, e.to_string());
@@ -97,6 +100,7 @@ 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();
@@ -107,6 +111,7 @@ async fn populate_headers_and_auth(config: &mut Configuration, parsed: &Config)
} else {
config.extraparams.authentication = DashMap::new();
}
// ======================================================================================== //
}
async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
@@ -126,9 +131,17 @@ async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
build_headers(&path_config.server_headers, config, &mut sl);
client_header_list.insert(Arc::from(path.as_str()), hl);
server_header_list.insert(Arc::from(path.as_str()), sl);
let mut server_list = Vec::new();
for server in &path_config.servers {
let mut path_auth: Option<Arc<InnerAuth>> = None;
if let Some(pa) = &path_config.authorization {
let y: InnerAuth = InnerAuth {
auth_type: Arc::from(pa.auth_type.clone()),
auth_cred: Arc::from(pa.auth_cred.clone()),
};
path_auth = Some(Arc::from(y));
}
if let Some((ip, port_str)) = server.split_once(':') {
if let Ok(port) = port_str.parse::<u16>() {
server_list.push(Arc::from(InnerMap {
@@ -139,6 +152,7 @@ async fn populate_file_upstreams(config: &mut Configuration, parsed: &Config) {
to_https: path_config.to_https.unwrap_or(false),
rate_limit: path_config.rate_limit,
healthcheck: path_config.healthcheck,
authorization: path_auth,
}));
}
}

View File

@@ -14,6 +14,7 @@ pub struct Extraparams {
pub to_https: Option<bool>,
pub sticky_sessions: bool,
pub authentication: DashMap<Arc<str>, Vec<Arc<str>>>,
// pub authentication: InnerAuth,
pub rate_limit: Option<isize>,
}
@@ -70,7 +71,13 @@ pub struct HostConfig {
pub paths: HashMap<String, PathConfig>,
pub rate_limit: Option<isize>,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Auth {
#[serde(rename = "type")]
pub auth_type: String,
#[serde(rename = "creds")]
pub auth_cred: String,
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct PathConfig {
pub servers: Vec<String>,
@@ -80,6 +87,8 @@ pub struct PathConfig {
pub server_headers: Option<Vec<String>>,
pub rate_limit: Option<isize>,
pub healthcheck: Option<bool>,
// pub authorization: Option<HashMap<String, String>>,
pub authorization: Option<Auth>,
}
#[derive(Debug, Default)]
pub struct Configuration {
@@ -116,7 +125,13 @@ pub struct AppConfig {
pub rungroup: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct InnerAuth {
pub auth_type: Arc<str>,
pub auth_cred: Arc<str>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InnerMap {
pub address: Arc<str>,
pub port: u16,
@@ -125,6 +140,8 @@ pub struct InnerMap {
pub to_https: bool,
pub rate_limit: Option<isize>,
pub healthcheck: Option<bool>,
// pub authorization: Option<DashMap<Arc<str>, Arc<str>>>,
pub authorization: Option<Arc<InnerAuth>>,
}
#[allow(dead_code)]
@@ -139,6 +156,7 @@ impl InnerMap {
to_https: Default::default(),
rate_limit: Default::default(),
healthcheck: Default::default(),
authorization: Default::default(),
}
}
}

View File

@@ -124,11 +124,23 @@ pub fn compare_dashmaps(map1: &UpstreamsDashMap, map2: &UpstreamsDashMap) -> boo
return false; // Path exists in map1 but not in map2
};
let (vec2, _counter2) = entry2.value();
let set1: HashSet<_> = vec1.iter().collect();
let set2: HashSet<_> = vec2.iter().collect();
if set1 != set2 {
if vec1.len() != vec2.len() {
return false;
}
for item in vec1.iter() {
let count1 = vec1.iter().filter(|&x| x == item).count();
let count2 = vec2.iter().filter(|&x| x == item).count();
if count1 != count2 {
return false;
}
}
// let set1: HashSet<_> = vec1.iter().collect();
// let set2: HashSet<_> = vec2.iter().collect();
// if set1 != set2 {
// return false;
// }
}
}
true
@@ -168,6 +180,7 @@ pub fn clone_idmap_into(original: &UpstreamsDashMap, cloned: &UpstreamsIdMap) {
to_https: false,
rate_limit: None,
healthcheck: None,
authorization: None,
};
cloned.insert(id, Arc::from(to_add));