diff --git a/apps/recorder/src/auth/errors.rs b/apps/recorder/src/auth/errors.rs index 79845a2..dc9445b 100644 --- a/apps/recorder/src/auth/errors.rs +++ b/apps/recorder/src/auth/errors.rs @@ -1,5 +1,6 @@ use std::fmt; +use async_graphql::dynamic::ResolverContext; use axum::{ Json, http::StatusCode, @@ -75,14 +76,48 @@ pub enum AuthError { #[error("Subject missing")] OidcSubMissingError, #[error(fmt = display_graphql_permission_error)] - GraphQLPermissionError(async_graphql::Error), + GraphQLPermissionError { + inner_error: async_graphql::Error, + field: String, + column: String, + context_path: String, + }, +} + +impl AuthError { + pub fn from_graphql_subscribe_id_guard( + inner_error: async_graphql::Error, + context: &ResolverContext, + field_name: &str, + column_name: &str, + ) -> AuthError { + AuthError::GraphQLPermissionError { + inner_error, + field: field_name.to_string(), + column: column_name.to_string(), + context_path: context + .ctx + .path_node + .map(|p| p.to_string_vec().join("")) + .unwrap_or_default(), + } + } } fn display_graphql_permission_error( - error: &async_graphql::Error, + inner_error: &async_graphql::Error, + field: &String, + column: &String, + context_path: &String, formatter: &mut fmt::Formatter<'_>, ) -> fmt::Result { - write!(formatter, "GraphQL permission denied: {}", error.message) + write!( + formatter, + "GraphQL permission denied since {context_path}{}{field}{}{column}: {}", + (if field.is_empty() { "" } else { "." }), + (if column.is_empty() { "" } else { "." }), + inner_error.message + ) } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/apps/recorder/src/graphql/guard.rs b/apps/recorder/src/graphql/guard.rs index 8d29899..14b3482 100644 --- a/apps/recorder/src/graphql/guard.rs +++ b/apps/recorder/src/graphql/guard.rs @@ -24,7 +24,7 @@ fn guard_data_object_accessor_with_subscriber_id( if id == subscriber_id as i64 { Ok(()) } else { - Err(async_graphql::Error::new("subscriber permission denied")) + Err(async_graphql::Error::new("subscriber not match")) } } @@ -43,7 +43,7 @@ fn guard_data_object_accessor_with_optional_subscriber_id( if id == subscriber_id as i64 { Ok(()) } else { - Err(async_graphql::Error::new("subscriber permission denied")) + Err(async_graphql::Error::new("subscriber not match")) } } else { Ok(()) @@ -66,7 +66,7 @@ fn guard_filter_object_accessor_with_subscriber_id( if id == subscriber_id as i64 { Ok(()) } else { - Err(async_graphql::Error::new("subscriber permission denied")) + Err(async_graphql::Error::new("subscriber not match")) } } @@ -100,7 +100,7 @@ where entity_name, context.entity_delete_mutation.mutation_suffix.clone() )); - let entity_delete_filter_field_name = + let entity_delete_mutation_filter_field_name = Arc::new(context.entity_delete_mutation.filter_field.clone()); let entity_update_mutation_field_name = Arc::new(format!( "{}{}", @@ -126,6 +126,14 @@ where &column_name, subscriber_id, ) + }) + .map_err(|inner_error| { + AuthError::from_graphql_subscribe_id_guard( + inner_error, + context, + &entity_create_one_mutation_data_field_name, + &column_name, + ) }), field if field == entity_create_batch_mutation_field_name.as_str() => context .args @@ -140,16 +148,32 @@ where ) }) }) + }) + .map_err(|inner_error| { + AuthError::from_graphql_subscribe_id_guard( + inner_error, + context, + &entity_create_batch_mutation_data_field_name, + &column_name, + ) }), field if field == entity_delete_mutation_field_name.as_str() => context .args - .try_get(&entity_delete_filter_field_name) + .try_get(&entity_delete_mutation_filter_field_name) .and_then(|filter_value| { guard_filter_object_accessor_with_subscriber_id( filter_value, &column_name, subscriber_id, ) + }) + .map_err(|inner_error| { + AuthError::from_graphql_subscribe_id_guard( + inner_error, + context, + &entity_delete_mutation_filter_field_name, + &column_name, + ) }), field if field == entity_update_mutation_field_name.as_str() => context .args @@ -161,6 +185,14 @@ where subscriber_id, ) }) + .map_err(|inner_error| { + AuthError::from_graphql_subscribe_id_guard( + inner_error, + context, + &entity_update_mutation_filter_field_name, + &column_name, + ) + }) .and_then(|_| { match context.args.get(&entity_update_mutation_data_field_name) { Some(data_value) => { @@ -169,6 +201,14 @@ where &column_name, subscriber_id, ) + .map_err(|inner_error| { + AuthError::from_graphql_subscribe_id_guard( + inner_error, + context, + &entity_update_mutation_data_field_name, + &column_name, + ) + }) } None => Ok(()), } @@ -182,13 +222,23 @@ where &column_name, subscriber_id, ) + }) + .map_err(|inner_error| { + AuthError::from_graphql_subscribe_id_guard( + inner_error, + context, + &entity_query_filter_field_name, + &column_name, + ) }), - field => Err(async_graphql::Error::new(format!( - "unsupport graphql field {}", - field - ))), + field => Err(AuthError::from_graphql_subscribe_id_guard( + async_graphql::Error::new("unsupport graphql field"), + context, + field, + "", + )), }; - match validation_result.map_err(AuthError::GraphQLPermissionError) { + match validation_result { Ok(_) => GuardAction::Allow, Err(err) => GuardAction::Block(Some(err.to_string())), }