use std::collections::HashSet;
use crate::migration::alc::acl_config::AclConfig;
use crate::AuthFailureKind;
use crate::AuthOperation;
use crate::AuthServiceError;
use crate::AuthServiceResult;
pub fn validate_acl_config(config: &AclConfig) -> AuthServiceResult<()> {
let Some(accounts) = config.plain_access_configs() else {
return Ok(());
};
let mut seen_access_keys = HashSet::new();
for account in accounts {
let access_key = account
.access_key()
.map(|value| value.as_str().trim())
.filter(|value| !value.is_empty())
.ok_or_else(|| invalid_acl_config("accessKey must not be blank", "<missing>"))?;
if !seen_access_keys.insert(access_key.to_owned()) {
return Err(invalid_acl_config("duplicate accessKey", access_key));
}
account
.secret_key()
.map(|value| value.as_str().trim())
.filter(|value| !value.is_empty())
.ok_or_else(|| invalid_acl_config("secretKey must not be blank", access_key))?;
}
Ok(())
}
fn invalid_acl_config(_reason: &'static str, _account: &str) -> AuthServiceError {
AuthServiceError::new(AuthOperation::Initialize, AuthFailureKind::InvalidConfiguration)
}
#[cfg(test)]
mod tests {
use cheetah_string::CheetahString;
use super::*;
use crate::migration::alc::plain_access_config::PlainAccessConfig;
#[test]
fn validates_empty_config() {
validate_acl_config(&AclConfig::new()).unwrap();
}
#[test]
fn rejects_missing_access_key() {
let mut account = PlainAccessConfig::new();
account.set_secret_key(CheetahString::from("sk"));
let mut config = AclConfig::new();
config.set_plain_access_configs(vec![account]);
let error = validate_acl_config(&config).unwrap_err();
assert_eq!(error.kind(), AuthFailureKind::InvalidConfiguration);
}
#[test]
fn rejects_missing_secret_key_without_leaking_secret() {
let mut account = PlainAccessConfig::new();
account.set_access_key(CheetahString::from("ak"));
let mut config = AclConfig::new();
config.set_plain_access_configs(vec![account]);
let error = validate_acl_config(&config).unwrap_err();
assert_eq!(error.kind(), AuthFailureKind::InvalidConfiguration);
assert!(!error.to_string().contains("secret="));
}
#[test]
fn rejects_duplicate_access_keys() {
let mut first = PlainAccessConfig::new();
first.set_access_key(CheetahString::from("ak"));
first.set_secret_key(CheetahString::from("sk1"));
let mut second = PlainAccessConfig::new();
second.set_access_key(CheetahString::from("ak"));
second.set_secret_key(CheetahString::from("sk2"));
let mut config = AclConfig::new();
config.set_plain_access_configs(vec![first, second]);
let error = validate_acl_config(&config).unwrap_err();
assert_eq!(error.kind(), AuthFailureKind::InvalidConfiguration);
}
}