From e15ea184d9c3b057549afe8d245bb69a4d5afcdc Mon Sep 17 00:00:00 2001 From: Rachit Naithani <81706961+racnan@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:08:35 +0530 Subject: [PATCH] feat(user): implement entity level authorization (#5819) --- crates/router/src/analytics.rs | 246 ++++++++++++++---- crates/router/src/consts.rs | 2 +- crates/router/src/consts/user_role.rs | 1 + crates/router/src/routes/admin.rs | 26 +- crates/router/src/routes/api_keys.rs | 10 + crates/router/src/routes/blocklist.rs | 21 +- .../router/src/routes/connector_onboarding.rs | 16 +- crates/router/src/routes/customers.rs | 46 +++- crates/router/src/routes/disputes.rs | 41 ++- crates/router/src/routes/mandates.rs | 6 +- crates/router/src/routes/payment_methods.rs | 11 +- crates/router/src/routes/payments.rs | 61 ++++- crates/router/src/routes/payouts.rs | 36 ++- crates/router/src/routes/refunds.rs | 36 ++- crates/router/src/routes/routing.rs | 182 ++++++++++--- crates/router/src/routes/user.rs | 47 +++- crates/router/src/routes/user_role.rs | 56 +++- crates/router/src/routes/verification.rs | 11 +- crates/router/src/routes/verify_connector.rs | 6 +- crates/router/src/routes/webhook_events.rs | 4 + crates/router/src/services/authentication.rs | 76 +++--- crates/router/src/services/authorization.rs | 86 +++--- .../src/services/authorization/roles.rs | 2 +- .../authorization/roles/predefined_roles.rs | 19 ++ crates/router/src/utils/user_role.rs | 4 +- 25 files changed, 806 insertions(+), 246 deletions(-) diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index a6e94ed294a0..7c4d1acc6bfb 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -20,6 +20,7 @@ pub mod routes { GetRefundFilterRequest, GetRefundMetricRequest, GetSdkEventFiltersRequest, GetSdkEventMetricRequest, ReportRequest, }; + use common_enums::EntityType; use error_stack::{report, ResultExt}; use crate::{ @@ -393,7 +394,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -429,7 +433,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -472,7 +479,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -510,7 +520,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -546,7 +559,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -589,7 +605,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -627,7 +646,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -663,7 +685,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -706,7 +731,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -738,7 +766,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -774,7 +805,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -811,7 +845,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -848,7 +885,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -876,7 +916,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -902,7 +945,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -935,7 +981,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -961,7 +1010,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -989,7 +1041,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1015,7 +1070,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1048,7 +1106,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1070,7 +1131,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1096,7 +1160,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1126,7 +1193,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1157,7 +1227,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1186,7 +1259,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1234,7 +1310,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1280,7 +1359,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Organization, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1333,7 +1415,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1381,7 +1466,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1427,7 +1515,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Organization, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1480,7 +1571,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1528,7 +1622,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1574,7 +1671,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Organization, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1626,7 +1726,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::GenerateReport), + &auth::JWTAuth { + permission: Permission::GenerateReport, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1664,7 +1767,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1700,7 +1806,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1743,7 +1852,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1771,7 +1883,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1797,7 +1912,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1830,7 +1948,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1859,7 +1980,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1899,7 +2023,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1939,7 +2066,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1967,7 +2097,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -2000,7 +2133,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -2026,7 +2162,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -2064,7 +2203,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -2107,7 +2249,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -2143,7 +2288,10 @@ pub mod routes { .await .map(ApplicationResponse::Json) }, - &auth::JWTAuth(Permission::Analytics), + &auth::JWTAuth { + permission: Permission::Analytics, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs index d7afe8dafde5..3f315360211f 100644 --- a/crates/router/src/consts.rs +++ b/crates/router/src/consts.rs @@ -90,7 +90,7 @@ pub const EMAIL_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day #[cfg(feature = "email")] pub const EMAIL_TOKEN_BLACKLIST_PREFIX: &str = "BET_"; -pub const ROLE_CACHE_PREFIX: &str = "CR_"; +pub const ROLE_INFO_CACHE_PREFIX: &str = "CR_INFO_"; #[cfg(feature = "olap")] pub const VERIFY_CONNECTOR_ID_PREFIX: &str = "conn_verify"; diff --git a/crates/router/src/consts/user_role.rs b/crates/router/src/consts/user_role.rs index 672e58300130..fbabec67291e 100644 --- a/crates/router/src/consts/user_role.rs +++ b/crates/router/src/consts/user_role.rs @@ -5,5 +5,6 @@ pub const ROLE_ID_MERCHANT_IAM_ADMIN: &str = "merchant_iam_admin"; pub const ROLE_ID_MERCHANT_DEVELOPER: &str = "merchant_developer"; pub const ROLE_ID_MERCHANT_OPERATOR: &str = "merchant_operator"; pub const ROLE_ID_MERCHANT_CUSTOMER_SUPPORT: &str = "merchant_customer_support"; +pub const ROLE_ID_PROFILE_CUSTOMER_SUPPORT: &str = "profile_customer_support"; pub const INTERNAL_USER_MERCHANT_ID: &str = "juspay000"; pub const MAX_ROLE_NAME_LENGTH: usize = 64; diff --git a/crates/router/src/routes/admin.rs b/crates/router/src/routes/admin.rs index ae97bfe60447..ae92360b13e2 100644 --- a/crates/router/src/routes/admin.rs +++ b/crates/router/src/routes/admin.rs @@ -1,4 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -118,6 +119,7 @@ pub async fn retrieve_merchant_account( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -170,6 +172,7 @@ pub async fn update_merchant_account( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -230,6 +233,7 @@ pub async fn connector_create( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -261,6 +265,7 @@ pub async fn connector_create( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -323,6 +328,7 @@ pub async fn connector_retrieve( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantConnectorAccountRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -361,6 +367,7 @@ pub async fn connector_retrieve( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantConnectorAccountRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -406,6 +413,7 @@ pub async fn payment_connector_list( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantConnectorAccountRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -457,6 +465,7 @@ pub async fn payment_connector_list_profile( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantConnectorAccountRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -517,6 +526,7 @@ pub async fn connector_update( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -568,6 +578,7 @@ pub async fn connector_update( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -623,6 +634,7 @@ pub async fn connector_delete( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -661,6 +673,7 @@ pub async fn connector_delete( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -743,6 +756,7 @@ pub async fn business_profile_create( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -773,6 +787,7 @@ pub async fn business_profile_create( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -807,6 +822,7 @@ pub async fn business_profile_retrieve( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -837,6 +853,7 @@ pub async fn business_profile_retrieve( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -872,6 +889,7 @@ pub async fn business_profile_update( &auth::JWTAuthMerchantAndProfileFromRoute { merchant_id: merchant_id.clone(), profile_id: profile_id.clone(), + minimum_entity_level: EntityType::Merchant, required_permission: Permission::MerchantAccountWrite, }, req.headers(), @@ -904,6 +922,7 @@ pub async fn business_profile_update( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -955,6 +974,7 @@ pub async fn business_profiles_list( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -989,6 +1009,7 @@ pub async fn business_profiles_list_at_profile_level( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -1018,7 +1039,10 @@ pub async fn toggle_connector_agnostic_mit( |state, _, req, _| connector_agnostic_mit_toggle(state, &merchant_id, &profile_id, req), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/api_keys.rs b/crates/router/src/routes/api_keys.rs index 68e5687e249f..71632cc57496 100644 --- a/crates/router/src/routes/api_keys.rs +++ b/crates/router/src/routes/api_keys.rs @@ -1,4 +1,5 @@ use actix_web::{web, HttpRequest, Responder}; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -37,6 +38,7 @@ pub async fn api_key_create( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::ApiKeyWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -67,6 +69,7 @@ pub async fn api_key_create( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::ApiKeyWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -104,6 +107,7 @@ pub async fn api_key_retrieve( &auth::AdminApiAuthWithMerchantIdFromHeader, &auth::JWTAuthMerchantFromHeader { required_permission: Permission::ApiKeyRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -136,6 +140,7 @@ pub async fn api_key_retrieve( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::ApiKeyRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -172,6 +177,7 @@ pub async fn api_key_update( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::ApiKeyWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -204,6 +210,7 @@ pub async fn api_key_update( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::ApiKeyWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -237,6 +244,7 @@ pub async fn api_key_revoke( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::ApiKeyWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -266,6 +274,7 @@ pub async fn api_key_revoke( &auth::JWTAuthMerchantFromRoute { merchant_id: merchant_id.clone(), required_permission: Permission::ApiKeyWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -318,6 +327,7 @@ pub async fn api_key_list( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::ApiKeyRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), diff --git a/crates/router/src/routes/blocklist.rs b/crates/router/src/routes/blocklist.rs index f2a70a7b9054..4738df5ed2ca 100644 --- a/crates/router/src/routes/blocklist.rs +++ b/crates/router/src/routes/blocklist.rs @@ -1,5 +1,6 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::blocklist as api_blocklist; +use common_enums::EntityType; use router_env::Flow; use crate::{ @@ -36,7 +37,10 @@ pub async fn add_entry_to_blocklist( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -72,7 +76,10 @@ pub async fn remove_entry_from_blocklist( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -110,7 +117,10 @@ pub async fn list_blocked_payment_methods( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantAccountRead), + &auth::JWTAuth { + permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -148,7 +158,10 @@ pub async fn toggle_blocklist_guard( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/connector_onboarding.rs b/crates/router/src/routes/connector_onboarding.rs index f5555f5bf9bf..f7494e182c19 100644 --- a/crates/router/src/routes/connector_onboarding.rs +++ b/crates/router/src/routes/connector_onboarding.rs @@ -1,5 +1,6 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::connector_onboarding as api_types; +use common_enums::EntityType; use router_env::Flow; use super::AppState; @@ -21,7 +22,10 @@ pub async fn get_action_url( &http_req, req_payload.clone(), core::get_action_url, - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -40,7 +44,10 @@ pub async fn sync_onboarding_status( &http_req, req_payload.clone(), core::sync_onboarding_status, - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -59,7 +66,10 @@ pub async fn reset_tracking_id( &http_req, req_payload.clone(), core::reset_tracking_id, - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/routes/customers.rs b/crates/router/src/routes/customers.rs index 2e3ce35a974a..66ff1f8e323d 100644 --- a/crates/router/src/routes/customers.rs +++ b/crates/router/src/routes/customers.rs @@ -1,4 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse, Responder}; +use common_enums::EntityType; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] use common_utils::id_type; use router_env::{instrument, tracing, Flow}; @@ -25,7 +26,10 @@ pub async fn customers_create( |state, auth, req, _| create_customer(state, auth.merchant_account, auth.key_store, req), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::CustomerWrite), + &auth::JWTAuth { + permission: Permission::CustomerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -48,7 +52,10 @@ pub async fn customers_retrieve( .into_inner(); let auth = if auth::is_jwt_auth(req.headers()) { - Box::new(auth::JWTAuth(Permission::CustomerRead)) + Box::new(auth::JWTAuth { + permission: Permission::CustomerRead, + minimum_entity_level: EntityType::Merchant, + }) } else { match auth::is_ephemeral_auth(req.headers()) { Ok(auth) => auth, @@ -88,7 +95,10 @@ pub async fn customers_retrieve( let payload = web::Json(customers::GlobalId::new(path.into_inner())).into_inner(); let auth = if auth::is_jwt_auth(req.headers()) { - Box::new(auth::JWTAuth(Permission::CustomerRead)) + Box::new(auth::JWTAuth { + permission: Permission::CustomerRead, + minimum_entity_level: EntityType::Merchant, + }) } else { match auth::is_ephemeral_auth(req.headers()) { Ok(auth) => auth, @@ -133,7 +143,10 @@ pub async fn customers_list( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::CustomerRead), + &auth::JWTAuth { + permission: Permission::CustomerRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -169,7 +182,10 @@ pub async fn customers_update( }, auth::auth_type( &auth::ApiKeyAuth, - &auth::JWTAuth(Permission::CustomerWrite), + &auth::JWTAuth { + permission: Permission::CustomerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -204,7 +220,10 @@ pub async fn customers_update( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::CustomerWrite), + &auth::JWTAuth { + permission: Permission::CustomerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -230,7 +249,10 @@ pub async fn customers_delete( |state, auth, req, _| delete_customer(state, auth.merchant_account, req, auth.key_store), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::CustomerWrite), + &auth::JWTAuth { + permission: Permission::CustomerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -259,7 +281,10 @@ pub async fn customers_delete( |state, auth, req, _| delete_customer(state, auth.merchant_account, req, auth.key_store), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::CustomerWrite), + &auth::JWTAuth { + permission: Permission::CustomerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -294,7 +319,10 @@ pub async fn get_customer_mandates( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MandateRead), + &auth::JWTAuth { + permission: Permission::MandateRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/disputes.rs b/crates/router/src/routes/disputes.rs index e8edcd704d7b..98ba33a64b49 100644 --- a/crates/router/src/routes/disputes.rs +++ b/crates/router/src/routes/disputes.rs @@ -1,6 +1,7 @@ use actix_multipart::Multipart; use actix_web::{web, HttpRequest, HttpResponse}; use api_models::disputes as dispute_models; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use crate::{core::api_locking, services::authorization::permissions::Permission}; @@ -48,7 +49,10 @@ pub async fn retrieve_dispute( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeRead), + &auth::JWTAuth { + permission: Permission::DisputeRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -97,7 +101,10 @@ pub async fn retrieve_disputes_list( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeRead), + &auth::JWTAuth { + permission: Permission::DisputeRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -152,7 +159,10 @@ pub async fn retrieve_disputes_list_profile( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeRead), + &auth::JWTAuth { + permission: Permission::DisputeRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -201,7 +211,10 @@ pub async fn accept_dispute( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeWrite), + &auth::JWTAuth { + permission: Permission::DisputeWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -244,7 +257,10 @@ pub async fn submit_dispute_evidence( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeWrite), + &auth::JWTAuth { + permission: Permission::DisputeWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -295,7 +311,10 @@ pub async fn attach_dispute_evidence( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeWrite), + &auth::JWTAuth { + permission: Permission::DisputeWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -338,7 +357,10 @@ pub async fn retrieve_dispute_evidence( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeRead), + &auth::JWTAuth { + permission: Permission::DisputeRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -376,7 +398,10 @@ pub async fn delete_dispute_evidence( |state, auth, req, _| disputes::delete_evidence(state, auth.merchant_account, req), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::DisputeWrite), + &auth::JWTAuth { + permission: Permission::DisputeWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/mandates.rs b/crates/router/src/routes/mandates.rs index d2c5d5e46440..70b36f879833 100644 --- a/crates/router/src/routes/mandates.rs +++ b/crates/router/src/routes/mandates.rs @@ -1,4 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -131,7 +132,10 @@ pub async fn retrieve_mandates_list( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MandateRead), + &auth::JWTAuth { + permission: Permission::MandateRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs index b3c7f5cc59b6..e4d7337ef72c 100644 --- a/crates/router/src/routes/payment_methods.rs +++ b/crates/router/src/routes/payment_methods.rs @@ -4,6 +4,7 @@ ))] use actix_multipart::form::MultipartForm; use actix_web::{web, HttpRequest, HttpResponse}; +use common_enums::EntityType; use common_utils::{errors::CustomResult, id_type}; use diesel_models::enums::IntentStatus; use error_stack::ResultExt; @@ -663,11 +664,17 @@ pub async fn list_countries_currencies_for_connector_payment_method( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantConnectorAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::MerchantConnectorAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index 95b65e5be573..f249285c554a 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -6,6 +6,7 @@ pub mod helpers; use actix_web::{web, Responder}; use api_models::payments::HeaderPayload; +use common_enums::EntityType; use error_stack::report; use masking::PeekInterface; use router_env::{env, instrument, logger, tracing, types, Flow}; @@ -149,7 +150,10 @@ pub async fn payments_create( env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth), _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PaymentWrite), + &auth::JWTAuth { + permission: Permission::PaymentWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), }, @@ -309,7 +313,10 @@ pub async fn payments_retrieve( }, auth::auth_type( &*auth_type, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), locking_action, @@ -1016,7 +1023,10 @@ pub async fn payments_list( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -1073,7 +1083,10 @@ pub async fn profile_payments_list( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -1103,7 +1116,10 @@ pub async fn payments_list_by_filter( req, ) }, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1132,7 +1148,10 @@ pub async fn profile_payments_list_by_filter( req, ) }, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1155,7 +1174,10 @@ pub async fn get_filters_for_payments( |state, auth: auth::AuthenticationData, req, _| { payments::get_filters_for_payments(state, auth.merchant_account, auth.key_store, req) }, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1176,7 +1198,10 @@ pub async fn get_payment_filters( |state, auth: auth::AuthenticationData, _, _| { payments::get_payment_filters(state, auth.merchant_account, None) }, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1201,7 +1226,10 @@ pub async fn get_payment_filters_profile( auth.profile_id.map(|profile_id| vec![profile_id]), ) }, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1224,7 +1252,10 @@ pub async fn get_payments_aggregates( |state, auth: auth::AuthenticationData, req, _| { payments::get_aggregates_for_payments(state, auth.merchant_account, req) }, - &auth::JWTAuth(Permission::PaymentRead), + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -1275,7 +1306,10 @@ pub async fn payments_approve( env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth), _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PaymentWrite), + &auth::JWTAuth { + permission: Permission::PaymentWrite, + minimum_entity_level: EntityType::Profile, + }, http_req.headers(), ), }, @@ -1331,7 +1365,10 @@ pub async fn payments_reject( env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth), _ => auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PaymentWrite), + &auth::JWTAuth { + permission: Permission::PaymentWrite, + minimum_entity_level: EntityType::Profile, + }, http_req.headers(), ), }, diff --git a/crates/router/src/routes/payouts.rs b/crates/router/src/routes/payouts.rs index 8c45f9fdfd94..50c18d71f2a4 100644 --- a/crates/router/src/routes/payouts.rs +++ b/crates/router/src/routes/payouts.rs @@ -2,6 +2,7 @@ use actix_web::{ body::{BoxBody, MessageBody}, web, HttpRequest, HttpResponse, Responder, }; +use common_enums::EntityType; use common_utils::consts; use router_env::{instrument, tracing, Flow}; @@ -75,7 +76,10 @@ pub async fn payouts_retrieve( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -213,7 +217,10 @@ pub async fn payouts_list( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -248,7 +255,10 @@ pub async fn payouts_list_profile( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -277,7 +287,10 @@ pub async fn payouts_list_by_filter( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -312,7 +325,10 @@ pub async fn payouts_list_by_filter_profile( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -341,7 +357,10 @@ pub async fn payouts_list_available_filters_for_merchant( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -375,7 +394,10 @@ pub async fn payouts_list_available_filters_for_profile( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::PayoutRead), + &auth::JWTAuth { + permission: Permission::PayoutRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/refunds.rs b/crates/router/src/routes/refunds.rs index bdef96794f48..4b964dba6262 100644 --- a/crates/router/src/routes/refunds.rs +++ b/crates/router/src/routes/refunds.rs @@ -1,4 +1,5 @@ use actix_web::{web, HttpRequest, HttpResponse}; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -47,7 +48,10 @@ pub async fn refunds_create( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundWrite), + &auth::JWTAuth { + permission: Permission::RefundWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -108,7 +112,10 @@ pub async fn refunds_retrieve( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundRead), + &auth::JWTAuth { + permission: Permission::RefundRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -233,7 +240,10 @@ pub async fn refunds_list( |state, auth, req, _| refund_list(state, auth.merchant_account, None, req), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundRead), + &auth::JWTAuth { + permission: Permission::RefundRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -278,7 +288,10 @@ pub async fn refunds_list_profile( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundRead), + &auth::JWTAuth { + permission: Permission::RefundRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -316,7 +329,10 @@ pub async fn refunds_filter_list( |state, auth, req, _| refund_filter_list(state, auth.merchant_account, req), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundRead), + &auth::JWTAuth { + permission: Permission::RefundRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -349,7 +365,10 @@ pub async fn get_refunds_filters(state: web::Data, req: HttpRequest) - |state, auth, _, _| get_filters_for_refunds(state, auth.merchant_account, None), auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundRead), + &auth::JWTAuth { + permission: Permission::RefundRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -391,7 +410,10 @@ pub async fn get_refunds_filters_profile( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RefundRead), + &auth::JWTAuth { + permission: Permission::RefundRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 09bf77c62ef1..8533c9ddea98 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -5,6 +5,7 @@ use actix_web::{web, HttpRequest, Responder}; use api_models::{enums, routing as routing_types, routing::RoutingRetrieveQuery}; +use common_enums::EntityType; use router_env::{ tracing::{self, instrument}, Flow, @@ -42,11 +43,17 @@ pub async fn routing_create_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -79,11 +86,17 @@ pub async fn routing_link_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -125,6 +138,7 @@ pub async fn routing_link_config( &auth::JWTAuthProfileFromRoute { profile_id: routing_payload_wrapper.profile_id, required_permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -132,6 +146,7 @@ pub async fn routing_link_config( &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, required_permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) @@ -164,11 +179,17 @@ pub async fn routing_retrieve_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -200,11 +221,17 @@ pub async fn list_routing_configs( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -236,11 +263,17 @@ pub async fn list_routing_configs_for_profile( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -283,6 +316,7 @@ pub async fn routing_unlink_config( &auth::JWTAuthProfileFromRoute { profile_id: path, required_permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) @@ -316,11 +350,17 @@ pub async fn routing_unlink_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -355,11 +395,17 @@ pub async fn routing_update_default_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -389,11 +435,17 @@ pub async fn routing_update_default_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingWrite), + &auth::JWTAuth { + permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -426,6 +478,7 @@ pub async fn routing_retrieve_default_config( &auth::JWTAuthProfileFromRoute { profile_id: path, required_permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -433,6 +486,7 @@ pub async fn routing_retrieve_default_config( &auth::JWTAuthProfileFromRoute { profile_id: path, required_permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, }, api_locking::LockAction::NotApplicable, )) @@ -457,11 +511,17 @@ pub async fn routing_retrieve_default_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -491,11 +551,17 @@ pub async fn upsert_surcharge_decision_manager_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -522,11 +588,17 @@ pub async fn delete_surcharge_decision_manager_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -553,11 +625,17 @@ pub async fn retrieve_surcharge_decision_manager_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::SurchargeDecisionManagerRead), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::SurchargeDecisionManagerRead), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, ) .await @@ -587,11 +665,17 @@ pub async fn upsert_decision_manager_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::SurchargeDecisionManagerRead), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::SurchargeDecisionManagerRead), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -619,11 +703,17 @@ pub async fn delete_decision_manager_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerWrite, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -647,11 +737,17 @@ pub async fn retrieve_decision_manager_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::SurchargeDecisionManagerRead), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::SurchargeDecisionManagerRead), + &auth::JWTAuth { + permission: Permission::SurchargeDecisionManagerRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, ) .await @@ -690,6 +786,7 @@ pub async fn routing_retrieve_linked_config( &auth::JWTAuthProfileFromRoute { profile_id, required_permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -697,6 +794,7 @@ pub async fn routing_retrieve_linked_config( &auth::JWTAuthProfileFromRoute { profile_id, required_permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, }, api_locking::LockAction::NotApplicable, )) @@ -720,11 +818,17 @@ pub async fn routing_retrieve_linked_config( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), #[cfg(feature = "release")] - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, + }, api_locking::LockAction::NotApplicable, )) .await @@ -767,6 +871,7 @@ pub async fn routing_retrieve_linked_config( &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, required_permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, }, req.headers(), ), @@ -774,6 +879,7 @@ pub async fn routing_retrieve_linked_config( &auth::JWTAuthProfileFromRoute { profile_id: wrapper.profile_id, required_permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Profile, }, api_locking::LockAction::NotApplicable, )) @@ -803,13 +909,19 @@ pub async fn routing_retrieve_default_config_for_profiles( #[cfg(not(feature = "release"))] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), #[cfg(feature = "release")] auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::RoutingRead), + &auth::JWTAuth { + permission: Permission::RoutingRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -851,6 +963,7 @@ pub async fn routing_update_default_config_for_profile( &auth::JWTAuthProfileFromRoute { profile_id: routing_payload_wrapper.profile_id, required_permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -858,6 +971,7 @@ pub async fn routing_update_default_config_for_profile( &auth::JWTAuthProfileFromRoute { profile_id: routing_payload_wrapper.profile_id, required_permission: Permission::RoutingWrite, + minimum_entity_level: EntityType::Merchant, }, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/user.rs b/crates/router/src/routes/user.rs index dfc25c68945f..85850c39e302 100644 --- a/crates/router/src/routes/user.rs +++ b/crates/router/src/routes/user.rs @@ -5,7 +5,7 @@ use api_models::{ errors::types::ApiErrorResponse, user::{self as user_api}, }; -use common_enums::TokenPurpose; +use common_enums::{EntityType, TokenPurpose}; use common_utils::errors::ReportSwitchExt; use router_env::Flow; @@ -175,7 +175,10 @@ pub async fn set_dashboard_metadata( &req, payload, user_core::dashboard_metadata::set_metadata, - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -257,7 +260,10 @@ pub async fn user_merchant_account_create( |state, auth: auth::UserFromToken, json_payload, _| { user_core::create_merchant_account(state, auth, json_payload) }, - &auth::JWTAuth(Permission::MerchantAccountCreate), + &auth::JWTAuth { + permission: Permission::MerchantAccountCreate, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -278,7 +284,10 @@ pub async fn generate_sample_data( &http_req, payload.into_inner(), sample_data::generate_sample_data_for_user, - &auth::JWTAuth(Permission::PaymentWrite), + &auth::JWTAuth { + permission: Permission::PaymentWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -298,7 +307,10 @@ pub async fn delete_sample_data( &http_req, payload.into_inner(), sample_data::delete_sample_data_for_user, - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -330,7 +342,10 @@ pub async fn get_user_role_details( &req, payload.into_inner(), user_core::get_user_details_in_merchant_account, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -348,7 +363,10 @@ pub async fn list_user_roles_details( &req, payload.into_inner(), user_core::list_user_roles_details, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -365,7 +383,10 @@ pub async fn list_users_for_merchant_account( &req, (), |state, user, _, _| user_core::list_users_for_merchant_account(state, user), - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -445,7 +466,10 @@ pub async fn invite_multiple_user( |state, user, payload, req_state| { user_core::invite_multiple_user(state, user, payload, req_state, auth_id.clone()) }, - &auth::JWTAuth(Permission::UsersWrite), + &auth::JWTAuth { + permission: Permission::UsersWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -468,7 +492,10 @@ pub async fn resend_invite( |state, user, req_payload, _| { user_core::resend_invite(state, user, req_payload, auth_id.clone()) }, - &auth::JWTAuth(Permission::UsersWrite), + &auth::JWTAuth { + permission: Permission::UsersWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/routes/user_role.rs b/crates/router/src/routes/user_role.rs index 35c9098edd28..00b289b0b804 100644 --- a/crates/router/src/routes/user_role.rs +++ b/crates/router/src/routes/user_role.rs @@ -1,6 +1,6 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::user_role::{self as user_role_api, role as role_api}; -use common_enums::TokenPurpose; +use common_enums::{EntityType, TokenPurpose}; use router_env::Flow; use super::AppState; @@ -29,7 +29,10 @@ pub async fn get_authorization_info( |state, _: (), _, _| async move { user_role_core::get_authorization_info_with_groups(state).await }, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -64,7 +67,10 @@ pub async fn create_role( &req, json_payload.into_inner(), role_core::create_role, - &auth::JWTAuth(Permission::UsersWrite), + &auth::JWTAuth { + permission: Permission::UsersWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -80,7 +86,10 @@ pub async fn list_all_roles(state: web::Data, req: HttpRequest) -> Htt |state, user, _, _| async move { role_core::list_invitable_roles_with_groups(state, user).await }, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -103,7 +112,10 @@ pub async fn get_role( |state, user, payload, _| async move { role_core::get_role_with_groups(state, user, payload).await }, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -124,7 +136,10 @@ pub async fn update_role( &req, json_payload.into_inner(), |state, user, req, _| role_core::update_role(state, user, req, &role_id), - &auth::JWTAuth(Permission::UsersWrite), + &auth::JWTAuth { + permission: Permission::UsersWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -143,7 +158,10 @@ pub async fn update_user_role( &req, payload, user_role_core::update_user_role, - &auth::JWTAuth(Permission::UsersWrite), + &auth::JWTAuth { + permission: Permission::UsersWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -241,7 +259,10 @@ pub async fn delete_user_role( &req, payload.into_inner(), user_role_core::delete_user_role, - &auth::JWTAuth(Permission::UsersWrite), + &auth::JWTAuth { + permission: Permission::UsersWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -261,7 +282,9 @@ pub async fn get_role_information( |_, _: (), _, _| async move { user_role_core::get_authorization_info_with_group_tag().await }, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth{ + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant}, api_locking::LockAction::NotApplicable, )) .await @@ -293,7 +316,10 @@ pub async fn list_roles_with_info(state: web::Data, req: HttpRequest) &req, (), |state, user_from_token, _, _| role_core::list_roles_with_info(state, user_from_token), - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -319,7 +345,10 @@ pub async fn list_invitable_roles_at_entity_level( role_api::RoleCheckType::Invite, ) }, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await @@ -345,7 +374,10 @@ pub async fn list_updatable_roles_at_entity_level( role_api::RoleCheckType::Update, ) }, - &auth::JWTAuth(Permission::UsersRead), + &auth::JWTAuth { + permission: Permission::UsersRead, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/routes/verification.rs b/crates/router/src/routes/verification.rs index b818fcfc1d43..f2996009f82d 100644 --- a/crates/router/src/routes/verification.rs +++ b/crates/router/src/routes/verification.rs @@ -1,5 +1,6 @@ use actix_web::{web, HttpRequest, Responder}; use api_models::verifications; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -32,7 +33,10 @@ pub async fn apple_pay_merchant_registration( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantAccountWrite, + minimum_entity_level: EntityType::Profile, + }, req.headers(), ), api_locking::LockAction::NotApplicable, @@ -64,7 +68,10 @@ pub async fn retrieve_apple_pay_verified_domains( }, auth::auth_type( &auth::HeaderAuth(auth::ApiKeyAuth), - &auth::JWTAuth(Permission::MerchantAccountRead), + &auth::JWTAuth { + permission: Permission::MerchantAccountRead, + minimum_entity_level: EntityType::Merchant, + }, req.headers(), ), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/verify_connector.rs b/crates/router/src/routes/verify_connector.rs index b510ba29637f..29f8c154bc0d 100644 --- a/crates/router/src/routes/verify_connector.rs +++ b/crates/router/src/routes/verify_connector.rs @@ -1,5 +1,6 @@ use actix_web::{web, HttpRequest, HttpResponse}; use api_models::verify_connector::VerifyConnectorRequest; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use super::AppState; @@ -23,7 +24,10 @@ pub async fn payment_connector_verify( |state, auth: auth::AuthenticationData, req, _| { verify_connector::verify_connector_credentials(state, req, auth.profile_id) }, - &auth::JWTAuth(Permission::MerchantConnectorAccountWrite), + &auth::JWTAuth { + permission: Permission::MerchantConnectorAccountWrite, + minimum_entity_level: EntityType::Merchant, + }, api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/routes/webhook_events.rs b/crates/router/src/routes/webhook_events.rs index d5150ad1fefa..8b94fb61f56b 100644 --- a/crates/router/src/routes/webhook_events.rs +++ b/crates/router/src/routes/webhook_events.rs @@ -1,4 +1,5 @@ use actix_web::{web, HttpRequest, Responder}; +use common_enums::EntityType; use router_env::{instrument, tracing, Flow}; use crate::{ @@ -44,6 +45,7 @@ pub async fn list_initial_webhook_delivery_attempts( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::WebhookEventRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -83,6 +85,7 @@ pub async fn list_webhook_delivery_attempts( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::WebhookEventRead, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), @@ -122,6 +125,7 @@ pub async fn retry_webhook_delivery_attempt( &auth::JWTAuthMerchantFromRoute { merchant_id, required_permission: Permission::WebhookEventWrite, + minimum_entity_level: EntityType::Merchant, }, req.headers(), ), diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 4f9a222db5ed..6d100ab3576e 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -10,7 +10,7 @@ use api_models::payment_methods::PaymentMethodIntentConfirm; use api_models::payouts; use api_models::{payment_methods::PaymentMethodListRequest, payments}; use async_trait::async_trait; -use common_enums::TokenPurpose; +use common_enums::{EntityType, TokenPurpose}; use common_utils::{date_time, id_type}; use error_stack::{report, ResultExt}; use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; @@ -1004,12 +1004,9 @@ where } #[derive(Debug)] -pub(crate) struct JWTAuth(pub Permission); - -#[derive(serde::Deserialize)] -struct JwtAuthPayloadFetchUnit { - #[serde(rename(deserialize = "exp"))] - _exp: u64, +pub(crate) struct JWTAuth { + pub permission: Permission, + pub minimum_entity_level: EntityType, } #[async_trait] @@ -1027,8 +1024,9 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.0, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; Ok(( (), @@ -1056,8 +1054,9 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.0, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; Ok(( UserFromToken { @@ -1091,8 +1090,10 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.0, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; + let key_manager_state = &(&state.session_state()).into(); let key_store = state .store() @@ -1132,10 +1133,12 @@ where pub struct JWTAuthMerchantFromRoute { pub merchant_id: id_type::MerchantId, pub required_permission: Permission, + pub minimum_entity_level: EntityType, } pub struct JWTAuthMerchantFromHeader { pub required_permission: Permission, + pub minimum_entity_level: EntityType, } #[async_trait] @@ -1153,8 +1156,9 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.required_permission, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.required_permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; let merchant_id_from_header = HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?; @@ -1188,8 +1192,9 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.required_permission, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.required_permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; let merchant_id_from_header = HeaderMapStruct::new(request_headers).get_merchant_id_from_header()?; @@ -1254,8 +1259,9 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.required_permission, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.required_permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; // Check if token has access to MerchantId that has been requested through query param if payload.merchant_id != self.merchant_id { @@ -1290,8 +1296,10 @@ where return Err(report!(errors::ApiErrorResponse::InvalidJwtToken)); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.required_permission, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.required_permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; + let key_manager_state = &(&state.session_state()).into(); let key_store = state .store() @@ -1333,6 +1341,7 @@ pub struct JWTAuthMerchantAndProfileFromRoute { pub merchant_id: id_type::MerchantId, pub profile_id: id_type::ProfileId, pub required_permission: Permission, + pub minimum_entity_level: EntityType, } #[async_trait] @@ -1362,8 +1371,10 @@ where return Err(report!(errors::ApiErrorResponse::InvalidJwtToken)); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.required_permission, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.required_permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; + let key_manager_state = &(&state.session_state()).into(); let key_store = state .store() @@ -1406,6 +1417,7 @@ where pub struct JWTAuthProfileFromRoute { pub profile_id: id_type::ProfileId, pub required_permission: Permission, + pub minimum_entity_level: EntityType, } #[async_trait] @@ -1423,8 +1435,10 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.required_permission, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.required_permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; + let key_manager_state = &(&state.session_state()).into(); let key_store = state .store() @@ -1517,8 +1531,10 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.0, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; + let key_manager_state = &(&state.session_state()).into(); let key_store = state .store() @@ -1574,8 +1590,10 @@ where return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - let permissions = authorization::get_permissions(state, &payload).await?; - authorization::check_authorization(&self.0, &permissions)?; + let role_info = authorization::get_role_info(state, &payload).await?; + authorization::check_permission(&self.permission, &role_info)?; + authorization::check_entity(self.minimum_entity_level, &role_info)?; + let key_manager_state = &(&state.session_state()).into(); let key_store = state .store() diff --git a/crates/router/src/services/authorization.rs b/crates/router/src/services/authorization.rs index ea1264bde069..78af4c00884e 100644 --- a/crates/router/src/services/authorization.rs +++ b/crates/router/src/services/authorization.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use common_enums::PermissionGroup; use common_utils::id_type; use error_stack::ResultExt; use redis_interface::RedisConnectionPool; @@ -19,69 +18,57 @@ pub mod permission_groups; pub mod permissions; pub mod roles; -pub async fn get_permissions( - state: &A, - token: &AuthToken, -) -> RouterResult> +pub async fn get_role_info(state: &A, token: &AuthToken) -> RouterResult where A: SessionStateInfo + Sync, { - if let Some(permissions) = get_permissions_from_predefined_roles(&token.role_id) { - return Ok(permissions); + if let Some(role_info) = roles::predefined_roles::PREDEFINED_ROLES.get(token.role_id.as_str()) { + return Ok(role_info.clone()); } - if let Ok(permissions) = get_permissions_from_cache(state, &token.role_id) + if let Ok(role_info) = get_role_info_from_cache(state, &token.role_id) .await .map_err(|e| logger::error!("Failed to get permissions from cache {e:?}")) { - return Ok(permissions); + return Ok(role_info.clone()); } - let permissions = - get_permissions_from_db(state, &token.role_id, &token.merchant_id, &token.org_id).await?; + let role_info = + get_role_info_from_db(state, &token.role_id, &token.merchant_id, &token.org_id).await?; let token_expiry = i64::try_from(token.exp).change_context(ApiErrorResponse::InternalServerError)?; let cache_ttl = token_expiry - common_utils::date_time::now_unix_timestamp(); - set_permissions_in_cache(state, &token.role_id, &permissions, cache_ttl) + set_role_info_in_cache(state, &token.role_id, &role_info, cache_ttl) .await - .map_err(|e| logger::error!("Failed to set permissions in cache {e:?}")) + .map_err(|e| logger::error!("Failed to set role info in cache {e:?}")) .ok(); - Ok(permissions) + Ok(role_info) } -async fn get_permissions_from_cache( - state: &A, - role_id: &str, -) -> RouterResult> +async fn get_role_info_from_cache(state: &A, role_id: &str) -> RouterResult where A: SessionStateInfo + Sync, { let redis_conn = get_redis_connection(state)?; redis_conn - .get_and_deserialize_key(&get_cache_key_from_role_id(role_id), "Vec") + .get_and_deserialize_key(&get_cache_key_from_role_id(role_id), "RoleInfo") .await .change_context(ApiErrorResponse::InternalServerError) } pub fn get_cache_key_from_role_id(role_id: &str) -> String { - format!("{}{}", consts::ROLE_CACHE_PREFIX, role_id) + format!("{}{}", consts::ROLE_INFO_CACHE_PREFIX, role_id) } -fn get_permissions_from_predefined_roles(role_id: &str) -> Option> { - roles::predefined_roles::PREDEFINED_ROLES - .get(role_id) - .map(|role_info| get_permissions_from_groups(role_info.get_permission_groups())) -} - -async fn get_permissions_from_db( +async fn get_role_info_from_db( state: &A, role_id: &str, merchant_id: &id_type::MerchantId, org_id: &id_type::OrganizationId, -) -> RouterResult> +) -> RouterResult where A: SessionStateInfo + Sync, { @@ -89,14 +76,14 @@ where .store() .find_role_by_role_id_in_merchant_scope(role_id, merchant_id, org_id) .await - .map(|role| get_permissions_from_groups(&role.groups)) + .map(roles::RoleInfo::from) .to_not_found_response(ApiErrorResponse::InvalidJwtToken) } -pub async fn set_permissions_in_cache( +pub async fn set_role_info_in_cache( state: &A, role_id: &str, - permissions: &Vec, + role_info: &roles::RoleInfo, expiry: i64, ) -> RouterResult<()> where @@ -105,32 +92,17 @@ where let redis_conn = get_redis_connection(state)?; redis_conn - .serialize_and_set_key_with_expiry( - &get_cache_key_from_role_id(role_id), - permissions, - expiry, - ) + .serialize_and_set_key_with_expiry(&get_cache_key_from_role_id(role_id), role_info, expiry) .await .change_context(ApiErrorResponse::InternalServerError) } -pub fn get_permissions_from_groups(groups: &[PermissionGroup]) -> Vec { - groups - .iter() - .flat_map(|group| { - permission_groups::get_permissions_vec(group) - .iter() - .cloned() - }) - .collect() -} - -pub fn check_authorization( +pub fn check_permission( required_permission: &permissions::Permission, - permissions: &[permissions::Permission], + role_info: &roles::RoleInfo, ) -> RouterResult<()> { - permissions - .contains(required_permission) + role_info + .check_permission_exists(required_permission) .then_some(()) .ok_or( ApiErrorResponse::AccessForbidden { @@ -140,6 +112,18 @@ pub fn check_authorization( ) } +pub fn check_entity( + required_minimum_entity: common_enums::EntityType, + role_info: &roles::RoleInfo, +) -> RouterResult<()> { + if required_minimum_entity > role_info.get_entity_type() { + Err(ApiErrorResponse::AccessForbidden { + resource: required_minimum_entity.to_string(), + })?; + } + Ok(()) +} + fn get_redis_connection(state: &A) -> RouterResult> { state .store() diff --git a/crates/router/src/services/authorization/roles.rs b/crates/router/src/services/authorization/roles.rs index 9b506cc5ef7f..c498a33614e1 100644 --- a/crates/router/src/services/authorization/roles.rs +++ b/crates/router/src/services/authorization/roles.rs @@ -8,7 +8,7 @@ use crate::{core::errors, routes::SessionState}; pub mod predefined_roles; -#[derive(Clone)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)] pub struct RoleInfo { role_id: String, role_name: String, diff --git a/crates/router/src/services/authorization/roles/predefined_roles.rs b/crates/router/src/services/authorization/roles/predefined_roles.rs index f5320c41335b..9d55c5b2d169 100644 --- a/crates/router/src/services/authorization/roles/predefined_roles.rs +++ b/crates/router/src/services/authorization/roles/predefined_roles.rs @@ -215,5 +215,24 @@ pub static PREDEFINED_ROLES: Lazy> = Lazy::new(| is_internal: false, }, ); + roles.insert( + consts::user_role::ROLE_ID_PROFILE_CUSTOMER_SUPPORT, + RoleInfo { + groups: vec![ + PermissionGroup::OperationsView, + PermissionGroup::OperationsManage, + PermissionGroup::ConnectorsView, + PermissionGroup::WorkflowsView, + ], + role_id: consts::user_role::ROLE_ID_PROFILE_CUSTOMER_SUPPORT.to_string(), + role_name: "profile_support".to_string(), + scope: RoleScope::Organization, + entity_type: EntityType::Profile, + is_invitable: true, + is_deletable: true, + is_updatable: true, + is_internal: false, + }, + ); roles }); diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs index ecf12742e326..cf02d7766b57 100644 --- a/crates/router/src/utils/user_role.rs +++ b/crates/router/src/utils/user_role.rs @@ -156,10 +156,10 @@ pub async fn set_role_permissions_in_cache_if_required( .change_context(UserErrors::InternalServerError) .attach_printable("Error getting role_info from role_id")?; - authz::set_permissions_in_cache( + authz::set_role_info_in_cache( state, role_id, - &role_info.get_permissions_set().into_iter().collect(), + &role_info, i64::try_from(consts::JWT_TOKEN_TIME_IN_SECS) .change_context(UserErrors::InternalServerError)?, )