feat(auth): Add Authorization for JWT Authentication types (#2973)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Mani Chandra
2023-11-24 19:11:46 +05:30
committed by GitHub
parent 4c1c6da0d1
commit 03c0a772a9
20 changed files with 659 additions and 91 deletions

View File

@ -8,7 +8,10 @@ use router_env::AnalyticsFlow;
use super::{core::*, payments, refunds, types::AnalyticsDomain}; use super::{core::*, payments, refunds, types::AnalyticsDomain};
use crate::{ use crate::{
core::api_locking, core::api_locking,
services::{api, authentication as auth, authentication::AuthenticationData}, services::{
api, authentication as auth, authentication::AuthenticationData,
authorization::permissions::Permission,
},
AppState, AppState,
}; };
@ -68,7 +71,11 @@ pub async fn get_payment_metrics(
|state, auth: AuthenticationData, req| { |state, auth: AuthenticationData, req| {
payments::get_metrics(state.pool.clone(), auth.merchant_account, req) payments::get_metrics(state.pool.clone(), auth.merchant_account, req)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::Analytics),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -98,7 +105,11 @@ pub async fn get_refunds_metrics(
|state, auth: AuthenticationData, req| { |state, auth: AuthenticationData, req| {
refunds::get_metrics(state.pool.clone(), auth.merchant_account, req) refunds::get_metrics(state.pool.clone(), auth.merchant_account, req)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::Analytics),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -118,7 +129,11 @@ pub async fn get_payment_filters(
|state, auth: AuthenticationData, req| { |state, auth: AuthenticationData, req| {
payment_filters_core(state.pool.clone(), req, auth.merchant_account) payment_filters_core(state.pool.clone(), req, auth.merchant_account)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::Analytics),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -138,7 +153,11 @@ pub async fn get_refund_filters(
|state, auth: AuthenticationData, req: GetRefundFilterRequest| { |state, auth: AuthenticationData, req: GetRefundFilterRequest| {
refund_filter_core(state.pool.clone(), req, auth.merchant_account) refund_filter_core(state.pool.clone(), req, auth.merchant_account)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::Analytics),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -58,3 +58,5 @@ pub const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes
#[cfg(any(feature = "olap", feature = "oltp"))] #[cfg(any(feature = "olap", feature = "oltp"))]
pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days
pub const ROLE_ID_ORGANIZATION_ADMIN: &str = "org_admin";

View File

@ -1,8 +1,2 @@
#[cfg(feature = "olap")]
pub const MAX_NAME_LENGTH: usize = 70; pub const MAX_NAME_LENGTH: usize = 70;
#[cfg(feature = "olap")]
pub const MAX_COMPANY_NAME_LENGTH: usize = 70; pub const MAX_COMPANY_NAME_LENGTH: usize = 70;
// USER ROLES
#[cfg(any(feature = "olap", feature = "oltp"))]
pub const ROLE_ID_ORGANIZATION_ADMIN: &str = "org_admin";

View File

@ -5,9 +5,7 @@ use masking::{ExposeInterface, Secret};
use router_env::env; use router_env::env;
use super::errors::{UserErrors, UserResponse}; use super::errors::{UserErrors, UserResponse};
use crate::{ use crate::{consts, routes::AppState, services::ApplicationResponse, types::domain};
consts::user as consts, routes::AppState, services::ApplicationResponse, types::domain,
};
pub async fn connect_account( pub async fn connect_account(
state: AppState, state: AppState,

View File

@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState; use super::app::AppState;
use crate::{ use crate::{
core::{admin::*, api_locking}, core::{admin::*, api_locking},
services::{api, authentication as auth}, services::{api, authentication as auth, authorization::permissions::Permission},
types::api::admin, types::api::admin,
}; };
@ -77,7 +77,10 @@ pub async fn retrieve_merchant_account(
|state, _, req| get_merchant_account(state, req), |state, _, req| get_merchant_account(state, req),
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantAccountRead,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
@ -141,6 +144,7 @@ pub async fn update_merchant_account(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantAccountWrite,
}, },
req.headers(), req.headers(),
), ),
@ -220,6 +224,7 @@ pub async fn payment_connector_create(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantConnectorAccountWrite,
}, },
req.headers(), req.headers(),
), ),
@ -270,7 +275,10 @@ pub async fn payment_connector_retrieve(
}, },
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantConnectorAccountRead,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
@ -312,7 +320,10 @@ pub async fn payment_connector_list(
|state, _, merchant_id| list_payment_connectors(state, merchant_id), |state, _, merchant_id| list_payment_connectors(state, merchant_id),
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantConnectorAccountRead,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
@ -359,6 +370,7 @@ pub async fn payment_connector_update(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantConnectorAccountWrite,
}, },
req.headers(), req.headers(),
), ),
@ -407,7 +419,10 @@ pub async fn payment_connector_delete(
|state, _, req| delete_payment_connector(state, req.merchant_id, req.merchant_connector_id), |state, _, req| delete_payment_connector(state, req.merchant_id, req.merchant_connector_id),
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantConnectorAccountWrite,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
@ -460,6 +475,7 @@ pub async fn business_profile_create(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantAccountWrite,
}, },
req.headers(), req.headers(),
), ),
@ -484,7 +500,10 @@ pub async fn business_profile_retrieve(
|state, _, profile_id| retrieve_business_profile(state, profile_id), |state, _, profile_id| retrieve_business_profile(state, profile_id),
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantAccountRead,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
@ -511,6 +530,7 @@ pub async fn business_profile_update(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantAccountWrite,
}, },
req.headers(), req.headers(),
), ),
@ -555,7 +575,10 @@ pub async fn business_profiles_list(
|state, _, merchant_id| list_business_profile(state, merchant_id), |state, _, merchant_id| list_business_profile(state, merchant_id),
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantAccountRead,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,

View File

@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState; use super::app::AppState;
use crate::{ use crate::{
core::{api_keys, api_locking}, core::{api_keys, api_locking},
services::{api, authentication as auth}, services::{api, authentication as auth, authorization::permissions::Permission},
types::api as api_types, types::api as api_types,
}; };
@ -57,6 +57,7 @@ pub async fn api_key_create(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::ApiKeyWrite,
}, },
req.headers(), req.headers(),
), ),
@ -101,6 +102,7 @@ pub async fn api_key_retrieve(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::ApiKeyRead,
}, },
req.headers(), req.headers(),
), ),
@ -189,6 +191,7 @@ pub async fn api_key_revoke(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { &auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(), merchant_id: merchant_id.clone(),
required_permission: Permission::ApiKeyWrite,
}, },
req.headers(), req.headers(),
), ),
@ -237,7 +240,10 @@ pub async fn api_key_list(
}, },
auth::auth_type( auth::auth_type(
&auth::AdminApiAuth, &auth::AdminApiAuth,
&auth::JWTAuthMerchantFromRoute { merchant_id }, &auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::ApiKeyRead,
},
req.headers(), req.headers(),
), ),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,

View File

@ -3,7 +3,7 @@ use actix_web::{web, HttpRequest, HttpResponse};
use api_models::disputes as dispute_models; use api_models::disputes as dispute_models;
use router_env::{instrument, tracing, Flow}; use router_env::{instrument, tracing, Flow};
use crate::core::api_locking; use crate::{core::api_locking, services::authorization::permissions::Permission};
pub mod utils; pub mod utils;
use super::app::AppState; use super::app::AppState;
@ -44,7 +44,11 @@ pub async fn retrieve_dispute(
&req, &req,
dispute_id, dispute_id,
|state, auth, req| disputes::retrieve_dispute(state, auth.merchant_account, req), |state, auth, req| disputes::retrieve_dispute(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -87,7 +91,11 @@ pub async fn retrieve_disputes_list(
&req, &req,
payload, payload,
|state, auth, req| disputes::retrieve_disputes_list(state, auth.merchant_account, req), |state, auth, req| disputes::retrieve_disputes_list(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -125,7 +133,11 @@ pub async fn accept_dispute(
|state, auth, req| { |state, auth, req| {
disputes::accept_dispute(state, auth.merchant_account, auth.key_store, req) disputes::accept_dispute(state, auth.merchant_account, auth.key_store, req)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -158,7 +170,11 @@ pub async fn submit_dispute_evidence(
|state, auth, req| { |state, auth, req| {
disputes::submit_evidence(state, auth.merchant_account, auth.key_store, req) disputes::submit_evidence(state, auth.merchant_account, auth.key_store, req)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -199,7 +215,11 @@ pub async fn attach_dispute_evidence(
|state, auth, req| { |state, auth, req| {
disputes::attach_evidence(state, auth.merchant_account, auth.key_store, req) disputes::attach_evidence(state, auth.merchant_account, auth.key_store, req)
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -235,7 +255,11 @@ pub async fn retrieve_dispute_evidence(
&req, &req,
dispute_id, dispute_id,
|state, auth, req| disputes::retrieve_dispute_evidence(state, auth.merchant_account, req), |state, auth, req| disputes::retrieve_dispute_evidence(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::DisputeRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await

View File

@ -2,7 +2,7 @@ use actix_multipart::Multipart;
use actix_web::{web, HttpRequest, HttpResponse}; use actix_web::{web, HttpRequest, HttpResponse};
use router_env::{instrument, tracing, Flow}; use router_env::{instrument, tracing, Flow};
use crate::core::api_locking; use crate::{core::api_locking, services::authorization::permissions::Permission};
pub mod transformers; pub mod transformers;
use super::app::AppState; use super::app::AppState;
@ -45,7 +45,11 @@ pub async fn files_create(
&req, &req,
create_file_request, create_file_request,
|state, auth, req| files_create_core(state, auth.merchant_account, auth.key_store, req), |state, auth, req| files_create_core(state, auth.merchant_account, auth.key_store, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::FileWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -83,7 +87,11 @@ pub async fn files_delete(
&req, &req,
file_id, file_id,
|state, auth, req| files_delete_core(state, auth.merchant_account, req), |state, auth, req| files_delete_core(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::FileWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -121,7 +129,11 @@ pub async fn files_retrieve(
&req, &req,
file_id, file_id,
|state, auth, req| files_retrieve_core(state, auth.merchant_account, auth.key_store, req), |state, auth, req| files_retrieve_core(state, auth.merchant_account, auth.key_store, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::FileRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await

View File

@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState; use super::app::AppState;
use crate::{ use crate::{
core::{api_locking, mandate}, core::{api_locking, mandate},
services::{api, authentication as auth}, services::{api, authentication as auth, authorization::permissions::Permission},
types::api::mandates, types::api::mandates,
}; };
@ -122,7 +122,11 @@ pub async fn retrieve_mandates_list(
&req, &req,
payload, payload,
|state, auth, req| mandate::retrieve_mandates_list(state, auth.merchant_account, req), |state, auth, req| mandate::retrieve_mandates_list(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::MandateRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -118,7 +118,7 @@ pub async fn payments_link_list(
&req, &req,
payload, payload,
|state, auth, payload| list_payment_link(state, auth.merchant_account, payload), |state, auth, payload| list_payment_link(state, auth.merchant_account, payload),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), &auth::ApiKeyAuth,
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -1,4 +1,7 @@
use crate::core::api_locking::{self, GetLockingInput}; use crate::{
core::api_locking::{self, GetLockingInput},
services::authorization::permissions::Permission,
};
pub mod helpers; pub mod helpers;
use actix_web::{web, Responder}; use actix_web::{web, Responder};
@ -128,7 +131,11 @@ pub async fn payments_create(
}, },
match env::which() { match env::which() {
env::Env::Production => &auth::ApiKeyAuth, env::Env::Production => &auth::ApiKeyAuth,
_ => auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), _ => auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::PaymentWrite),
req.headers(),
),
}, },
locking_action, locking_action,
)) ))
@ -262,7 +269,7 @@ pub async fn payments_retrieve(
}, },
auth::auth_type( auth::auth_type(
&*auth_type, &*auth_type,
&auth::JWTAuth, &auth::JWTAuth(Permission::PaymentRead),
req.headers(), req.headers(),
), ),
locking_action, locking_action,
@ -843,7 +850,11 @@ pub async fn payments_list(
&req, &req,
payload, payload,
|state, auth, req| payments::list_payments(state, auth.merchant_account, req), |state, auth, req| payments::list_payments(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::PaymentRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -863,7 +874,11 @@ pub async fn payments_list_by_filter(
&req, &req,
payload, payload,
|state, auth, req| payments::apply_filters_on_payments(state, auth.merchant_account, req), |state, auth, req| payments::apply_filters_on_payments(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::PaymentRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -883,7 +898,11 @@ pub async fn get_filters_for_payments(
&req, &req,
payload, payload,
|state, auth, req| payments::get_filters_for_payments(state, auth.merchant_account, req), |state, auth, req| payments::get_filters_for_payments(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::PaymentRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState; use super::app::AppState;
use crate::{ use crate::{
core::{api_locking, refunds::*}, core::{api_locking, refunds::*},
services::{api, authentication as auth}, services::{api, authentication as auth, authorization::permissions::Permission},
types::api::refunds, types::api::refunds,
}; };
@ -37,7 +37,11 @@ pub async fn refunds_create(
&req, &req,
json_payload.into_inner(), json_payload.into_inner(),
|state, auth, req| refund_create_core(state, auth.merchant_account, auth.key_store, req), |state, auth, req| refund_create_core(state, auth.merchant_account, auth.key_store, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RefundWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -88,7 +92,11 @@ pub async fn refunds_retrieve(
refund_retrieve_core, refund_retrieve_core,
) )
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RefundRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -202,7 +210,11 @@ pub async fn refunds_list(
&req, &req,
payload.into_inner(), payload.into_inner(),
|state, auth, req| refund_list(state, auth.merchant_account, req), |state, auth, req| refund_list(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RefundRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -235,7 +247,11 @@ pub async fn refunds_filter_list(
&req, &req,
payload.into_inner(), payload.into_inner(),
|state, auth, req| refund_filter_list(state, auth.merchant_account, req), |state, auth, req| refund_filter_list(state, auth.merchant_account, req),
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RefundRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -14,7 +14,7 @@ use router_env::{
use crate::{ use crate::{
core::{api_locking, conditional_config, routing, surcharge_decision_config}, core::{api_locking, conditional_config, routing, surcharge_decision_config},
routes::AppState, routes::AppState,
services::{api as oss_api, authentication as auth}, services::{api as oss_api, authentication as auth, authorization::permissions::Permission},
}; };
#[cfg(feature = "olap")] #[cfg(feature = "olap")]
@ -34,9 +34,13 @@ pub async fn routing_create_config(
routing::create_routing_config(state, auth.merchant_account, auth.key_store, payload) routing::create_routing_config(state, auth.merchant_account, auth.key_store, payload)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -65,9 +69,13 @@ pub async fn routing_link_config(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -91,9 +99,13 @@ pub async fn routing_retrieve_config(
routing::retrieve_routing_config(state, auth.merchant_account, algorithm_id) routing::retrieve_routing_config(state, auth.merchant_account, algorithm_id)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -122,9 +134,13 @@ pub async fn routing_retrieve_dictionary(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -142,9 +158,13 @@ pub async fn routing_retrieve_dictionary(
routing::retrieve_merchant_routing_dictionary(state, auth.merchant_account) routing::retrieve_merchant_routing_dictionary(state, auth.merchant_account)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -172,9 +192,13 @@ pub async fn routing_unlink_config(
routing::unlink_routing_config(state, auth.merchant_account, payload_req) routing::unlink_routing_config(state, auth.merchant_account, payload_req)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -192,9 +216,13 @@ pub async fn routing_unlink_config(
routing::unlink_routing_config(state, auth.merchant_account, auth.key_store) routing::unlink_routing_config(state, auth.merchant_account, auth.key_store)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -217,9 +245,13 @@ pub async fn routing_update_default_config(
routing::update_default_routing_config(state, auth.merchant_account, updated_config) routing::update_default_routing_config(state, auth.merchant_account, updated_config)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -240,9 +272,13 @@ pub async fn routing_retrieve_default_config(
routing::retrieve_default_routing_config(state, auth.merchant_account) routing::retrieve_default_routing_config(state, auth.merchant_account)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -270,9 +306,13 @@ pub async fn upsert_surcharge_decision_manager_config(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -297,9 +337,13 @@ pub async fn delete_surcharge_decision_manager_config(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -324,9 +368,13 @@ pub async fn retrieve_surcharge_decision_manager_config(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -354,9 +402,13 @@ pub async fn upsert_decision_manager_config(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -382,9 +434,13 @@ pub async fn delete_decision_manager_config(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::SurchargeDecisionManagerWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -406,9 +462,13 @@ pub async fn retrieve_decision_manager_config(
conditional_config::retrieve_conditional_config(state, auth.merchant_account) conditional_config::retrieve_conditional_config(state, auth.merchant_account)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::SurchargeDecisionManagerRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -434,9 +494,13 @@ pub async fn routing_retrieve_linked_config(
routing::retrieve_linked_routing_config(state, auth.merchant_account, query_params) routing::retrieve_linked_routing_config(state, auth.merchant_account, query_params)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -454,9 +518,13 @@ pub async fn routing_retrieve_linked_config(
routing::retrieve_linked_routing_config(state, auth.merchant_account) routing::retrieve_linked_routing_config(state, auth.merchant_account)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingRead),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -478,9 +546,17 @@ pub async fn routing_retrieve_default_config_for_profiles(
routing::retrieve_default_routing_config_for_profiles(state, auth.merchant_account) routing::retrieve_default_routing_config_for_profiles(state, auth.merchant_account)
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -512,9 +588,13 @@ pub async fn routing_update_default_config_for_profile(
) )
}, },
#[cfg(not(feature = "release"))] #[cfg(not(feature = "release"))]
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::RoutingWrite),
req.headers(),
),
#[cfg(feature = "release")] #[cfg(feature = "release")]
&auth::JWTAuth, &auth::JWTAuth(Permission::RoutingWrite),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -5,7 +5,7 @@ use router_env::{instrument, tracing, Flow};
use super::app::AppState; use super::app::AppState;
use crate::{ use crate::{
core::{api_locking, verification}, core::{api_locking, verification},
services::{api, authentication as auth}, services::{api, authentication as auth, authorization::permissions::Permission},
}; };
#[instrument(skip_all, fields(flow = ?Flow::Verification))] #[instrument(skip_all, fields(flow = ?Flow::Verification))]
@ -32,7 +32,11 @@ pub async fn apple_pay_merchant_registration(
merchant_id.clone(), merchant_id.clone(),
) )
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::MerchantAccountWrite),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
)) ))
.await .await
@ -60,7 +64,11 @@ pub async fn retrieve_apple_pay_verified_domains(
mca_id.to_string(), mca_id.to_string(),
) )
}, },
auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), auth::auth_type(
&auth::ApiKeyAuth,
&auth::JWTAuth(Permission::MerchantAccountRead),
req.headers(),
),
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -1,5 +1,6 @@
pub mod api; pub mod api;
pub mod authentication; pub mod authentication;
pub mod authorization;
pub mod encryption; pub mod encryption;
#[cfg(feature = "olap")] #[cfg(feature = "olap")]
pub mod jwt; pub mod jwt;

View File

@ -9,6 +9,7 @@ use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use masking::{PeekInterface, StrongSecret}; use masking::{PeekInterface, StrongSecret};
use serde::Serialize; use serde::Serialize;
use super::authorization::{self, permissions::Permission};
#[cfg(feature = "olap")] #[cfg(feature = "olap")]
use super::jwt; use super::jwt;
#[cfg(feature = "olap")] #[cfg(feature = "olap")]
@ -387,7 +388,7 @@ where
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct JWTAuth; pub(crate) struct JWTAuth(pub Permission);
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct JwtAuthPayloadFetchUnit { struct JwtAuthPayloadFetchUnit {
@ -406,6 +407,10 @@ where
state: &A, state: &A,
) -> RouterResult<((), AuthenticationType)> { ) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?; let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
let permissions = authorization::get_permissions(&payload.role_id)?;
authorization::check_authorization(&self.0, permissions)?;
Ok(( Ok((
(), (),
AuthenticationType::MerchantJWT { AuthenticationType::MerchantJWT {
@ -418,6 +423,7 @@ where
pub struct JWTAuthMerchantFromRoute { pub struct JWTAuthMerchantFromRoute {
pub merchant_id: String, pub merchant_id: String,
pub required_permission: Permission,
} }
#[async_trait] #[async_trait]
@ -432,6 +438,9 @@ where
) -> RouterResult<((), AuthenticationType)> { ) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?; let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
let permissions = authorization::get_permissions(&payload.role_id)?;
authorization::check_authorization(&self.required_permission, permissions)?;
// Check if token has access to merchantID that has been requested through query param // Check if token has access to merchantID that has been requested through query param
if payload.merchant_id != self.merchant_id { if payload.merchant_id != self.merchant_id {
return Err(report!(errors::ApiErrorResponse::InvalidJwtToken)); return Err(report!(errors::ApiErrorResponse::InvalidJwtToken));
@ -460,6 +469,7 @@ where
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct JwtAuthPayloadFetchMerchantAccount { struct JwtAuthPayloadFetchMerchantAccount {
merchant_id: String, merchant_id: String,
role_id: String,
} }
#[async_trait] #[async_trait]
@ -475,6 +485,10 @@ where
let payload = let payload =
parse_jwt_payload::<A, JwtAuthPayloadFetchMerchantAccount>(request_headers, state) parse_jwt_payload::<A, JwtAuthPayloadFetchMerchantAccount>(request_headers, state)
.await?; .await?;
let permissions = authorization::get_permissions(&payload.role_id)?;
authorization::check_authorization(&self.0, permissions)?;
let key_store = state let key_store = state
.store() .store()
.get_merchant_key_store_by_merchant_id( .get_merchant_key_store_by_merchant_id(

View File

@ -0,0 +1,27 @@
use crate::core::errors::{ApiErrorResponse, RouterResult};
pub mod info;
pub mod permissions;
pub mod predefined_permissions;
pub fn get_permissions(role: &str) -> RouterResult<&Vec<permissions::Permission>> {
predefined_permissions::PREDEFINED_PERMISSIONS
.get(role)
.map(|role_info| role_info.get_permissions())
.ok_or(ApiErrorResponse::InvalidJwtToken.into())
}
pub fn check_authorization(
required_permission: &permissions::Permission,
permissions: &[permissions::Permission],
) -> RouterResult<()> {
permissions
.contains(required_permission)
.then_some(())
.ok_or(
ApiErrorResponse::AccessForbidden {
resource: required_permission.to_string(),
}
.into(),
)
}

View File

@ -0,0 +1,168 @@
use strum::{EnumIter, IntoEnumIterator};
use super::permissions::Permission;
pub fn get_authorization_info() -> Vec<ModuleInfo> {
PermissionModule::iter()
.map(|module| ModuleInfo::new(&module))
.collect()
}
pub struct PermissionInfo {
pub enum_name: Permission,
pub description: &'static str,
}
impl PermissionInfo {
pub fn new(permissions: &[Permission]) -> Vec<Self> {
let mut permission_infos = Vec::with_capacity(permissions.len());
for permission in permissions {
if let Some(description) = Permission::get_permission_description(permission) {
permission_infos.push(Self {
enum_name: permission.clone(),
description,
})
}
}
permission_infos
}
}
#[derive(PartialEq, EnumIter, Clone)]
pub enum PermissionModule {
Payments,
Refunds,
MerchantAccount,
Connectors,
Forex,
Routing,
Analytics,
Mandates,
Disputes,
Files,
ThreeDsDecisionManager,
SurchargeDecisionManager,
}
impl PermissionModule {
pub fn get_module_description(&self) -> &'static str {
match self {
Self::Payments => "Everything related to payments - like creating and viewing payment related information are within this module",
Self::Refunds => "Refunds module encompasses everything related to refunds - like creating and viewing payment related information",
Self::MerchantAccount => "Accounts module permissions allow the user to view and update account details, configure webhooks and much more",
Self::Connectors => "All connector related actions - like configuring new connectors, viewing and updating connector configuration lies with this module",
Self::Routing => "All actions related to new, active, and past routing stacks take place here",
Self::Forex => "Forex module permissions allow the user to view and query the forex rates",
Self::Analytics => "Permission to view and analyse the data relating to payments, refunds, sdk etc.",
Self::Mandates => "Everything related to mandates - like creating and viewing mandate related information are within this module",
Self::Disputes => "Everything related to disputes - like creating and viewing dispute related information are within this module",
Self::Files => "Permissions for uploading, deleting and viewing files for disputes",
Self::ThreeDsDecisionManager => "View and configure 3DS decision rules configured for a merchant",
Self::SurchargeDecisionManager =>"View and configure surcharge decision rules configured for a merchant"
}
}
}
pub struct ModuleInfo {
pub module: PermissionModule,
pub description: &'static str,
pub permissions: Vec<PermissionInfo>,
}
impl ModuleInfo {
pub fn new(module: &PermissionModule) -> Self {
let module_name = module.clone();
let description = module.get_module_description();
match module {
PermissionModule::Payments => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::PaymentRead,
Permission::PaymentWrite,
]),
},
PermissionModule::Refunds => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::RefundRead,
Permission::RefundWrite,
]),
},
PermissionModule::MerchantAccount => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::MerchantAccountRead,
Permission::MerchantAccountWrite,
]),
},
PermissionModule::Connectors => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::MerchantConnectorAccountRead,
Permission::MerchantConnectorAccountWrite,
]),
},
PermissionModule::Forex => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[Permission::ForexRead]),
},
PermissionModule::Routing => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::RoutingRead,
Permission::RoutingWrite,
]),
},
PermissionModule::Analytics => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[Permission::Analytics]),
},
PermissionModule::Mandates => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::MandateRead,
Permission::MandateWrite,
]),
},
PermissionModule::Disputes => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::DisputeRead,
Permission::DisputeWrite,
]),
},
PermissionModule::Files => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[Permission::FileRead, Permission::FileWrite]),
},
PermissionModule::ThreeDsDecisionManager => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::ThreeDsDecisionManagerWrite,
Permission::ThreeDsDecisionManagerRead,
]),
},
PermissionModule::SurchargeDecisionManager => Self {
module: module_name,
description,
permissions: PermissionInfo::new(&[
Permission::SurchargeDecisionManagerWrite,
Permission::SurchargeDecisionManagerRead,
]),
},
}
}
}

View File

@ -0,0 +1,74 @@
use strum::Display;
#[derive(PartialEq, Display, Clone, Debug)]
pub enum Permission {
PaymentRead,
PaymentWrite,
RefundRead,
RefundWrite,
ApiKeyRead,
ApiKeyWrite,
MerchantAccountRead,
MerchantAccountWrite,
MerchantConnectorAccountRead,
MerchantConnectorAccountWrite,
ForexRead,
RoutingRead,
RoutingWrite,
DisputeRead,
DisputeWrite,
MandateRead,
MandateWrite,
FileRead,
FileWrite,
Analytics,
ThreeDsDecisionManagerWrite,
ThreeDsDecisionManagerRead,
SurchargeDecisionManagerWrite,
SurchargeDecisionManagerRead,
UsersRead,
UsersWrite,
MerchantAccountCreate,
}
impl Permission {
pub fn get_permission_description(&self) -> Option<&'static str> {
match self {
Self::PaymentRead => Some("View all payments"),
Self::PaymentWrite => Some("Create payment, download payments data"),
Self::RefundRead => Some("View all refunds"),
Self::RefundWrite => Some("Create refund, download refunds data"),
Self::ApiKeyRead => Some("View API keys (masked generated for the system"),
Self::ApiKeyWrite => Some("Create and update API keys"),
Self::MerchantAccountRead => Some("View merchant account details"),
Self::MerchantAccountWrite => {
Some("Update merchant account details, configure webhooks, manage api keys")
}
Self::MerchantConnectorAccountRead => Some("View connectors configured"),
Self::MerchantConnectorAccountWrite => {
Some("Create, update, verify and delete connector configurations")
}
Self::ForexRead => Some("Query Forex data"),
Self::RoutingRead => Some("View routing configuration"),
Self::RoutingWrite => Some("Create and activate routing configurations"),
Self::DisputeRead => Some("View disputes"),
Self::DisputeWrite => Some("Create and update disputes"),
Self::MandateRead => Some("View mandates"),
Self::MandateWrite => Some("Create and update mandates"),
Self::FileRead => Some("View files"),
Self::FileWrite => Some("Create, update and delete files"),
Self::Analytics => Some("Access to analytics module"),
Self::ThreeDsDecisionManagerWrite => Some("Create and update 3DS decision rules"),
Self::ThreeDsDecisionManagerRead => {
Some("View all 3DS decision rules configured for a merchant")
}
Self::SurchargeDecisionManagerWrite => {
Some("Create and update the surcharge decision rules")
}
Self::SurchargeDecisionManagerRead => Some("View all the surcharge decision rules"),
Self::UsersRead => Some("View all the users for a merchant"),
Self::UsersWrite => Some("Invite users, assign and update roles"),
Self::MerchantAccountCreate => None,
}
}
}

View File

@ -0,0 +1,79 @@
use std::collections::HashMap;
use once_cell::sync::Lazy;
use super::permissions::Permission;
use crate::consts;
pub struct RoleInfo {
permissions: Vec<Permission>,
name: Option<&'static str>,
is_invitable: bool,
}
impl RoleInfo {
pub fn get_permissions(&self) -> &Vec<Permission> {
&self.permissions
}
pub fn get_name(&self) -> Option<&'static str> {
self.name
}
pub fn is_invitable(&self) -> bool {
self.is_invitable
}
}
pub static PREDEFINED_PERMISSIONS: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|| {
let mut roles = HashMap::new();
roles.insert(
consts::ROLE_ID_ORGANIZATION_ADMIN,
RoleInfo {
permissions: vec![
Permission::PaymentRead,
Permission::PaymentWrite,
Permission::RefundRead,
Permission::RefundWrite,
Permission::ApiKeyRead,
Permission::ApiKeyWrite,
Permission::MerchantAccountRead,
Permission::MerchantAccountWrite,
Permission::MerchantConnectorAccountRead,
Permission::MerchantConnectorAccountWrite,
Permission::RoutingRead,
Permission::RoutingWrite,
Permission::ForexRead,
Permission::ThreeDsDecisionManagerWrite,
Permission::ThreeDsDecisionManagerRead,
Permission::SurchargeDecisionManagerWrite,
Permission::SurchargeDecisionManagerRead,
Permission::DisputeRead,
Permission::DisputeWrite,
Permission::MandateRead,
Permission::MandateWrite,
Permission::FileRead,
Permission::FileWrite,
Permission::Analytics,
Permission::UsersRead,
Permission::UsersWrite,
Permission::MerchantAccountCreate,
],
name: Some("Organization Admin"),
is_invitable: false,
},
);
roles
});
pub fn get_role_name_from_id(role_id: &str) -> Option<&'static str> {
PREDEFINED_PERMISSIONS
.get(role_id)
.and_then(|role_info| role_info.name)
}
pub fn is_role_invitable(role_id: &str) -> bool {
PREDEFINED_PERMISSIONS
.get(role_id)
.map_or(false, |role_info| role_info.is_invitable)
}