use async_trait::async_trait;
use super::super::auth_strategy::{AuthConfig, AuthStrategy, Credentials};
use super::super::errors::AuthError;
#[derive(Debug, Default)]
pub struct ApiKeyStrategy;
#[async_trait]
impl AuthStrategy for ApiKeyStrategy {
async fn authenticate(&self, config: &AuthConfig) -> anyhow::Result<Credentials> {
let api_key = config
.get("api_key")
.ok_or_else(|| AuthError::MissingCredentials("api_key".to_string()))?;
let mut credentials = Credentials::new();
credentials.insert("api_key".to_string(), api_key.clone());
Ok(credentials)
}
fn validate_credentials(&self, credentials: &Credentials) -> bool {
credentials
.get("api_key")
.is_some_and(|key| !key.is_empty())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn carries_the_configured_api_key_through() {
let strategy = ApiKeyStrategy;
let config = AuthConfig::from([("api_key".to_string(), "abc123".to_string())]);
let credentials = strategy.authenticate(&config).await.unwrap();
assert_eq!(credentials.get("api_key").unwrap(), "abc123");
}
#[tokio::test]
async fn rejects_a_config_missing_the_api_key() {
let strategy = ApiKeyStrategy;
assert!(strategy.authenticate(&AuthConfig::new()).await.is_err());
}
#[test]
fn rejects_an_empty_api_key_as_invalid() {
let strategy = ApiKeyStrategy;
let credentials = Credentials::from([("api_key".to_string(), String::new())]);
assert!(!strategy.validate_credentials(&credentials));
}
}