use crate::{AuthProvider, Result};
use async_trait::async_trait;
use secrecy::{ExposeSecret, SecretString};
use tracing::instrument;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ApiKeyTier {
Content,
Features,
Location,
Public,
}
pub struct ApiKeyAuth {
api_key: SecretString,
}
impl ApiKeyAuth {
#[instrument(skip(api_key))]
pub fn new(api_key: impl Into<String>) -> Self {
tracing::debug!("Creating API Key authentication provider");
Self {
api_key: SecretString::new(api_key.into().into_boxed_str()),
}
}
#[instrument]
pub fn from_env(tier: ApiKeyTier) -> Result<Self> {
tracing::debug!("Loading API key from environment: {:?}", tier);
let config = crate::EnvConfig::global();
let (api_key, key_name) = match tier {
ApiKeyTier::Content => (config.arcgis_content_key.as_ref(), "ARCGIS_CONTENT_KEY"),
ApiKeyTier::Features => (config.arcgis_features_key.as_ref(), "ARCGIS_FEATURES_KEY"),
ApiKeyTier::Location => (config.arcgis_location_key.as_ref(), "ARCGIS_LOCATION_KEY"),
ApiKeyTier::Public => (config.arcgis_public_key.as_ref(), "ARCGIS_PUBLIC_KEY"),
};
let api_key = api_key.or(config.arcgis_api_key.as_ref()).ok_or_else(|| {
tracing::error!(
"No API key found in environment. Set {} or ARCGIS_API_KEY",
key_name
);
crate::Error::from(crate::ErrorKind::Env(crate::EnvError::new(
std::env::VarError::NotPresent,
)))
})?;
tracing::debug!("Successfully loaded API key from environment: {}", key_name);
Ok(Self::new(api_key.expose_secret().to_string()))
}
#[instrument]
pub fn agol(tier: ApiKeyTier) -> Result<Self> {
Self::from_env(tier)
}
#[instrument]
pub fn enterprise() -> Result<Self> {
tracing::debug!("Loading Enterprise API key from environment");
let config = crate::EnvConfig::global();
let api_key = config.arcgis_enterprise_key.as_ref().ok_or_else(|| {
tracing::error!("ARCGIS_ENTERPRISE_KEY not found in environment");
crate::Error::from(crate::ErrorKind::Env(crate::EnvError::new(
std::env::VarError::NotPresent,
)))
})?;
tracing::debug!("Successfully loaded Enterprise API key");
Ok(Self::new(api_key.expose_secret().to_string()))
}
}
#[async_trait]
impl AuthProvider for ApiKeyAuth {
#[instrument(skip(self))]
async fn get_token(&self) -> Result<String> {
tracing::debug!("Retrieving API key token");
Ok(self.api_key.expose_secret().to_string())
}
#[instrument(skip(self))]
fn requires_token_param(&self) -> bool {
true
}
}