diff --git a/rustfs/src/auth.rs b/rustfs/src/auth.rs index 0bacf8933..dc254afa8 100644 --- a/rustfs/src/auth.rs +++ b/rustfs/src/auth.rs @@ -516,39 +516,6 @@ fn check_claims_from_token_with_context( Ok(HashMap::new()) } -/// Check for Keystone authentication headers and authenticate if present -/// Returns Some((Credentials, is_owner)) if Keystone authentication succeeds -/// Returns None if no Keystone headers present (fall back to standard auth) -/// -/// Reserved for future use (alternative Keystone auth path) -#[allow(dead_code)] -pub async fn try_keystone_auth(headers: &HeaderMap) -> S3Result> { - use crate::auth_keystone; - - if !auth_keystone::is_keystone_enabled() { - return Ok(None); - } - - match auth_keystone::authenticate_keystone(headers).await? { - Some(cred) => { - // Keystone credentials are never "owner" in the traditional sense - // unless they have admin role - let is_owner = cred - .groups - .as_ref() - .map(|groups| { - groups - .iter() - .any(|g| g.eq_ignore_ascii_case("admin") || g.eq_ignore_ascii_case("reseller_admin")) - }) - .unwrap_or(false); - - Ok(Some((cred, is_owner))) - } - None => Ok(None), - } -} - pub fn get_session_token<'a>(uri: &'a Uri, hds: &'a HeaderMap) -> Option<&'a str> { let token = hds .get("x-amz-security-token") diff --git a/rustfs/src/auth_keystone.rs b/rustfs/src/auth_keystone.rs index 9c7b3159c..3d4170010 100644 --- a/rustfs/src/auth_keystone.rs +++ b/rustfs/src/auth_keystone.rs @@ -14,13 +14,9 @@ //! OpenStack Keystone authentication integration for RustFS -use http::HeaderMap; -use rustfs_credentials::Credentials; use rustfs_keystone::{KeystoneAuthProvider, KeystoneClient, KeystoneConfig, KeystoneIdentityMapper}; -use rustfs_utils::MaskedAccessKey; -use s3s::{S3Result, s3_error}; use std::sync::{Arc, OnceLock}; -use tracing::{error, info}; +use tracing::info; static KEYSTONE_AUTH: OnceLock> = OnceLock::new(); static KEYSTONE_MAPPER: OnceLock> = OnceLock::new(); @@ -112,239 +108,7 @@ pub fn get_keystone_auth() -> Option> { KEYSTONE_AUTH.get().cloned() } -/// Get Keystone identity mapper -/// -/// Reserved for future use (Swift API, tenant prefixing) -#[allow(dead_code)] -pub fn get_keystone_mapper() -> Option> { - KEYSTONE_MAPPER.get().cloned() -} - -/// Get Keystone configuration -/// -/// Reserved for future use (dynamic configuration updates) -#[allow(dead_code)] -pub fn get_keystone_config() -> Option<&'static KeystoneConfig> { - KEYSTONE_CONFIG.get() -} - /// Check if Keystone is enabled pub fn is_keystone_enabled() -> bool { KEYSTONE_CONFIG.get().map(|c| c.enable).unwrap_or(false) } - -/// Authenticate request with Keystone -/// -/// Checks for: -/// 1. X-Auth-Token header (Keystone token) -/// 2. X-Storage-Token header (Swift compatibility) -/// -/// Returns Some(Credentials) if authenticated via Keystone, -/// None if Keystone is disabled or no Keystone headers present -/// -/// Reserved for future use (alternative auth path, Swift API) -#[allow(dead_code)] -pub async fn authenticate_keystone(headers: &HeaderMap) -> S3Result> { - let auth_provider = match get_keystone_auth() { - Some(provider) => provider, - None => return Ok(None), // Keystone not enabled - }; - - // Check for X-Auth-Token header (Keystone v3) - if let Some(token) = headers.get("X-Auth-Token").and_then(|v| v.to_str().ok()) { - return match auth_provider.authenticate_with_token(token).await { - Ok(cred) => { - info!( - component = LOG_COMPONENT_AUTH, - subsystem = LOG_SUBSYSTEM_KEYSTONE, - event = "keystone_token_auth", - token_type = "x_auth_token", - principal = %MaskedAccessKey(&cred.parent_user), - result = "success", - "Keystone token authentication completed" - ); - Ok(Some(cred)) - } - Err(e) => { - error!( - component = LOG_COMPONENT_AUTH, - subsystem = LOG_SUBSYSTEM_KEYSTONE, - event = "keystone_token_auth", - token_type = "x_auth_token", - result = "failed", - error = %e, - "Keystone token authentication completed" - ); - Err(s3_error!(InvalidToken, "Invalid Keystone token: {}", e)) - } - }; - } - - // Check for X-Storage-Token header (Swift compatibility) - if let Some(token) = headers.get("X-Storage-Token").and_then(|v| v.to_str().ok()) { - return match auth_provider.authenticate_with_token(token).await { - Ok(cred) => { - info!( - component = LOG_COMPONENT_AUTH, - subsystem = LOG_SUBSYSTEM_KEYSTONE, - event = "keystone_token_auth", - token_type = "x_storage_token", - principal = %MaskedAccessKey(&cred.parent_user), - result = "success", - "Keystone token authentication completed" - ); - Ok(Some(cred)) - } - Err(e) => { - error!( - component = LOG_COMPONENT_AUTH, - subsystem = LOG_SUBSYSTEM_KEYSTONE, - event = "keystone_token_auth", - token_type = "x_storage_token", - result = "failed", - error = %e, - "Keystone token authentication completed" - ); - Err(s3_error!(InvalidToken, "Invalid Keystone token: {}", e)) - } - }; - } - - // No Keystone headers found - Ok(None) -} - -/// Apply tenant prefix to bucket name -/// -/// Reserved for future use (multi-tenancy feature) -#[allow(dead_code)] -pub fn apply_tenant_prefix(bucket: &str, cred: &Credentials) -> String { - let mapper = match get_keystone_mapper() { - Some(m) => m, - None => return bucket.to_string(), - }; - - // Extract project_id from claims - let project_id = cred - .claims - .as_ref() - .and_then(|claims| claims.get("keystone_project_id")) - .and_then(|v| v.as_str()); - - mapper.apply_tenant_prefix(bucket, project_id) -} - -/// Remove tenant prefix from bucket name -/// -/// Reserved for future use (multi-tenancy feature) -#[allow(dead_code)] -pub fn remove_tenant_prefix(prefixed_bucket: &str, cred: &Credentials) -> String { - let mapper = match get_keystone_mapper() { - Some(m) => m, - None => return prefixed_bucket.to_string(), - }; - - let project_id = cred - .claims - .as_ref() - .and_then(|claims| claims.get("keystone_project_id")) - .and_then(|v| v.as_str()); - - mapper.remove_tenant_prefix(prefixed_bucket, project_id) -} - -/// Check if bucket belongs to user's project -/// -/// Reserved for future use (multi-tenancy feature) -#[allow(dead_code)] -pub fn is_user_bucket(bucket: &str, cred: &Credentials) -> bool { - let mapper = match get_keystone_mapper() { - Some(m) => m, - None => return true, - }; - - let project_id = cred - .claims - .as_ref() - .and_then(|claims| claims.get("keystone_project_id")) - .and_then(|v| v.as_str()); - - mapper.is_project_bucket(bucket, project_id) -} - -/// Filter bucket list to only show user's project buckets -/// -/// Reserved for future use (multi-tenancy feature) -#[allow(dead_code)] -pub fn filter_bucket_list(buckets: Vec, cred: &Credentials) -> Vec { - let mapper = match get_keystone_mapper() { - Some(m) => m, - None => return buckets, - }; - - if !mapper.is_tenant_prefix_enabled() { - return buckets; - } - - let project_id = cred - .claims - .as_ref() - .and_then(|claims| claims.get("keystone_project_id")) - .and_then(|v| v.as_str()); - - if let Some(proj_id) = project_id { - let prefix = format!("{}:", proj_id); - buckets - .into_iter() - .filter(|b| b.starts_with(&prefix)) - .map(|b| b[prefix.len()..].to_string()) - .collect() - } else { - // No project ID, return unprefixed buckets only - buckets.into_iter().filter(|b| !b.contains(':')).collect() - } -} - -/// Check if credential is from Keystone -/// -/// Reserved for future use (credential type detection) -#[allow(dead_code)] -pub fn is_keystone_credential(cred: &Credentials) -> bool { - cred.claims - .as_ref() - .and_then(|claims| claims.get("auth_source")) - .and_then(|v| v.as_str()) - .map(|s| s == "keystone") - .unwrap_or(false) -} - -#[cfg(test)] -mod tests { - use super::*; - use serde_json::json; - use std::collections::HashMap; - - fn create_test_credentials(project_id: Option<&str>) -> Credentials { - let mut claims = HashMap::new(); - claims.insert("auth_source".to_string(), json!("keystone")); - if let Some(proj_id) = project_id { - claims.insert("keystone_project_id".to_string(), json!(proj_id)); - } - - Credentials { - access_key: "test-access".to_string(), - secret_key: "test-secret".to_string(), - claims: Some(claims), - ..Default::default() - } - } - - #[test] - fn test_is_keystone_credential() { - let cred = create_test_credentials(Some("proj123")); - assert!(is_keystone_credential(&cred)); - - let non_keystone_cred = Credentials::default(); - assert!(!is_keystone_credential(&non_keystone_cred)); - } -}