diff --git a/rustfs/src/admin/handlers/service_account.rs b/rustfs/src/admin/handlers/service_account.rs index 7d26e9bad..942bf4e59 100644 --- a/rustfs/src/admin/handlers/service_account.rs +++ b/rustfs/src/admin/handlers/service_account.rs @@ -1,4 +1,5 @@ use crate::admin::utils::has_space_be; +use crate::auth::get_session_token; use crate::{admin::router::Operation, auth::check_key_valid}; use http::HeaderMap; use hyper::StatusCode; @@ -29,7 +30,8 @@ impl Operation for AddServiceAccount { return Err(s3_error!(InvalidRequest, "get cred failed")); }; - let (cred, _owner) = check_key_valid(&req.headers, &req_cred.access_key).await?; + let (cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &req_cred.access_key).await?; let mut input = req.input; let body = match input.store_all_unlimited().await { @@ -357,10 +359,13 @@ impl Operation for ListServiceAccount { return Err(s3_error!(InvalidRequest, "get cred failed")); }; - let (cred, _owner) = check_key_valid(&req.headers, &input_cred.access_key).await.map_err(|e| { - debug!("check key failed: {e:?}"); - s3_error!(InternalError, "check key failed") - })?; + let (cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key) + .await + .map_err(|e| { + debug!("check key failed: {e:?}"); + s3_error!(InternalError, "check key failed") + })?; let target_account = if let Some(user) = query.user { if user != input_cred.access_key { @@ -415,10 +420,13 @@ impl Operation for DeleteServiceAccount { return Err(s3_error!(InvalidRequest, "get cred failed")); }; - let (_cred, _owner) = check_key_valid(&req.headers, &input_cred.access_key).await.map_err(|e| { - debug!("check key failed: {e:?}"); - s3_error!(InternalError, "check key failed") - })?; + let (_cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key) + .await + .map_err(|e| { + debug!("check key failed: {e:?}"); + s3_error!(InternalError, "check key failed") + })?; let query = { if let Some(query) = req.uri.query() { diff --git a/rustfs/src/admin/handlers/sts.rs b/rustfs/src/admin/handlers/sts.rs index 14efd2222..025866cde 100644 --- a/rustfs/src/admin/handlers/sts.rs +++ b/rustfs/src/admin/handlers/sts.rs @@ -42,12 +42,13 @@ impl Operation for AssumeRoleHandle { let Some(user) = req.credentials else { return Err(s3_error!(InvalidRequest, "get cred failed")) }; - let session_token = get_session_token(&req.headers); + let session_token = get_session_token(&req.uri, &req.headers); if session_token.is_some() { return Err(s3_error!(InvalidRequest, "AccessDenied1")); } - let (cred, _owner) = check_key_valid(&req.headers, &user.access_key).await?; + let (cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &user.access_key).await?; // // TODO: 判断权限, 不允许sts访问 if cred.is_temp() || cred.is_service_account() { diff --git a/rustfs/src/admin/handlers/user.rs b/rustfs/src/admin/handlers/user.rs index ae55f97f7..06e2b9872 100644 --- a/rustfs/src/admin/handlers/user.rs +++ b/rustfs/src/admin/handlers/user.rs @@ -11,7 +11,7 @@ use tracing::warn; use crate::{ admin::{router::Operation, utils::has_space_be}, - auth::check_key_valid, + auth::{check_key_valid, get_session_token}, }; #[derive(Debug, Deserialize, Default)] @@ -39,7 +39,8 @@ impl Operation for AddUser { return Err(s3_error!(InvalidRequest, "get cred failed")); }; - let (cred, _owner) = check_key_valid(&req.headers, &input_cred.access_key).await?; + let (cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key).await?; let ak = query.access_key.as_deref().unwrap_or_default(); @@ -246,7 +247,8 @@ impl Operation for RemoveUser { return Err(s3_error!(InvalidRequest, "get cred failed")); }; - let (cred, _owner) = check_key_valid(&req.headers, &input_cred.access_key).await?; + let (cred, _owner) = + check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key).await?; let sys_cred = get_global_action_cred() .ok_or_else(|| S3Error::with_message(S3ErrorCode::InternalError, "get_global_action_cred failed"))?; diff --git a/rustfs/src/auth.rs b/rustfs/src/auth.rs index 3d0425535..c3b8ed5f9 100644 --- a/rustfs/src/auth.rs +++ b/rustfs/src/auth.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use http::HeaderMap; +use http::Uri; use iam::error::Error as IamError; use iam::get_global_action_cred; use iam::sys::SESSION_POLICY_NAME; @@ -48,7 +49,7 @@ impl S3Auth for IAMAuth { } // check_key_valid checks the key is valid or not. return the user's credentials and if the user is the owner. -pub async fn check_key_valid(header: &HeaderMap, access_key: &str) -> S3Result<(auth::Credentials, bool)> { +pub async fn check_key_valid(session_token: &str, access_key: &str) -> S3Result<(auth::Credentials, bool)> { let Some(mut cred) = get_global_action_cred() else { return Err(S3Error::with_message( S3ErrorCode::InternalError, @@ -88,7 +89,7 @@ pub async fn check_key_valid(header: &HeaderMap, access_key: &str) -> S3Result<( cred = u.credentials; } - let claims = check_claims_from_token(header, &cred) + let claims = check_claims_from_token(session_token, &cred) .map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("check claims failed {}", e)))?; cred.claims = if !claims.is_empty() { Some(claims) } else { None }; @@ -105,9 +106,7 @@ pub async fn check_key_valid(header: &HeaderMap, access_key: &str) -> S3Result<( Ok((cred, owner)) } -pub fn check_claims_from_token(header: &HeaderMap, cred: &auth::Credentials) -> S3Result> { - let token = get_session_token(header).unwrap_or_default(); - +pub fn check_claims_from_token(token: &str, cred: &auth::Credentials) -> S3Result> { if !token.is_empty() && cred.access_key.is_empty() { return Err(s3_error!(InvalidRequest, "no access key")); } @@ -149,8 +148,10 @@ pub fn check_claims_from_token(header: &HeaderMap, cred: &auth::Credentials) -> Ok(HashMap::new()) } -pub fn get_session_token(hds: &HeaderMap) -> Option<&str> { - hds.get("x-amz-security-token").map(|v| v.to_str().unwrap_or_default()) +pub fn get_session_token<'a>(uri: &'a Uri, hds: &'a HeaderMap) -> Option<&'a str> { + hds.get("x-amz-security-token") + .map(|v| v.to_str().unwrap_or_default()) + .or_else(|| get_query_param(uri.query().unwrap_or_default(), "x-amz-security-token")) } pub fn get_condition_values(header: &HeaderMap, cred: &auth::Credentials) -> HashMap> { @@ -295,3 +296,17 @@ pub fn get_condition_values(header: &HeaderMap, cred: &auth::Credentials) -> Has args } + +pub fn get_query_param<'a>(url: &'a str, param_name: &str) -> Option<&'a str> { + let query_start = url.find('?')?; + let query = &url[query_start + 1..]; + for pair in query.split('&') { + let mut parts = pair.splitn(2, '='); + if let (Some(key), Some(value)) = (parts.next(), parts.next()) { + if key.to_lowercase() == param_name { + return Some(value); + } + } + } + None +} diff --git a/rustfs/src/storage/access.rs b/rustfs/src/storage/access.rs index 0e1562cad..fc6bb0b62 100644 --- a/rustfs/src/storage/access.rs +++ b/rustfs/src/storage/access.rs @@ -1,5 +1,5 @@ use super::ecfs::FS; -use crate::auth::{check_key_valid, get_condition_values}; +use crate::auth::{check_key_valid, get_condition_values, get_session_token}; use ecstore::bucket::policy_sys::PolicySys; use iam::error::Error as IamError; use policy::auth; @@ -8,6 +8,7 @@ use policy::policy::{Args, BucketPolicyArgs}; use s3s::access::{S3Access, S3AccessContext}; use s3s::{dto::*, s3_error, S3Error, S3ErrorCode, S3Request, S3Result}; use std::collections::HashMap; +use tracing::info; #[allow(dead_code)] #[derive(Default, Clone)] @@ -143,19 +144,20 @@ impl S3Access for FS { // /// + [`cx.extensions_mut()`](S3AccessContext::extensions_mut) async fn check(&self, cx: &mut S3AccessContext<'_>) -> S3Result<()> { // 上层验证了 ak/sk - // info!( - // "s3 check uri: {:?}, method: {:?} path: {:?}, s3_op: {:?}, cred: {:?}, headers:{:?}", - // cx.uri(), - // cx.method(), - // cx.s3_path(), - // cx.s3_op().name(), - // cx.credentials(), - // cx.headers(), - // // cx.extensions_mut(), - // ); + info!( + "s3 check uri: {:?}, method: {:?} path: {:?}, s3_op: {:?}, cred: {:?}, headers:{:?}", + cx.uri(), + cx.method(), + cx.s3_path(), + cx.s3_op().name(), + cx.credentials(), + cx.headers(), + // cx.extensions_mut(), + ); let (cred, is_owner) = if let Some(input_cred) = cx.credentials() { - let (cred, is_owner) = check_key_valid(cx.headers(), &input_cred.access_key).await?; + let (cred, is_owner) = + check_key_valid(get_session_token(cx.uri(), cx.headers()).unwrap_or_default(), &input_cred.access_key).await?; (Some(cred), is_owner) } else { (None, false)