mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-12 22:20:19 +08:00
fix(gateway): apply group policy to admin-owned keys
This commit is contained in:
@@ -1781,20 +1781,13 @@ impl GatewayDataState {
|
||||
let Some(mut snapshot) = snapshot else {
|
||||
return Ok(None);
|
||||
};
|
||||
if snapshot.user_role.eq_ignore_ascii_case("admin") && !snapshot.api_key_is_standalone {
|
||||
apply_admin_unrestricted_auth_snapshot(&mut snapshot);
|
||||
return Ok(Some(GatewayAuthApiKeySnapshot::from_stored(
|
||||
snapshot,
|
||||
now_unix_secs,
|
||||
)));
|
||||
}
|
||||
let Some(repository) = self.user_reader.as_ref() else {
|
||||
return Ok(Some(GatewayAuthApiKeySnapshot::from_stored(
|
||||
snapshot,
|
||||
now_unix_secs,
|
||||
)));
|
||||
};
|
||||
let Some(user) = crate::request_diagnostics::observe_db_operation(
|
||||
let Some(_) = crate::request_diagnostics::observe_db_operation(
|
||||
"auth_user_policy",
|
||||
self.database_pool_summary(),
|
||||
repository.find_user_auth_by_id(&snapshot.user_id),
|
||||
@@ -1806,14 +1799,6 @@ impl GatewayDataState {
|
||||
now_unix_secs,
|
||||
)));
|
||||
};
|
||||
if user.role.eq_ignore_ascii_case("admin") && !snapshot.api_key_is_standalone {
|
||||
snapshot.user_role = user.role;
|
||||
apply_admin_unrestricted_auth_snapshot(&mut snapshot);
|
||||
return Ok(Some(GatewayAuthApiKeySnapshot::from_stored(
|
||||
snapshot,
|
||||
now_unix_secs,
|
||||
)));
|
||||
}
|
||||
let groups = self
|
||||
.effective_user_groups_for_user(&snapshot.user_id)
|
||||
.await?;
|
||||
@@ -1925,18 +1910,6 @@ impl GatewayDataState {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_admin_unrestricted_auth_snapshot(snapshot: &mut StoredAuthApiKeySnapshot) {
|
||||
snapshot.user_allowed_providers = None;
|
||||
snapshot.user_allowed_api_formats = None;
|
||||
snapshot.user_allowed_models = None;
|
||||
snapshot.user_rate_limit = None;
|
||||
snapshot.api_key_allowed_providers = None;
|
||||
snapshot.api_key_allowed_api_formats = None;
|
||||
snapshot.api_key_allowed_models = None;
|
||||
snapshot.api_key_rate_limit = None;
|
||||
snapshot.api_key_concurrent_limit = None;
|
||||
}
|
||||
|
||||
// Per-user list policy columns are retained only for legacy import/export compatibility.
|
||||
// Runtime authorization and user-facing catalogs must both treat group policies as authoritative.
|
||||
fn resolve_group_effective_list_policies(
|
||||
|
||||
@@ -1673,7 +1673,7 @@ async fn gateway_handles_admin_user_api_key_routes_locally_with_trusted_admin_pr
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn admin_created_user_key_inherits_target_user_policy_not_admin_policy() {
|
||||
async fn admin_created_user_keys_inherit_owner_group_policy() {
|
||||
let mut admin_snapshot = sample_admin_api_key_snapshot("admin-user", "admin-seed-key");
|
||||
admin_snapshot.user_role = "admin".to_string();
|
||||
let auth_repository = Arc::new(InMemoryAuthApiKeySnapshotRepository::seed(vec![
|
||||
@@ -1855,6 +1855,44 @@ async fn admin_created_user_key_inherits_target_user_policy_not_admin_policy() {
|
||||
"an omitted key override must inherit target settings"
|
||||
);
|
||||
|
||||
let response = reqwest::Client::new()
|
||||
.post(format!("{gateway_url}/api/admin/users/admin-user/api-keys"))
|
||||
.header(crate::constants::GATEWAY_HEADER, "rust-phase3b")
|
||||
.header(TRUSTED_ADMIN_USER_ID_HEADER, "admin-user")
|
||||
.header(TRUSTED_ADMIN_USER_ROLE_HEADER, "admin")
|
||||
.header(TRUSTED_ADMIN_SESSION_ID_HEADER, "admin-session")
|
||||
.json(&json!({"name": "admin-user-key"}))
|
||||
.send()
|
||||
.await
|
||||
.expect("request should succeed");
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let payload: serde_json::Value = response.json().await.expect("response should parse");
|
||||
let plaintext_key = payload["key"].as_str().expect("plaintext key should exist");
|
||||
|
||||
let resolved = inspection_state
|
||||
.read_cached_auth_api_key_snapshot_by_key_hash(
|
||||
&hash_api_key(plaintext_key),
|
||||
chrono::Utc::now().timestamp().max(0) as u64,
|
||||
)
|
||||
.await
|
||||
.expect("admin-owned user key snapshot should resolve")
|
||||
.expect("admin-owned user key snapshot should exist");
|
||||
assert_eq!(resolved.user_id, "admin-user");
|
||||
assert!(!resolved.api_key_is_standalone);
|
||||
assert_eq!(
|
||||
resolved.effective_allowed_providers(),
|
||||
Some(&["openai".to_string()][..])
|
||||
);
|
||||
assert_eq!(
|
||||
resolved.effective_allowed_api_formats(),
|
||||
Some(&["openai:responses".to_string()][..])
|
||||
);
|
||||
assert_eq!(
|
||||
resolved.effective_allowed_models(),
|
||||
Some(&["gpt-5.4".to_string()][..])
|
||||
);
|
||||
assert_eq!(resolved.user_rate_limit, Some(100));
|
||||
|
||||
gateway_handle.abort();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user