mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Enforce read-only admin route permissions
This commit is contained in:
@@ -615,6 +615,35 @@ mod tests {
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_only_permissions_allow_reads_and_reject_writes() {
|
||||
let decision = GatewayControlDecision::synthetic(
|
||||
"/api/admin/providers".to_string(),
|
||||
Some("admin_proxy".to_string()),
|
||||
Some("providers_manage".to_string()),
|
||||
Some("create_provider".to_string()),
|
||||
Some("admin:providers".to_string()),
|
||||
);
|
||||
let permissions = read_only_management_token_permissions();
|
||||
|
||||
assert!(validate_management_token_admin_route_permission(
|
||||
&http::Method::GET,
|
||||
&decision,
|
||||
Some(&permissions),
|
||||
)
|
||||
.is_ok());
|
||||
assert_eq!(
|
||||
validate_management_token_admin_route_permission(
|
||||
&http::Method::POST,
|
||||
&decision,
|
||||
Some(&permissions),
|
||||
)
|
||||
.expect_err("read-only permissions should reject writes")
|
||||
.required_permission,
|
||||
"admin:providers:write"
|
||||
);
|
||||
}
|
||||
|
||||
fn extract_admin_route_scopes(source: &'static str) -> BTreeSet<&'static str> {
|
||||
let mut scopes = BTreeSet::new();
|
||||
let mut remaining = source;
|
||||
|
||||
@@ -18,7 +18,7 @@ pub(crate) use management_token_permissions::{
|
||||
management_token_permission_keys_from_value, management_token_permission_mode_and_summary,
|
||||
management_token_permissions_cover_all_assignable_permissions,
|
||||
management_token_required_permission, normalize_assignable_management_token_permissions,
|
||||
validate_management_token_admin_route_permission,
|
||||
read_only_management_token_permissions, validate_management_token_admin_route_permission,
|
||||
};
|
||||
pub(crate) use public::{resolve_public_request_context, GatewayPublicRequestContext};
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -2,7 +2,8 @@ use super::super::internal;
|
||||
use crate::admin_api;
|
||||
use crate::audit::attach_admin_audit_event;
|
||||
use crate::control::{
|
||||
validate_management_token_admin_route_permission, GatewayPublicRequestContext,
|
||||
read_only_management_token_permissions, validate_management_token_admin_route_permission,
|
||||
GatewayPublicRequestContext,
|
||||
};
|
||||
use crate::{AppState, GatewayError};
|
||||
use axum::body::{Body, Bytes};
|
||||
@@ -61,21 +62,32 @@ fn maybe_build_management_token_permission_denied_response(
|
||||
) -> Option<Response<Body>> {
|
||||
let decision = request_context.control_decision.as_ref()?;
|
||||
let admin_principal = decision.admin_principal.as_ref()?;
|
||||
let token_id = admin_principal.management_token_id.as_deref()?;
|
||||
let audit_admin_read_only_permissions;
|
||||
let token_permissions = if crate::roles::can_write_admin_console(&admin_principal.user_role) {
|
||||
admin_principal.management_token_permissions.as_deref()
|
||||
} else {
|
||||
audit_admin_read_only_permissions = read_only_management_token_permissions();
|
||||
Some(audit_admin_read_only_permissions.as_slice())
|
||||
};
|
||||
let denied = validate_management_token_admin_route_permission(
|
||||
&request_context.request_method,
|
||||
decision,
|
||||
admin_principal.management_token_permissions.as_deref(),
|
||||
token_permissions,
|
||||
)
|
||||
.err()?;
|
||||
let actor_id = admin_principal
|
||||
.management_token_id
|
||||
.as_deref()
|
||||
.unwrap_or(admin_principal.user_id.as_str());
|
||||
|
||||
warn!(
|
||||
trace_id = %request_context.trace_id,
|
||||
admin_management_token_id = %token_id,
|
||||
admin_actor_id = %actor_id,
|
||||
admin_user_role = %admin_principal.user_role,
|
||||
route_family = decision.route_family.as_deref().unwrap_or("unknown"),
|
||||
route_kind = decision.route_kind.as_deref().unwrap_or("unknown"),
|
||||
required_permission = %denied.required_permission,
|
||||
"management token permission denied"
|
||||
"admin route permission denied"
|
||||
);
|
||||
|
||||
let mut response = (
|
||||
@@ -91,10 +103,10 @@ fn maybe_build_management_token_permission_denied_response(
|
||||
.into_response();
|
||||
attach_admin_audit_event(
|
||||
&mut response,
|
||||
"admin_management_token_permission_denied",
|
||||
"admin_route_permission_denied",
|
||||
"permission_denied",
|
||||
"management_token_permission",
|
||||
token_id,
|
||||
"admin_route_permission",
|
||||
actor_id,
|
||||
);
|
||||
Some(response)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user