use std::any::Any;
use tracing::debug;
use crate::authorization::context::default_authorization_context::DefaultAuthorizationContext;
use crate::authorization::strategy::abstract_authorization_strategy::AbstractAuthorizationStrategy;
use crate::authorization::strategy::abstract_authorization_strategy::AuthorizationFuture;
use crate::authorization::strategy::abstract_authorization_strategy::AuthorizationStrategy;
use crate::authorization::strategy::evaluate_base_authorization;
use crate::config::AuthConfig;
use crate::AuthServiceResult;
pub struct StatelessAuthorizationStrategy {
base: AbstractAuthorizationStrategy,
}
impl StatelessAuthorizationStrategy {
pub fn new(
auth_config: AuthConfig,
metadata_service: Option<Box<dyn Any + Send + Sync>>,
) -> AuthServiceResult<Self> {
let base = AbstractAuthorizationStrategy::new(auth_config, metadata_service)?;
debug!("StatelessAuthorizationStrategy initialized");
Ok(Self { base })
}
pub fn base(&self) -> &AbstractAuthorizationStrategy {
&self.base
}
}
impl AuthorizationStrategy for StatelessAuthorizationStrategy {
fn evaluate<'a>(&'a self, context: &'a DefaultAuthorizationContext) -> AuthorizationFuture<'a> {
Box::pin(async move {
debug!("Stateless authorization evaluation started");
evaluate_base_authorization(&self.base, context).await
})
}
}
#[cfg(test)]
mod tests {
use cheetah_string::CheetahString;
use super::*;
fn create_test_config() -> AuthConfig {
AuthConfig {
config_name: CheetahString::from("test"),
cluster_name: CheetahString::from("test-cluster"),
auth_config_path: CheetahString::from("/tmp/auth"),
acl_file: CheetahString::new(),
acl_file_watch_enabled: false,
acl_file_watch_interval_millis: 5_000,
authentication_enabled: false,
authentication_provider: CheetahString::new(),
authentication_metadata_provider: CheetahString::new(),
authentication_strategy: CheetahString::new(),
authentication_whitelist: CheetahString::new(),
init_authentication_user: CheetahString::new(),
inner_client_authentication_credentials: CheetahString::new(),
signature_algorithm: Default::default(),
request_timestamp_expired_millis: 0,
authorization_enabled: true,
authorization_provider: CheetahString::new(),
authorization_metadata_provider: CheetahString::new(),
authorization_strategy: CheetahString::new(),
authorization_whitelist: CheetahString::from("10,11"),
migrate_auth_from_v1_enabled: false,
user_cache_max_num: 1000,
user_cache_expired_second: 300,
user_cache_refresh_second: 60,
acl_cache_max_num: 1000,
acl_cache_expired_second: 300,
acl_cache_refresh_second: 60,
stateful_authentication_cache_max_num: 1000,
stateful_authentication_cache_expired_second: 300,
stateful_authorization_cache_max_num: 1000,
stateful_authorization_cache_expired_second: 300,
stateful_authorization_cache_negative_enable: false,
..AuthConfig::default()
}
}
#[test]
fn test_stateless_strategy_creation() {
let config = create_test_config();
let strategy = StatelessAuthorizationStrategy::new(config, None);
assert!(strategy.is_ok());
}
#[test]
fn test_stateless_strategy_whitelist() {
let config = create_test_config();
let strategy = StatelessAuthorizationStrategy::new(config, None).unwrap();
assert!(strategy.base().is_whitelisted("10"));
assert!(strategy.base().is_whitelisted("11"));
assert!(!strategy.base().is_whitelisted("12"));
}
#[tokio::test]
async fn test_stateless_evaluate_disabled() {
let mut config = create_test_config();
config.authorization_enabled = false;
let strategy = StatelessAuthorizationStrategy::new(config, None).unwrap();
let context = DefaultAuthorizationContext::default();
let result = strategy.evaluate(&context).await;
assert!(result.is_ok());
}
#[tokio::test(flavor = "current_thread")]
async fn evaluate_inside_current_thread_runtime_without_nested_block_on_panic() {
let mut config = create_test_config();
config.authorization_enabled = false;
let strategy = StatelessAuthorizationStrategy::new(config, None).unwrap();
let context = DefaultAuthorizationContext::default();
assert!(strategy.evaluate(&context).await.is_ok());
}
}