refactor: route notify dispatch through app context (#3789)

* refactor: route notify dispatch through app context

* refactor: route admin IAM globals through app context (#3791)

* refactor: centralize IAM root credential access (#3792)
This commit is contained in:
Zhengchao An
2026-06-23 20:05:28 +08:00
committed by GitHub
parent da565c11bc
commit 70a2441407
19 changed files with 272 additions and 72 deletions
+5
View File
@@ -47,6 +47,7 @@ pub mod keyring;
pub mod manager; pub mod manager;
pub mod oidc; pub mod oidc;
pub mod oidc_state; pub mod oidc_state;
mod root_credentials;
pub mod store; pub mod store;
pub mod sys; pub mod sys;
pub mod utils; pub mod utils;
@@ -60,6 +61,10 @@ pub(crate) type IamStore = EcstoreStore;
pub(crate) type IamConfigObjectInfo = <IamStore as rustfs_storage_api::ObjectOperations>::ObjectInfo; pub(crate) type IamConfigObjectInfo = <IamStore as rustfs_storage_api::ObjectOperations>::ObjectInfo;
pub(crate) type IamConfigObjectOptions = <IamStore as rustfs_storage_api::ObjectOperations>::ObjectOptions; pub(crate) type IamConfigObjectOptions = <IamStore as rustfs_storage_api::ObjectOperations>::ObjectOptions;
pub fn is_root_access_key(access_key: &str) -> bool {
root_credentials::is_root_access_key(access_key)
}
pub(crate) async fn read_iam_config_no_lock(api: Arc<IamStore>, file: &str) -> IamStorageResult<Vec<u8>> { pub(crate) async fn read_iam_config_no_lock(api: Arc<IamStore>, file: &str) -> IamStorageResult<Vec<u8>> {
ecstore_read_config_no_lock(api, file).await ecstore_read_config_no_lock(api, file).await
} }
+2 -6
View File
@@ -25,7 +25,7 @@ use crate::{
}, },
}; };
use futures::future::join_all; use futures::future::join_all;
use rustfs_credentials::{Credentials, EMBEDDED_POLICY_TYPE, INHERITED_POLICY_TYPE, get_global_action_cred}; use rustfs_credentials::{Credentials, EMBEDDED_POLICY_TYPE, INHERITED_POLICY_TYPE};
use rustfs_madmin::{AccountStatus, AddOrUpdateUserReq, GroupDesc}; use rustfs_madmin::{AccountStatus, AddOrUpdateUserReq, GroupDesc};
use rustfs_policy::{ use rustfs_policy::{
arn::ARN, arn::ARN,
@@ -2137,11 +2137,7 @@ fn set_default_canned_policies(policies: &mut HashMap<String, PolicyDoc>) {
} }
pub fn get_token_signing_key() -> Option<String> { pub fn get_token_signing_key() -> Option<String> {
if let Some(s) = get_global_action_cred() { crate::root_credentials::token_signing_key()
Some(s.secret_key)
} else {
None
}
} }
pub fn extract_jwt_claims(u: &UserIdentity) -> Result<HashMap<String, Value>> { pub fn extract_jwt_claims(u: &UserIdentity) -> Result<HashMap<String, Value>> {
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use rustfs_credentials::{Credentials, get_global_action_cred};
pub(crate) fn credentials() -> Option<Credentials> {
get_global_action_cred()
}
pub(crate) fn credentials_or_default() -> Credentials {
credentials().unwrap_or_default()
}
pub(crate) fn token_signing_key() -> Option<String> {
credentials().map(|cred| cred.secret_key)
}
pub(crate) fn is_root_access_key(access_key: &str) -> bool {
credentials().is_some_and(|cred| cred.access_key == access_key)
}
+5 -5
View File
@@ -23,9 +23,9 @@ use crate::{
error::{is_err_no_such_policy, is_err_no_such_user}, error::{is_err_no_such_policy, is_err_no_such_user},
keyring, keyring,
manager::{extract_jwt_claims, extract_jwt_claims_allow_missing_exp, get_default_policyes}, manager::{extract_jwt_claims, extract_jwt_claims_allow_missing_exp, get_default_policyes},
root_credentials,
}; };
use futures::future::join_all; use futures::future::join_all;
use rustfs_credentials::get_global_action_cred;
use rustfs_io_metrics::record_system_path_failure; use rustfs_io_metrics::record_system_path_failure;
use rustfs_policy::{auth::UserIdentity, policy::PolicyDoc}; use rustfs_policy::{auth::UserIdentity, policy::PolicyDoc};
use rustfs_storage_api::{HTTPPreconditions, ListOperations as _, ObjectInfoOrErr as StorageObjectInfoOrErr, ObjectOperations}; use rustfs_storage_api::{HTTPPreconditions, ListOperations as _, ObjectInfoOrErr as StorageObjectInfoOrErr, ObjectOperations};
@@ -165,7 +165,7 @@ impl ObjectStore {
} }
const STREAM_IO_HEADER_LEN: usize = 41; const STREAM_IO_HEADER_LEN: usize = 41;
let cred = get_global_action_cred().unwrap_or_default(); let cred = root_credentials::credentials_or_default();
let mut last_err = None; let mut last_err = None;
let mut try_decrypt_with_key = |key: &[u8], source: DecryptSource| -> Option<DecryptOutcome> { let mut try_decrypt_with_key = |key: &[u8], source: DecryptSource| -> Option<DecryptOutcome> {
@@ -1273,16 +1273,16 @@ impl Store for ObjectStore {
mod tests { mod tests {
use super::{DecryptSource, ObjectStore}; use super::{DecryptSource, ObjectStore};
use crate::keyring; use crate::keyring;
use rustfs_credentials::{Credentials, get_global_action_cred, init_global_action_credentials}; use rustfs_credentials::{Credentials, init_global_action_credentials};
use serial_test::serial; use serial_test::serial;
use temp_env::with_vars; use temp_env::with_vars;
fn test_cred() -> Credentials { fn test_cred() -> Credentials {
if let Some(cred) = get_global_action_cred() { if let Some(cred) = crate::root_credentials::credentials() {
return cred; return cred;
} }
let _ = init_global_action_credentials(Some("COMPATTESTAK".to_string()), Some("COMPATTESTSK1234567890".to_string())); let _ = init_global_action_credentials(Some("COMPATTESTAK".to_string()), Some("COMPATTESTSK1234567890".to_string()));
get_global_action_cred().unwrap_or_default() crate::root_credentials::credentials_or_default()
} }
#[test] #[test]
+8 -9
View File
@@ -28,7 +28,7 @@ use crate::{
notify_iam_delete_policy, notify_iam_delete_service_account, notify_iam_delete_user, notify_iam_load_group, notify_iam_delete_policy, notify_iam_delete_service_account, notify_iam_delete_user, notify_iam_load_group,
notify_iam_load_policy, notify_iam_load_policy_mapping, notify_iam_load_service_account, notify_iam_load_user, notify_iam_load_policy, notify_iam_load_policy_mapping, notify_iam_load_service_account, notify_iam_load_user,
}; };
use rustfs_credentials::{Credentials, EMBEDDED_POLICY_TYPE, INHERITED_POLICY_TYPE, get_global_action_cred}; use rustfs_credentials::{Credentials, EMBEDDED_POLICY_TYPE, INHERITED_POLICY_TYPE};
use rustfs_madmin::AddOrUpdateUserReq; use rustfs_madmin::AddOrUpdateUserReq;
use rustfs_madmin::GroupDesc; use rustfs_madmin::GroupDesc;
use rustfs_policy::arn::ARN; use rustfs_policy::arn::ARN;
@@ -748,7 +748,7 @@ impl<T: Store> IamSys<T> {
} }
pub async fn check_key(&self, access_key: &str) -> Result<(Option<UserIdentity>, bool)> { pub async fn check_key(&self, access_key: &str) -> Result<(Option<UserIdentity>, bool)> {
if let Some(sys_cred) = get_global_action_cred() if let Some(sys_cred) = crate::root_credentials::credentials()
&& sys_cred.access_key == access_key && sys_cred.access_key == access_key
{ {
return Ok((Some(UserIdentity::new(sys_cred)), true)); return Ok((Some(UserIdentity::new(sys_cred)), true));
@@ -1010,7 +1010,7 @@ impl<T: Store> IamSys<T> {
} }
pub(crate) async fn prepare_sts_auth(&self, args: &Args<'_>, parent_user: &str) -> PreparedIamAuth { pub(crate) async fn prepare_sts_auth(&self, args: &Args<'_>, parent_user: &str) -> PreparedIamAuth {
let is_owner = matches!(get_global_action_cred(), Some(cred) if cred.access_key == parent_user); let is_owner = crate::is_root_access_key(parent_user);
let role_arn = args.get_role_arn(); let role_arn = args.get_role_arn();
let (effective_groups, groups_source, policies) = if is_owner { let (effective_groups, groups_source, policies) = if is_owner {
@@ -1162,7 +1162,7 @@ impl<T: Store> IamSys<T> {
&& matches!(mode, PreparedServicePolicyMode::SessionBound) && matches!(mode, PreparedServicePolicyMode::SessionBound)
&& matches!(session_policy, PreparedSessionPolicy::Policy(_)); && matches!(session_policy, PreparedSessionPolicy::Policy(_));
let is_owner = matches!(get_global_action_cred(), Some(cred) if cred.access_key == parent_user); let is_owner = crate::is_root_access_key(parent_user);
let role_arn = args.get_role_arn(); let role_arn = args.get_role_arn();
let svc_policies = if is_owner || bypass_parent_policy { let svc_policies = if is_owner || bypass_parent_policy {
@@ -1352,7 +1352,7 @@ mod tests {
use crate::error::Error; use crate::error::Error;
use crate::manager::get_default_policyes; use crate::manager::get_default_policyes;
use crate::store::{GroupInfo, MappedPolicy, Store, UserType}; use crate::store::{GroupInfo, MappedPolicy, Store, UserType};
use rustfs_credentials::{Credentials, get_global_action_cred, init_global_action_credentials}; use rustfs_credentials::{Credentials, init_global_action_credentials};
use rustfs_policy::auth::{UserIdentity, get_new_credentials_with_metadata}; use rustfs_policy::auth::{UserIdentity, get_new_credentials_with_metadata};
use rustfs_policy::policy::Args; use rustfs_policy::policy::Args;
use rustfs_policy::policy::action::{Action, AdminAction, S3Action}; use rustfs_policy::policy::action::{Action, AdminAction, S3Action};
@@ -1660,7 +1660,7 @@ mod tests {
} }
fn ensure_test_global_credentials() { fn ensure_test_global_credentials() {
if get_global_action_cred().is_none() { if crate::root_credentials::credentials().is_none() {
let _ = init_global_action_credentials(Some("TESTROOTACCESSKEY".to_string()), Some("TESTROOTSECRET123".to_string())); let _ = init_global_action_credentials(Some("TESTROOTACCESSKEY".to_string()), Some("TESTROOTSECRET123".to_string()));
} }
} }
@@ -1940,9 +1940,8 @@ mod tests {
let iam_sys = IamSys::new(cache_manager); let iam_sys = IamSys::new(cache_manager);
let parent_user = "sts-fallback-test-parent"; let parent_user = "sts-fallback-test-parent";
let token_secret = get_global_action_cred() let token_secret = crate::root_credentials::token_signing_key()
.expect("global action credentials should be initialized") .unwrap_or_else(|| unreachable!("global action credentials should be initialized"));
.secret_key;
let mut claims = HashMap::new(); let mut claims = HashMap::new();
claims.insert("parent".to_string(), Value::String(parent_user.to_string())); claims.insert("parent".to_string(), Value::String(parent_user.to_string()));
claims.insert( claims.insert(
+1 -6
View File
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use rustfs_credentials;
use rustfs_policy::policy::action::S3Action as PolicyS3Action; use rustfs_policy::policy::action::S3Action as PolicyS3Action;
use serde_json; use serde_json;
use std::collections::HashMap; use std::collections::HashMap;
@@ -299,11 +298,7 @@ pub async fn is_authorized(
let policy_action: rustfs_policy::policy::action::Action = action.clone().into(); let policy_action: rustfs_policy::policy::action::Action = action.clone().into();
// Check if user is the owner (admin) // Check if user is the owner (admin)
let is_owner = if let Some(global_cred) = rustfs_credentials::get_global_action_cred() { let is_owner = rustfs_iam::is_root_access_key(session_context.principal.access_key());
session_context.principal.access_key() == global_cred.access_key
} else {
false
};
let args = rustfs_policy::policy::Args { let args = rustfs_policy::policy::Args {
account: session_context.principal.access_key(), account: session_context.principal.access_key(),
+112 -7
View File
@@ -5,16 +5,18 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
## Current Context ## Current Context
- Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660) - Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
- Branch: `overtrue/arch-iam-global-read-batch` - Branch: `overtrue/arch-iam-credential-boundary`
- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178`. - Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178/API-179/API-180/API-181`.
- Based on: API-171 through API-177 prepared in PR #3785; this branch batches - Based on: API-180 prepared in PR #3791; this branch batches IAM root
the next IAM consumer migration on top of that branch. credential boundary cleanup on top of that branch.
- PR type for this branch: `consumer-migration` - PR type for this branch: `consumer-migration`
- Runtime behavior changes: none. - Runtime behavior changes: none.
- Rust code changes: route replication pool, outbound TLS generation, runtime - Rust code changes: route replication pool, outbound TLS generation, runtime
region, KMS encryption service, runtime support handles, S3 Select DB, region, KMS encryption service, runtime support handles, S3 Select DB,
internode RPC metrics, and IAM authorization/handler reads through internode RPC metrics, IAM authorization/handler reads, notification
AppContext-first resolvers. rules/event dispatch, admin OIDC/token-signing reads, and IAM root
credential consumers through AppContext-first or IAM-owned resolver
boundaries.
- CI/script changes: lock completed owner and test/fuzz boundaries against - CI/script changes: lock completed owner and test/fuzz boundaries against
bare/glob imports, scattered raw ECStore facade subpaths, and startup bare/glob imports, scattered raw ECStore facade subpaths, and startup
runtime/root-server/table/S3/app shared/app bucket/app ECStore/admin facade runtime/root-server/table/S3/app shared/app bucket/app ECStore/admin facade
@@ -23,7 +25,7 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
and storage owner thin bridge regressions, plus app context and notify and storage owner thin bridge regressions, plus app context and notify
event-bridge thin module regressions; accept the reviewed AppContext resolver event-bridge thin module regressions; accept the reviewed AppContext resolver
reverse dependencies in the layer baseline. reverse dependencies in the layer baseline.
- Docs changes: record the API-136 through API-178 owner facade cleanup. - Docs changes: record the API-136 through API-181 owner facade cleanup.
## Phase 0 Tasks ## Phase 0 Tasks
@@ -4571,6 +4573,52 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
migration guard, layer guard, formatting, diff hygiene, residual IAM getter migration guard, layer guard, formatting, diff hygiene, residual IAM getter
scan, Rust risk scan, branch freshness check, and three-expert review. scan, Rust risk scan, branch freshness check, and three-expert review.
- [x] `API-179` Route notification dispatch through AppContext.
- Do: route startup notification rule registration, storage event
notifications, and ECStore event dispatch hooks through the AppContext
notify interface.
- Acceptance: production RustFS notification dispatch paths no longer call
the notify global directly, while the default adapter preserves the legacy
notifier fallback.
- Must preserve: bucket notification rule registration, operation helper
success-only event emission, replication-request suppression, ECStore event
conversion, and background spawn behavior.
- Verification: RustFS compile coverage, targeted context resolver tests,
migration guard, layer guard, formatting, diff hygiene, residual notify
dispatch scan, Rust risk scan, branch freshness check, and three-expert
review.
- [x] `API-180` Route admin OIDC and token-signing reads through AppContext.
- Do: expose AppContext-first resolvers for the OIDC system and token
signing key, then route console config, OIDC handlers, STS credential
generation, table credential vending, and site-replication STS validation
through those resolvers.
- Acceptance: targeted RustFS admin OIDC/token-signing consumers no longer
read IAM globals directly, while default adapters preserve the existing
global OIDC and action-credential fallback.
- Must preserve: OIDC provider listing, authorize/callback/logout behavior,
STS web-identity verification, STS/table credential claims, session-policy
handling, and site-replication STS token validation.
- Verification: RustFS compile coverage, targeted context resolver tests,
migration guard, layer guard, formatting, diff hygiene, residual
admin/global IAM scan, Rust risk scan, branch freshness check, and
three-expert review.
- [x] `API-181` Centralize IAM root credential reads behind IAM boundary.
- Do: add an IAM-owned root credential helper, route IAM store/sys/token
signing consumers through it, and make protocol gateway owner checks call an
IAM predicate instead of reading credentials directly.
- Acceptance: production IAM and protocol gateway paths no longer call the
action credential global directly outside the IAM boundary module, while
root user detection, legacy IAM decrypt fallback, and token-signing behavior
remain unchanged.
- Must preserve: root credential lookup, owner-policy bypass decisions,
legacy secret-key decrypt fallback, STS token signing key selection,
service-account/STSes authorization, and protocol gateway policy args.
- Verification: IAM/protocol compile coverage, IAM focused tests, formatting,
migration guard, layer guard, diff hygiene, residual direct credential scan,
Rust risk scan, branch freshness check, and three-expert review.
## Next PRs ## Next PRs
1. `consumer-migration`: continue reducing direct global reads behind AppContext resolver boundaries. 1. `consumer-migration`: continue reducing direct global reads behind AppContext resolver boundaries.
@@ -4661,11 +4709,68 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
| Quality/architecture | pass | API-178 keeps ready IAM access behind an AppContext-first resolver without widening handler semantics. | | Quality/architecture | pass | API-178 keeps ready IAM access behind an AppContext-first resolver without widening handler semantics. |
| Migration preservation | pass | Auth, storage authorization, admin IAM handlers, STS, and table credential flows keep existing error mapping and ready-check fallback. | | Migration preservation | pass | Auth, storage authorization, admin IAM handlers, STS, and table credential flows keep existing error mapping and ready-check fallback. |
| Testing/verification | pass | RustFS focused compile, targeted context resolver test, formatting, migration/layer guards, diff hygiene, residual IAM getter scan, Rust risk scan, and pre-commit passed for API-178. | | Testing/verification | pass | RustFS focused compile, targeted context resolver test, formatting, migration/layer guards, diff hygiene, residual IAM getter scan, Rust risk scan, and pre-commit passed for API-178. |
| Quality/architecture | pass | API-179 keeps notification rule registration and event dispatch behind the AppContext notify resolver. |
| Migration preservation | pass | Startup rules, success-only storage events, replication suppression, ECStore hook conversion, and default notifier fallback are preserved. |
| Testing/verification | pass | RustFS focused compile, targeted context resolver test, formatting, migration/layer guards, diff hygiene, residual notify dispatch scan, Rust risk scan, and pre-commit passed for API-179. |
| Quality/architecture | pass | API-180 keeps admin OIDC and token-signing reads behind IAM/AppContext resolver methods without widening handler behavior. |
| Migration preservation | pass | OIDC provider discovery, STS credential generation, table credential vending, and site-replication STS validation keep existing error mapping and fallback semantics. |
| Testing/verification | pass | RustFS focused compile, targeted context resolver test, formatting/migration/layer guards, diff hygiene, residual admin IAM scan, and Rust risk scan passed for API-180. |
| Quality/architecture | pass | API-181 keeps IAM root credential reads centralized in an IAM-owned helper and exposes only a root access-key predicate to protocol code. |
| Migration preservation | pass | Root owner checks, legacy IAM decrypt fallback, token signing, and gateway policy args preserve existing credential semantics. |
| Testing/verification | pass | IAM/protocol compile, IAM unit tests, formatting, migration/layer guards, diff hygiene, residual credential scan, and Rust risk scan passed for API-181. |
## Verification Notes ## Verification Notes
Passed before push: Passed before push:
- Issue #660 API-181 current slice:
- `cargo check -p rustfs-iam -p rustfs-protocols --tests`: passed.
- `cargo test -p rustfs-iam --lib`: passed.
- `cargo fmt --all`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `bash -n scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_layer_dependencies.sh`: passed.
- IAM/protocol credential scan: passed; production direct
`get_global_action_cred` calls are isolated to the IAM root credential
boundary.
- Rust risk scan: no new production unwrap/expect, panic/todo/unsafe, or cast
risks added.
- `make pre-commit`: passed.
- Issue #660 API-180 current slice:
- `cargo check --tests -p rustfs`: passed.
- `cargo test -p rustfs resolver_helpers_are_context_first_and_fallback_when_context_is_absent --lib`:
passed.
- `cargo fmt --all`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `bash -n scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_layer_dependencies.sh`: passed.
- Admin IAM/OIDC scan: passed; targeted admin OIDC and token-signing reads
now go through AppContext IAM resolvers.
- Rust risk scan: no new production unwrap/expect, panic/todo/unsafe, or cast
risks added.
- `make pre-commit`: passed.
- Issue #660 API-179 current slice:
- `cargo check --tests -p rustfs`: passed.
- `cargo test -p rustfs resolver_helpers_are_context_first_and_fallback_when_context_is_absent --lib`:
passed.
- `cargo fmt --all`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `bash -n scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_layer_dependencies.sh`: passed.
- Notify dispatch scan: passed; production startup, storage helper, and
ECStore event hook dispatch no longer call the notify global directly.
- Rust risk scan: no new production unwrap/expect, panic/todo/unsafe, or cast
risks added.
- `make pre-commit`: passed.
- Issue #660 API-178 current slice: - Issue #660 API-178 current slice:
- `cargo check --tests -p rustfs`: passed. - `cargo check --tests -p rustfs`: passed.
- `cargo test -p rustfs resolver_helpers_are_context_first_and_fallback_when_context_is_absent --lib`: - `cargo test -p rustfs resolver_helpers_are_context_first_and_fallback_when_context_is_absent --lib`:
+2 -1
View File
@@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
use crate::admin::handlers::health::{HealthProbe, build_health_response_parts, collect_dependency_readiness}; use crate::admin::handlers::health::{HealthProbe, build_health_response_parts, collect_dependency_readiness};
use crate::app::context::resolve_oidc_handle;
use crate::license::has_valid_license; use crate::license::has_valid_license;
use crate::server::has_path_prefix; use crate::server::has_path_prefix;
use crate::server::{ use crate::server::{
@@ -134,7 +135,7 @@ impl Config {
let http_prefix = rustfs_config::RUSTFS_HTTP_PREFIX; let http_prefix = rustfs_config::RUSTFS_HTTP_PREFIX;
// Collect OIDC provider info if available // Collect OIDC provider info if available
let oidc = rustfs_iam::get_oidc() let oidc = resolve_oidc_handle()
.map(|sys| { .map(|sys| {
sys.list_visible_providers() sys.list_visible_providers()
.into_iter() .into_iter()
+6 -6
View File
@@ -16,7 +16,7 @@ use super::super::{read_admin_config_without_migrate, save_admin_server_config};
use super::sts::create_oidc_sts_credentials; use super::sts::create_oidc_sts_credentials;
use crate::admin::auth::validate_admin_request; use crate::admin::auth::validate_admin_request;
use crate::admin::router::{AdminOperation, Operation, S3Router}; use crate::admin::router::{AdminOperation, Operation, S3Router};
use crate::app::context::{resolve_object_store_handle, resolve_server_config}; use crate::app::context::{resolve_object_store_handle, resolve_oidc_handle, resolve_server_config};
use crate::auth::{check_key_valid, get_session_token}; use crate::auth::{check_key_valid, get_session_token};
use crate::server::{ADMIN_PREFIX, MINIO_ADMIN_PREFIX, RemoteAddr}; use crate::server::{ADMIN_PREFIX, MINIO_ADMIN_PREFIX, RemoteAddr};
use http::StatusCode; use http::StatusCode;
@@ -268,7 +268,7 @@ pub struct ListOidcProvidersHandler {}
#[async_trait::async_trait] #[async_trait::async_trait]
impl Operation for ListOidcProvidersHandler { impl Operation for ListOidcProvidersHandler {
async fn call(&self, _req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> { async fn call(&self, _req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
let oidc_sys = rustfs_iam::get_oidc().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?; let oidc_sys = resolve_oidc_handle().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?;
let providers = oidc_sys.list_visible_providers(); let providers = oidc_sys.list_visible_providers();
let json_body = serde_json::to_vec(&providers) let json_body = serde_json::to_vec(&providers)
@@ -439,7 +439,7 @@ impl Operation for OidcAuthorizeHandler {
return Err(s3_error!(InvalidRequest, "invalid provider_id")); return Err(s3_error!(InvalidRequest, "invalid provider_id"));
} }
let oidc_sys = rustfs_iam::get_oidc().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?; let oidc_sys = resolve_oidc_handle().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?;
// Derive the callback redirect URI from the request // Derive the callback redirect URI from the request
let redirect_uri = derive_callback_uri(&req, provider_id)?; let redirect_uri = derive_callback_uri(&req, provider_id)?;
@@ -512,7 +512,7 @@ impl Operation for OidcCallbackHandler {
)); ));
} }
let oidc_sys = rustfs_iam::get_oidc().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?; let oidc_sys = resolve_oidc_handle().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?;
let redirect_uri = derive_callback_uri(&req, provider_id)?; let redirect_uri = derive_callback_uri(&req, provider_id)?;
@@ -599,7 +599,7 @@ impl Operation for OidcLogoutHandler {
return redirect_response(&fallback_location); return redirect_response(&fallback_location);
}; };
let location = match rustfs_iam::get_oidc() { let location = match resolve_oidc_handle() {
Some(oidc_sys) => match oidc_sys.build_logout_url(&logout_token, &fallback_location).await { Some(oidc_sys) => match oidc_sys.build_logout_url(&logout_token, &fallback_location).await {
Ok(Some(url)) => url, Ok(Some(url)) => url,
Ok(None) => fallback_location.clone(), Ok(None) => fallback_location.clone(),
@@ -628,7 +628,7 @@ impl Operation for OidcLogoutHandler {
/// an explicit redirect_uri is recommended to prevent header manipulation. /// an explicit redirect_uri is recommended to prevent header manipulation.
fn derive_callback_uri(req: &S3Request<Body>, provider_id: &str) -> S3Result<String> { fn derive_callback_uri(req: &S3Request<Body>, provider_id: &str) -> S3Result<String> {
// Use explicitly configured redirect_uri if available // Use explicitly configured redirect_uri if available
if let Some(oidc_sys) = rustfs_iam::get_oidc() if let Some(oidc_sys) = resolve_oidc_handle()
&& let Some(config) = oidc_sys.get_provider_config(provider_id) && let Some(config) = oidc_sys.get_provider_config(provider_id)
{ {
if let Some(ref uri) = config.redirect_uri { if let Some(ref uri) = config.redirect_uri {
@@ -34,7 +34,7 @@ use crate::admin::utils::{encode_compatible_admin_payload, read_compatible_admin
use crate::app::context::{ use crate::app::context::{
resolve_deployment_id, resolve_endpoints_handle, resolve_iam_handle, resolve_object_store_handle, resolve_oidc_handle, resolve_deployment_id, resolve_endpoints_handle, resolve_iam_handle, resolve_object_store_handle, resolve_oidc_handle,
resolve_outbound_tls_generation, resolve_outbound_tls_state, resolve_region, resolve_replication_pool_handle, resolve_outbound_tls_generation, resolve_outbound_tls_state, resolve_region, resolve_replication_pool_handle,
resolve_replication_stats_handle, resolve_runtime_port, resolve_server_config, resolve_replication_stats_handle, resolve_runtime_port, resolve_server_config, resolve_token_signing_key,
}; };
use crate::auth::{check_key_valid, get_session_token}; use crate::auth::{check_key_valid, get_session_token};
use crate::config::get_config_snapshot; use crate::config::get_config_snapshot;
@@ -3556,7 +3556,7 @@ async fn apply_iam_item(item: SRIAMItem) -> S3Result<()> {
let Some(sts_credential) = item.sts_credential else { let Some(sts_credential) = item.sts_credential else {
return Err(s3_error!(InvalidRequest, "stsCredential is required")); return Err(s3_error!(InvalidRequest, "stsCredential is required"));
}; };
let Some(secret) = rustfs_iam::manager::get_token_signing_key() else { let Some(secret) = resolve_token_signing_key() else {
return Err(s3_error!(InvalidRequest, "token signing key not initialized")); return Err(s3_error!(InvalidRequest, "token signing key not initialized"));
}; };
let claims = get_claims_from_token_with_secret(&sts_credential.session_token, &secret) let claims = get_claims_from_token_with_secret(&sts_credential.session_token, &secret)
+6 -6
View File
@@ -19,7 +19,7 @@ use crate::{
handlers::site_replication::site_replication_iam_change_hook, handlers::site_replication::site_replication_iam_change_hook,
router::{AdminOperation, Operation, S3Router}, router::{AdminOperation, Operation, S3Router},
}, },
app::context::resolve_action_credentials, app::context::{resolve_action_credentials, resolve_oidc_handle, resolve_token_signing_key},
auth::{check_key_valid, extract_string_list_claim, get_session_token}, auth::{check_key_valid, extract_string_list_claim, get_session_token},
server::ADMIN_PREFIX, server::ADMIN_PREFIX,
server::RemoteAddr, server::RemoteAddr,
@@ -29,7 +29,7 @@ use http::header::HeaderValue;
use hyper::Method; use hyper::Method;
use matchit::Params; use matchit::Params;
use rustfs_config::MAX_ADMIN_REQUEST_BODY_SIZE; use rustfs_config::MAX_ADMIN_REQUEST_BODY_SIZE;
use rustfs_iam::{manager::get_token_signing_key, oidc::OidcClaims, sys::SESSION_POLICY_NAME}; use rustfs_iam::{oidc::OidcClaims, sys::SESSION_POLICY_NAME};
use rustfs_madmin::{SITE_REPL_API_VERSION, SRIAMItem, SRSTSCredential}; use rustfs_madmin::{SITE_REPL_API_VERSION, SRIAMItem, SRSTSCredential};
use rustfs_policy::{ use rustfs_policy::{
auth::get_new_credentials_with_metadata, auth::get_new_credentials_with_metadata,
@@ -59,7 +59,7 @@ fn has_identity_authorization_context(policies: &[String], groups: &[String]) ->
} }
fn configured_roles_claim_key(provider_id: &str) -> Option<String> { fn configured_roles_claim_key(provider_id: &str) -> Option<String> {
rustfs_iam::get_oidc() resolve_oidc_handle()
.as_ref() .as_ref()
.and_then(|oidc_sys| oidc_sys.get_provider_config(provider_id)) .and_then(|oidc_sys| oidc_sys.get_provider_config(provider_id))
.map(|cfg| cfg.roles_claim.trim().to_string()) .map(|cfg| cfg.roles_claim.trim().to_string())
@@ -239,7 +239,7 @@ async fn handle_assume_role(
return Err(s3_error!(InvalidArgument, "invalid policy arg")); return Err(s3_error!(InvalidArgument, "invalid policy arg"));
} }
let Some(secret) = get_token_signing_key() else { let Some(secret) = resolve_token_signing_key() else {
return Err(s3_error!(InvalidArgument, "global active sk not init")); return Err(s3_error!(InvalidArgument, "global active sk not init"));
}; };
@@ -316,7 +316,7 @@ async fn handle_assume_role_with_web_identity(body: AssumeRoleRequest) -> S3Resu
} }
// Verify the JWT and extract claims // Verify the JWT and extract claims
let oidc_sys = rustfs_iam::get_oidc().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?; let oidc_sys = resolve_oidc_handle().ok_or_else(|| s3_error!(InternalError, "OIDC not initialized"))?;
let (claims, provider_id) = oidc_sys let (claims, provider_id) = oidc_sys
.verify_web_identity_token(&body.web_identity_token) .verify_web_identity_token(&body.web_identity_token)
@@ -429,7 +429,7 @@ pub async fn create_oidc_sts_credentials(
} }
// Generate STS temp credentials // Generate STS temp credentials
let secret = get_token_signing_key().ok_or_else(|| s3_error!(InternalError, "token signing key not initialized"))?; let secret = resolve_token_signing_key().ok_or_else(|| s3_error!(InternalError, "token signing key not initialized"))?;
let mut new_cred = get_new_credentials_with_metadata(&token_claims, &secret) let mut new_cred = get_new_credentials_with_metadata(&token_claims, &secret)
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("credential generation failed: {e}")))?; .map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("credential generation failed: {e}")))?;
+3 -3
View File
@@ -17,7 +17,7 @@ use crate::admin::{
auth::{AdminResourceScope, validate_admin_request, validate_admin_request_with_bucket_object}, auth::{AdminResourceScope, validate_admin_request, validate_admin_request_with_bucket_object},
router::{AdminOperation, Operation, S3Router}, router::{AdminOperation, Operation, S3Router},
}; };
use crate::app::context::resolve_object_store_handle; use crate::app::context::{resolve_object_store_handle, resolve_token_signing_key};
use crate::auth::{check_key_valid, get_session_token}; use crate::auth::{check_key_valid, get_session_token};
use crate::server::{RemoteAddr, TABLE_CATALOG_COMPAT_PREFIX, TABLE_CATALOG_PREFIX}; use crate::server::{RemoteAddr, TABLE_CATALOG_COMPAT_PREFIX, TABLE_CATALOG_PREFIX};
use crate::table_catalog::{DEFAULT_WAREHOUSE_ID, TableCatalogStore}; use crate::table_catalog::{DEFAULT_WAREHOUSE_ID, TableCatalogStore};
@@ -26,7 +26,7 @@ use hyper::Method;
use matchit::Params; use matchit::Params;
use metrics::{counter, histogram}; use metrics::{counter, histogram};
use rustfs_config::MAX_ADMIN_REQUEST_BODY_SIZE; use rustfs_config::MAX_ADMIN_REQUEST_BODY_SIZE;
use rustfs_iam::{manager::get_token_signing_key, sys::SESSION_POLICY_NAME}; use rustfs_iam::sys::SESSION_POLICY_NAME;
use rustfs_policy::{ use rustfs_policy::{
auth::get_new_credentials_with_metadata, auth::get_new_credentials_with_metadata,
policy::{ policy::{
@@ -696,7 +696,7 @@ impl TableCredentialIssuer for IamTableCredentialIssuer {
serde_json::Value::String(request.scope_prefix.clone()), serde_json::Value::String(request.scope_prefix.clone()),
); );
let secret = get_token_signing_key().ok_or_else(|| s3_error!(InternalError, "token signing key not initialized"))?; let secret = resolve_token_signing_key().ok_or_else(|| s3_error!(InternalError, "token signing key not initialized"))?;
let mut credential = get_new_credentials_with_metadata(&claims, &secret) let mut credential = get_new_credentials_with_metadata(&claims, &secret)
.map_err(|err| s3_error!(InternalError, "failed to generate table credentials: {}", err))?; .map_err(|err| s3_error!(InternalError, "failed to generate table credentials: {}", err))?;
bind_table_credential_parent(&mut credential, principal); bind_table_credential_parent(&mut credential, principal);
+63 -11
View File
@@ -37,8 +37,7 @@ use super::{BucketBandwidthMonitor, DynReplicationPool, NotificationSys, Replica
use crate::config::RustFSBufferConfig; use crate::config::RustFSBufferConfig;
use rustfs_config::server_config::Config; use rustfs_config::server_config::Config;
use rustfs_credentials::Credentials; use rustfs_credentials::Credentials;
use rustfs_iam::oidc::OidcSys; use rustfs_iam::{error::Error as IamError, oidc::OidcSys, store::object::ObjectStore, sys::IamSys};
use rustfs_iam::{error::Error as IamError, store::object::ObjectStore, sys::IamSys};
use rustfs_io_metrics::{PerformanceMetrics, internode_metrics::InternodeMetrics}; use rustfs_io_metrics::{PerformanceMetrics, internode_metrics::InternodeMetrics};
use rustfs_kms::{KmsServiceManager, ObjectEncryptionService, init_global_kms_service_manager}; use rustfs_kms::{KmsServiceManager, ObjectEncryptionService, init_global_kms_service_manager};
use rustfs_lock::LockClient; use rustfs_lock::LockClient;
@@ -85,14 +84,19 @@ pub fn resolve_iam_handle() -> Option<Arc<IamSys<ObjectStore>>> {
resolve_iam_handle_with(get_global_app_context(), rustfs_iam::get_global_iam_sys) resolve_iam_handle_with(get_global_app_context(), rustfs_iam::get_global_iam_sys)
} }
/// Resolve OIDC handle using AppContext-first precedence. /// Resolve a ready IAM system handle using AppContext-first precedence.
pub fn resolve_ready_iam_handle() -> rustfs_iam::error::Result<Arc<IamSys<ObjectStore>>> {
resolve_ready_iam_handle_with(get_global_app_context(), rustfs_iam::get)
}
/// Resolve OIDC system handle using AppContext-first precedence.
pub fn resolve_oidc_handle() -> Option<Arc<OidcSys>> { pub fn resolve_oidc_handle() -> Option<Arc<OidcSys>> {
resolve_oidc_handle_with(get_global_app_context(), rustfs_iam::get_oidc) resolve_oidc_handle_with(get_global_app_context(), rustfs_iam::get_oidc)
} }
/// Resolve a ready IAM system handle using AppContext-first precedence. /// Resolve token signing key using AppContext-first precedence.
pub fn resolve_ready_iam_handle() -> rustfs_iam::error::Result<Arc<IamSys<ObjectStore>>> { pub fn resolve_token_signing_key() -> Option<String> {
resolve_ready_iam_handle_with(get_global_app_context(), rustfs_iam::get) resolve_token_signing_key_with(get_global_app_context(), rustfs_iam::manager::get_token_signing_key)
} }
/// Resolve bucket metadata handle using AppContext-first precedence. /// Resolve bucket metadata handle using AppContext-first precedence.
@@ -111,6 +115,12 @@ pub fn resolve_object_store_handle_for_context(context: Option<&AppContext>) ->
context.map(|context| context.object_store()).or_else(new_object_layer_fn) context.map(|context| context.object_store()).or_else(new_object_layer_fn)
} }
/// Resolve notify interface using AppContext-first precedence.
pub fn resolve_notify_interface() -> Arc<dyn NotifyInterface> {
let context = get_global_app_context();
resolve_notify_interface_for_context(context.as_deref())
}
/// Resolve notify interface using an explicit AppContext, falling back to the legacy global notifier. /// Resolve notify interface using an explicit AppContext, falling back to the legacy global notifier.
pub fn resolve_notify_interface_for_context(context: Option<&AppContext>) -> Arc<dyn NotifyInterface> { pub fn resolve_notify_interface_for_context(context: Option<&AppContext>) -> Arc<dyn NotifyInterface> {
context context
@@ -323,6 +333,12 @@ fn resolve_ready_iam_handle_with(
fallback() fallback()
} }
fn resolve_token_signing_key_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> Option<String>) -> Option<String> {
context
.and_then(|context| context.iam().token_signing_key())
.or_else(fallback)
}
fn resolve_bucket_metadata_handle_with( fn resolve_bucket_metadata_handle_with(
context: Option<Arc<AppContext>>, context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<RwLock<BucketMetadataSys>>>, fallback: impl FnOnce() -> Option<Arc<RwLock<BucketMetadataSys>>>,
@@ -546,7 +562,7 @@ mod tests {
}; };
use crate::config::{RustFSBufferConfig, WorkloadProfile}; use crate::config::{RustFSBufferConfig, WorkloadProfile};
use async_trait::async_trait; use async_trait::async_trait;
use rustfs_iam::{store::object::ObjectStore, sys::IamSys}; use rustfs_iam::{oidc::OidcSys, store::object::ObjectStore, sys::IamSys};
use rustfs_io_metrics::{PerformanceMetrics, internode_metrics::InternodeMetrics}; use rustfs_io_metrics::{PerformanceMetrics, internode_metrics::InternodeMetrics};
use rustfs_lock::{LocalClient, LockClient}; use rustfs_lock::{LocalClient, LockClient};
use rustfs_s3select_api::{ use rustfs_s3select_api::{
@@ -562,6 +578,8 @@ mod tests {
struct TestIamInterface { struct TestIamInterface {
ready: bool, ready: bool,
oidc: Option<Arc<OidcSys>>,
token_signing_key: Option<String>,
} }
impl IamInterface for TestIamInterface { impl IamInterface for TestIamInterface {
@@ -572,13 +590,23 @@ mod tests {
fn is_ready(&self) -> bool { fn is_ready(&self) -> bool {
self.ready self.ready
} }
fn oidc(&self) -> Option<Arc<OidcSys>> {
self.oidc.clone()
}
fn token_signing_key(&self) -> Option<String> {
self.token_signing_key.clone()
}
} }
struct TestOidcInterface; struct TestOidcInterface {
oidc: Option<Arc<OidcSys>>,
}
impl OidcInterface for TestOidcInterface { impl OidcInterface for TestOidcInterface {
fn handle(&self) -> Option<Arc<rustfs_iam::oidc::OidcSys>> { fn handle(&self) -> Option<Arc<rustfs_iam::oidc::OidcSys>> {
None self.oidc.clone()
} }
} }
@@ -985,12 +1013,30 @@ mod tests {
}; };
let context_region: s3s::region::Region = "context-region".parse().expect("test region"); let context_region: s3s::region::Region = "context-region".parse().expect("test region");
let fallback_region: s3s::region::Region = "fallback-region".parse().expect("test region"); let fallback_region: s3s::region::Region = "fallback-region".parse().expect("test region");
let context_oidc_sys = match OidcSys::empty() {
Ok(sys) => sys,
Err(err) => unreachable!("test OIDC sys should initialize: {err}"),
};
let fallback_oidc_sys = match OidcSys::empty() {
Ok(sys) => sys,
Err(err) => unreachable!("test OIDC fallback sys should initialize: {err}"),
};
let context_oidc = Arc::new(context_oidc_sys);
let fallback_oidc = Arc::new(fallback_oidc_sys);
let context_token_signing_key = "context-token-signing-key".to_string();
let fallback_token_signing_key = "fallback-token-signing-key".to_string();
let context = Arc::new(AppContext::with_test_interfaces( let context = Arc::new(AppContext::with_test_interfaces(
object_store.clone(), object_store.clone(),
AppContextTestInterfaces { AppContextTestInterfaces {
iam: Arc::new(TestIamInterface { ready: true }), iam: Arc::new(TestIamInterface {
oidc: Arc::new(TestOidcInterface), ready: true,
oidc: None,
token_signing_key: Some(context_token_signing_key.clone()),
}),
oidc: Arc::new(TestOidcInterface {
oidc: Some(context_oidc.clone()),
}),
kms: Arc::new(TestKmsInterface { kms: Arc::new(TestKmsInterface {
kms: context_kms.clone(), kms: context_kms.clone(),
}), }),
@@ -1084,6 +1130,12 @@ mod tests {
context_outbound_tls_state.generation context_outbound_tls_state.generation
); );
assert!(resolve_iam_ready_with(Some(context.clone()), || false)); assert!(resolve_iam_ready_with(Some(context.clone()), || false));
let resolved_oidc = resolve_oidc_handle_with(Some(context.clone()), || Some(fallback_oidc.clone()));
assert!(resolved_oidc.as_ref().is_some_and(|oidc| Arc::ptr_eq(oidc, &context_oidc)));
assert_eq!(
resolve_token_signing_key_with(Some(context.clone()), || Some(fallback_token_signing_key.clone())).as_deref(),
Some(context_token_signing_key.as_str())
);
assert!(Arc::ptr_eq( assert!(Arc::ptr_eq(
&resolve_bucket_metadata_handle_with(Some(context.clone()), || None).expect("context bucket metadata"), &resolve_bucket_metadata_handle_with(Some(context.clone()), || None).expect("context bucket metadata"),
&bucket_metadata &bucket_metadata
+8
View File
@@ -74,6 +74,14 @@ impl IamInterface for IamHandle {
fn is_ready(&self) -> bool { fn is_ready(&self) -> bool {
rustfs_iam::get().is_ok() rustfs_iam::get().is_ok()
} }
fn oidc(&self) -> Option<Arc<OidcSys>> {
rustfs_iam::get_oidc()
}
fn token_signing_key(&self) -> Option<String> {
rustfs_iam::manager::get_token_signing_key()
}
} }
/// Default OIDC interface adapter. /// Default OIDC interface adapter.
+7 -2
View File
@@ -23,8 +23,7 @@ use crate::config::RustFSBufferConfig;
use async_trait::async_trait; use async_trait::async_trait;
use rustfs_config::server_config::Config; use rustfs_config::server_config::Config;
use rustfs_credentials::Credentials; use rustfs_credentials::Credentials;
use rustfs_iam::oidc::OidcSys; use rustfs_iam::{oidc::OidcSys, store::object::ObjectStore, sys::IamSys};
use rustfs_iam::{store::object::ObjectStore, sys::IamSys};
use rustfs_io_metrics::{PerformanceMetrics, internode_metrics::InternodeMetrics}; use rustfs_io_metrics::{PerformanceMetrics, internode_metrics::InternodeMetrics};
use rustfs_kms::KmsServiceManager; use rustfs_kms::KmsServiceManager;
use rustfs_lock::LockClient; use rustfs_lock::LockClient;
@@ -41,6 +40,12 @@ pub trait IamInterface: Send + Sync {
#[allow(dead_code)] #[allow(dead_code)]
fn handle(&self) -> Arc<IamSys<ObjectStore>>; fn handle(&self) -> Arc<IamSys<ObjectStore>>;
fn is_ready(&self) -> bool; fn is_ready(&self) -> bool;
fn oidc(&self) -> Option<Arc<OidcSys>> {
None
}
fn token_signing_key(&self) -> Option<String> {
None
}
} }
/// OIDC interface for admin and runtime consumers. /// OIDC interface for admin and runtime consumers.
+3 -3
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::app::context::resolve_region; use crate::app::context::{resolve_notify_interface, resolve_region};
use crate::server::ShutdownHandle; use crate::server::ShutdownHandle;
use crate::storage::{ use crate::storage::{
get_bucket_notification_config, process_lambda_configurations, process_queue_configurations, process_topic_configurations, get_bucket_notification_config, process_lambda_configurations, process_queue_configurations, process_topic_configurations,
@@ -22,7 +22,6 @@ use rustfs_config::{
DEFAULT_BUFFER_MAX_SIZE, DEFAULT_BUFFER_MIN_SIZE, DEFAULT_BUFFER_PROFILE, DEFAULT_BUFFER_UNKNOWN_SIZE, DEFAULT_UPDATE_CHECK, DEFAULT_BUFFER_MAX_SIZE, DEFAULT_BUFFER_MIN_SIZE, DEFAULT_BUFFER_PROFILE, DEFAULT_BUFFER_UNKNOWN_SIZE, DEFAULT_UPDATE_CHECK,
ENV_RUSTFS_BUFFER_DEFAULT_SIZE, ENV_RUSTFS_BUFFER_MAX_SIZE, ENV_RUSTFS_BUFFER_MIN_SIZE, ENV_UPDATE_CHECK, RUSTFS_REGION, ENV_RUSTFS_BUFFER_DEFAULT_SIZE, ENV_RUSTFS_BUFFER_MAX_SIZE, ENV_RUSTFS_BUFFER_MIN_SIZE, ENV_UPDATE_CHECK, RUSTFS_REGION,
}; };
use rustfs_notify::notifier_global;
use rustfs_targets::arn::{ARN, TargetIDError}; use rustfs_targets::arn::{ARN, TargetIDError};
use rustfs_utils::get_env_usize; use rustfs_utils::get_env_usize;
use s3s::s3_error; use s3s::s3_error;
@@ -245,7 +244,8 @@ pub async fn add_bucket_notification_configuration(buckets: Vec<String>) {
); );
} }
if let Err(e) = notifier_global::add_event_specific_rules(bucket, region, &event_rules) if let Err(e) = resolve_notify_interface()
.add_event_specific_rules(bucket, region, &event_rules)
.await .await
.map_err(|e| s3_error!(InternalError, "Failed to add rules: {e}")) .map_err(|e| s3_error!(InternalError, "Failed to add rules: {e}"))
{ {
+2 -2
View File
@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
use super::{module_switch::resolve_notify_module_state, refresh_persisted_module_switches_from_store}; use super::{module_switch::resolve_notify_module_state, refresh_persisted_module_switches_from_store};
use crate::app::context::resolve_server_config; use crate::app::context::{resolve_notify_interface, resolve_server_config};
use crate::storage::{EventArgs as EcstoreEventArgs, StorageObjectInfo, register_event_dispatch_hook}; use crate::storage::{EventArgs as EcstoreEventArgs, StorageObjectInfo, register_event_dispatch_hook};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use rustfs_notify::{EventArgs as NotifyEventArgs, NotifyObjectInfo}; use rustfs_notify::{EventArgs as NotifyEventArgs, NotifyObjectInfo};
@@ -118,7 +118,7 @@ fn install_ecstore_event_dispatch_hook() {
return; return;
}; };
spawn(async move { spawn(async move {
rustfs_notify::notifier_global::notify(notify_args).await; resolve_notify_interface().notify(notify_args).await;
}); });
}); });
+3 -3
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::app::context::resolve_action_credentials; use crate::app::context::{resolve_action_credentials, resolve_notify_interface};
use crate::server::{convert_ecstore_object_info, is_audit_module_enabled, is_notify_module_enabled}; use crate::server::{convert_ecstore_object_info, is_audit_module_enabled, is_notify_module_enabled};
use crate::storage::access::{ReqInfo, request_context_from_req}; use crate::storage::access::{ReqInfo, request_context_from_req};
use crate::storage::request_context::{RequestContext, extract_request_id_from_headers}; use crate::storage::request_context::{RequestContext, extract_request_id_from_headers};
@@ -24,7 +24,7 @@ use rustfs_audit::{
global::AuditLogger, global::AuditLogger,
}; };
use rustfs_io_metrics::record_s3_op; use rustfs_io_metrics::record_s3_op;
use rustfs_notify::{EventArgsBuilder, notifier_global}; use rustfs_notify::EventArgsBuilder;
use rustfs_s3_ops::{S3Operation, operation_matches_event_name}; use rustfs_s3_ops::{S3Operation, operation_matches_event_name};
use rustfs_s3_types::EventName; use rustfs_s3_types::EventName;
use rustfs_targets::{ use rustfs_targets::{
@@ -383,7 +383,7 @@ impl Drop for OperationHelper {
if !event_args.is_replication_request() { if !event_args.is_replication_request() {
let ctx = state.request_context.clone(); let ctx = state.request_context.clone();
spawn_background_with_context(ctx, async move { spawn_background_with_context(ctx, async move {
notifier_global::notify(event_args).await; resolve_notify_interface().notify(event_args).await;
}); });
} }
} }
+3
View File
@@ -41,11 +41,13 @@ dep|rustfs/src/app/object_usecase.rs|app->interface|crate::storage::ecfs
dep|rustfs/src/app/object_usecase.rs|app->interface|crate::storage::s3_api::multipart::parse_list_parts_params dep|rustfs/src/app/object_usecase.rs|app->interface|crate::storage::s3_api::multipart::parse_list_parts_params
dep|rustfs/src/auth.rs|infra->app|crate::app::context::resolve_action_credentials dep|rustfs/src/auth.rs|infra->app|crate::app::context::resolve_action_credentials
dep|rustfs/src/config/info.rs|infra->app|crate::app::context::resolve_buffer_config dep|rustfs/src/config/info.rs|infra->app|crate::app::context::resolve_buffer_config
dep|rustfs/src/init.rs|infra->app|crate::app::context::resolve_notify_interface
dep|rustfs/src/init.rs|infra->app|crate::app::context::resolve_region dep|rustfs/src/init.rs|infra->app|crate::app::context::resolve_region
dep|rustfs/src/init.rs|infra->interface|crate::admin dep|rustfs/src/init.rs|infra->interface|crate::admin
dep|rustfs/src/protocols/client.rs|infra->app|crate::app::context::resolve_action_credentials dep|rustfs/src/protocols/client.rs|infra->app|crate::app::context::resolve_action_credentials
dep|rustfs/src/protocols/client.rs|infra->interface|crate::storage::ecfs::FS dep|rustfs/src/protocols/client.rs|infra->interface|crate::storage::ecfs::FS
dep|rustfs/src/server/audit.rs|infra->app|crate::app::context::resolve_server_config dep|rustfs/src/server/audit.rs|infra->app|crate::app::context::resolve_server_config
dep|rustfs/src/server/event.rs|infra->app|crate::app::context::resolve_notify_interface
dep|rustfs/src/server/event.rs|infra->app|crate::app::context::resolve_server_config dep|rustfs/src/server/event.rs|infra->app|crate::app::context::resolve_server_config
dep|rustfs/src/server/http.rs|infra->interface|crate::admin dep|rustfs/src/server/http.rs|infra->interface|crate::admin
dep|rustfs/src/server/layer.rs|infra->app|crate::app::context::resolve_kms_runtime_service_manager dep|rustfs/src/server/layer.rs|infra->app|crate::app::context::resolve_kms_runtime_service_manager
@@ -69,6 +71,7 @@ dep|rustfs/src/storage/access.rs|infra->app|crate::app::context::resolve_region
dep|rustfs/src/storage/concurrency/manager.rs|infra->app|crate::app::context::resolve_performance_metrics dep|rustfs/src/storage/concurrency/manager.rs|infra->app|crate::app::context::resolve_performance_metrics
dep|rustfs/src/storage/sse.rs|infra->app|crate::app::context::resolve_encryption_service dep|rustfs/src/storage/sse.rs|infra->app|crate::app::context::resolve_encryption_service
dep|rustfs/src/storage/helper.rs|infra->app|crate::app::context::resolve_action_credentials dep|rustfs/src/storage/helper.rs|infra->app|crate::app::context::resolve_action_credentials
dep|rustfs/src/storage/helper.rs|infra->app|crate::app::context::resolve_notify_interface
dep|rustfs/src/storage/rpc/disk.rs|infra->app|crate::app::context::resolve_internode_metrics dep|rustfs/src/storage/rpc/disk.rs|infra->app|crate::app::context::resolve_internode_metrics
dep|rustfs/src/storage/rpc/health.rs|infra->app|crate::app::context::resolve_local_node_name dep|rustfs/src/storage/rpc/health.rs|infra->app|crate::app::context::resolve_local_node_name
dep|rustfs/src/storage/rpc/http_service.rs|infra->app|crate::app::context::resolve_internode_metrics dep|rustfs/src/storage/rpc/http_service.rs|infra->app|crate::app::context::resolve_internode_metrics