mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
refactor(euclid): check the authenticity of profile_id being used (#5647)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -57,18 +57,18 @@ pub struct ProfileDefaultRoutingConfig {
|
||||
pub connectors: Vec<RoutableConnectorChoice>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct RoutingRetrieveQuery {
|
||||
pub limit: Option<u16>,
|
||||
pub offset: Option<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct RoutingRetrieveLinkQuery {
|
||||
pub profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct RoutingRetrieveLinkQueryWrapper {
|
||||
pub routing_query: RoutingRetrieveQuery,
|
||||
pub profile_id: common_utils::id_type::ProfileId,
|
||||
|
||||
@ -84,12 +84,13 @@ impl RoutingAlgorithmUpdate {
|
||||
pub async fn retrieve_merchant_routing_dictionary(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
|
||||
query_params: RoutingRetrieveQuery,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingKind> {
|
||||
metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE.add(&metrics::CONTEXT, 1, &[]);
|
||||
|
||||
let routing_metadata = state
|
||||
let routing_metadata: Vec<diesel_models::routing_algorithm::RoutingProfileMetadata> = state
|
||||
.store
|
||||
.list_routing_algorithm_metadata_by_merchant_id_transaction_type(
|
||||
merchant_account.get_id(),
|
||||
@ -99,6 +100,9 @@ pub async fn retrieve_merchant_routing_dictionary(
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
let routing_metadata =
|
||||
super::utils::filter_objects_based_on_profile_id_list(profile_id_list, routing_metadata);
|
||||
|
||||
let result = routing_metadata
|
||||
.into_iter()
|
||||
.map(ForeignInto::foreign_into)
|
||||
@ -115,6 +119,7 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
request: routing_types::RoutingConfigRequest,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
@ -132,6 +137,8 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
.await?
|
||||
.get_required_value("BusinessProfile")?;
|
||||
|
||||
core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
|
||||
|
||||
let all_mcas = helpers::MerchantConnectorAccounts::get_all_mcas(
|
||||
merchant_account.get_id(),
|
||||
&key_store,
|
||||
@ -182,6 +189,7 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
request: routing_types::RoutingConfigRequest,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
@ -221,14 +229,17 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
})
|
||||
.attach_printable("Profile_id not provided")?;
|
||||
|
||||
core_utils::validate_and_get_business_profile(
|
||||
let business_profile = core_utils::validate_and_get_business_profile(
|
||||
db,
|
||||
key_manager_state,
|
||||
&key_store,
|
||||
Some(&profile_id),
|
||||
merchant_account.get_id(),
|
||||
)
|
||||
.await?;
|
||||
.await?
|
||||
.get_required_value("BusinessProfile")?;
|
||||
|
||||
core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
|
||||
|
||||
helpers::validate_connectors_in_routing_config(
|
||||
&state,
|
||||
@ -345,6 +356,7 @@ pub async fn link_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
algorithm_id: common_utils::id_type::RoutingId,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
@ -373,6 +385,8 @@ pub async fn link_routing_config(
|
||||
id: routing_algorithm.profile_id.get_string_repr().to_owned(),
|
||||
})?;
|
||||
|
||||
core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
|
||||
|
||||
let mut routing_ref: routing_types::RoutingAlgorithmRef = business_profile
|
||||
.routing_algorithm
|
||||
.clone()
|
||||
@ -421,6 +435,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
algorithm_id: common_utils::id_type::RoutingId,
|
||||
) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
|
||||
metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]);
|
||||
@ -430,7 +445,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id(
|
||||
let routing_algorithm =
|
||||
RoutingAlgorithmUpdate::fetch_routing_algo(merchant_account.get_id(), &algorithm_id, db)
|
||||
.await?;
|
||||
core_utils::validate_and_get_business_profile(
|
||||
let business_profile = core_utils::validate_and_get_business_profile(
|
||||
db,
|
||||
key_manager_state,
|
||||
&key_store,
|
||||
@ -441,6 +456,8 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id(
|
||||
.get_required_value("BusinessProfile")
|
||||
.change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
|
||||
core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
|
||||
|
||||
let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm.0)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("unable to parse routing algorithm")?;
|
||||
@ -454,6 +471,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
algorithm_id: common_utils::id_type::RoutingId,
|
||||
) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
|
||||
metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]);
|
||||
@ -468,7 +486,7 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id(
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
|
||||
core_utils::validate_and_get_business_profile(
|
||||
let business_profile = core_utils::validate_and_get_business_profile(
|
||||
db,
|
||||
key_manager_state,
|
||||
&key_store,
|
||||
@ -479,6 +497,8 @@ pub async fn retrieve_routing_algorithm_from_algorithm_id(
|
||||
.get_required_value("BusinessProfile")
|
||||
.change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
|
||||
core_utils::validate_profile_id_from_auth_layer(authentication_profile_id, &business_profile)?;
|
||||
|
||||
let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("unable to parse routing algorithm")?;
|
||||
@ -554,9 +574,11 @@ pub async fn unlink_routing_config(
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
request: routing_types::RoutingConfigRequest,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
metrics::ROUTING_UNLINK_CONFIG.add(&metrics::CONTEXT, 1, &[]);
|
||||
|
||||
let db = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
|
||||
@ -567,6 +589,7 @@ pub async fn unlink_routing_config(
|
||||
field_name: "profile_id",
|
||||
})
|
||||
.attach_printable("Profile_id not provided")?;
|
||||
|
||||
let business_profile = core_utils::validate_and_get_business_profile(
|
||||
db,
|
||||
key_manager_state,
|
||||
@ -575,8 +598,13 @@ pub async fn unlink_routing_config(
|
||||
merchant_account.get_id(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
match business_profile {
|
||||
Some(business_profile) => {
|
||||
core_utils::validate_profile_id_from_auth_layer(
|
||||
authentication_profile_id,
|
||||
&business_profile,
|
||||
)?;
|
||||
let routing_algo_ref: routing_types::RoutingAlgorithmRef = match transaction_type {
|
||||
enums::TransactionType::Payment => business_profile.routing_algorithm.clone(),
|
||||
#[cfg(feature = "payouts")]
|
||||
@ -880,6 +908,7 @@ pub async fn retrieve_linked_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
authentication_profile_id: Option<common_utils::id_type::ProfileId>,
|
||||
query_params: routing_types::RoutingRetrieveLinkQuery,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::LinkedRoutingConfigRetrieveResponse> {
|
||||
@ -902,13 +931,18 @@ pub async fn retrieve_linked_routing_config(
|
||||
id: profile_id.get_string_repr().to_owned(),
|
||||
})?
|
||||
} else {
|
||||
db.list_business_profile_by_merchant_id(
|
||||
let business_profile = db
|
||||
.list_business_profile_by_merchant_id(
|
||||
key_manager_state,
|
||||
&key_store,
|
||||
merchant_account.get_id(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
core_utils::filter_objects_based_on_profile_id_list(
|
||||
authentication_profile_id.map(|profile_id| vec![profile_id]),
|
||||
business_profile.clone(),
|
||||
)
|
||||
};
|
||||
|
||||
let mut active_algorithms = Vec::new();
|
||||
@ -1007,6 +1041,7 @@ pub async fn update_default_routing_config_for_profile(
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::ProfileDefaultRoutingConfig> {
|
||||
metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(&metrics::CONTEXT, 1, &[]);
|
||||
|
||||
let db = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
|
||||
|
||||
@ -1368,6 +1368,38 @@ impl GetProfileId for diesel_models::Refund {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
|
||||
impl GetProfileId for api_models::routing::RoutingConfigRequest {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
self.profile_id.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
impl GetProfileId for api_models::routing::RoutingConfigRequest {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
Some(&self.profile_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetProfileId for api_models::routing::RoutingRetrieveLinkQuery {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
self.profile_id.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetProfileId for diesel_models::routing_algorithm::RoutingProfileMetadata {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
Some(&self.profile_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl GetProfileId for domain::BusinessProfile {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
Some(self.get_id())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
impl GetProfileId for storage::Payouts {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
@ -1381,12 +1413,6 @@ impl<T, F> GetProfileId for (storage::Payouts, T, F) {
|
||||
}
|
||||
}
|
||||
|
||||
impl GetProfileId for domain::BusinessProfile {
|
||||
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
|
||||
Some(self.get_id())
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter Objects based on profile ids
|
||||
pub(super) fn filter_objects_based_on_profile_id_list<T: GetProfileId>(
|
||||
profile_id_list_auth_layer: Option<Vec<common_utils::id_type::ProfileId>>,
|
||||
|
||||
@ -711,6 +711,17 @@ impl Routing {
|
||||
)
|
||||
})),
|
||||
)
|
||||
.service(web::resource("/list/{profile_id}").route(web::get().to(
|
||||
|state, req, path, query: web::Query<RoutingRetrieveQuery>| {
|
||||
routing::list_routing_configs_for_profile(
|
||||
state,
|
||||
req,
|
||||
query,
|
||||
path,
|
||||
&TransactionType::Payment,
|
||||
)
|
||||
},
|
||||
)))
|
||||
.service(
|
||||
web::resource("/default")
|
||||
.route(web::get().to(|state, req| {
|
||||
|
||||
@ -34,6 +34,7 @@ pub async fn routing_create_config(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
auth.profile_id,
|
||||
payload,
|
||||
transaction_type,
|
||||
)
|
||||
@ -74,6 +75,7 @@ pub async fn routing_link_config(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
auth.profile_id,
|
||||
algorithm,
|
||||
transaction_type,
|
||||
)
|
||||
@ -110,7 +112,7 @@ pub async fn routing_link_config(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
wrapper,
|
||||
wrapper.clone(),
|
||||
|state, auth: auth::AuthenticationData, wrapper, _| {
|
||||
routing::link_routing_config_under_profile(
|
||||
state,
|
||||
@ -124,11 +126,17 @@ pub async fn routing_link_config(
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::ApiKeyAuth,
|
||||
&auth::JWTAuth(Permission::RoutingWrite),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: routing_payload_wrapper.profile_id,
|
||||
required_permission: Permission::RoutingWrite,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuth(Permission::RoutingWrite),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: wrapper.profile_id,
|
||||
required_permission: Permission::RoutingWrite,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
@ -153,6 +161,7 @@ pub async fn routing_retrieve_config(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
auth.profile_id,
|
||||
algorithm_id,
|
||||
)
|
||||
},
|
||||
@ -187,6 +196,7 @@ pub async fn list_routing_configs(
|
||||
routing::retrieve_merchant_routing_dictionary(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
None,
|
||||
query_params,
|
||||
transaction_type,
|
||||
)
|
||||
@ -204,6 +214,50 @@ pub async fn list_routing_configs(
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
#[instrument(skip_all)]
|
||||
pub async fn list_routing_configs_for_profile(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
query: web::Query<RoutingRetrieveQuery>,
|
||||
path: web::Path<common_utils::id_type::ProfileId>,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> impl Responder {
|
||||
let flow = Flow::RoutingRetrieveDictionary;
|
||||
let path = path.into_inner();
|
||||
Box::pin(oss_api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
query.into_inner(),
|
||||
|state, auth: auth::AuthenticationData, query_params, _| {
|
||||
routing::retrieve_merchant_routing_dictionary(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
auth.profile_id.map(|profile_id| vec![profile_id]),
|
||||
query_params,
|
||||
transaction_type,
|
||||
)
|
||||
},
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::HeaderAuth(auth::ApiKeyAuth),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: path,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: path,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "olap", feature = "v2", feature = "routing_v2"))]
|
||||
#[instrument(skip_all)]
|
||||
pub async fn routing_unlink_config(
|
||||
@ -213,11 +267,12 @@ pub async fn routing_unlink_config(
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> impl Responder {
|
||||
let flow = Flow::RoutingUnlinkConfig;
|
||||
let path = path.into_inner();
|
||||
Box::pin(oss_api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
path.into_inner(),
|
||||
path.clone(),
|
||||
|state, auth: auth::AuthenticationData, path, _| {
|
||||
routing::unlink_routing_config_under_profile(
|
||||
state,
|
||||
@ -230,11 +285,17 @@ pub async fn routing_unlink_config(
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::ApiKeyAuth,
|
||||
&auth::JWTAuth(Permission::RoutingWrite),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: path,
|
||||
required_permission: Permission::RoutingWrite,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuth(Permission::RoutingWrite),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: path,
|
||||
required_permission: Permission::RoutingWrite,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
@ -264,6 +325,7 @@ pub async fn routing_unlink_config(
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
payload_req,
|
||||
auth.profile_id,
|
||||
transaction_type,
|
||||
)
|
||||
},
|
||||
@ -374,11 +436,12 @@ pub async fn routing_retrieve_default_config(
|
||||
req: HttpRequest,
|
||||
path: web::Path<common_utils::id_type::ProfileId>,
|
||||
) -> impl Responder {
|
||||
let path = path.into_inner();
|
||||
Box::pin(oss_api::server_wrap(
|
||||
Flow::RoutingRetrieveDefaultConfig,
|
||||
state,
|
||||
&req,
|
||||
path.into_inner(),
|
||||
path.clone(),
|
||||
|state, auth: auth::AuthenticationData, profile_id, _| {
|
||||
routing::retrieve_default_fallback_algorithm_for_profile(
|
||||
state,
|
||||
@ -390,11 +453,17 @@ pub async fn routing_retrieve_default_config(
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::HeaderAuth(auth::ApiKeyAuth),
|
||||
&auth::JWTAuth(Permission::RoutingRead),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: path,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuth(Permission::RoutingRead),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: path,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
@ -636,16 +705,52 @@ pub async fn routing_retrieve_linked_config(
|
||||
) -> impl Responder {
|
||||
use crate::services::authentication::AuthenticationData;
|
||||
let flow = Flow::RoutingRetrieveActiveConfig;
|
||||
let query = query.into_inner();
|
||||
if let Some(profile_id) = query.profile_id.clone() {
|
||||
Box::pin(oss_api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
query.into_inner(),
|
||||
query.clone(),
|
||||
|state, auth: AuthenticationData, query_params, _| {
|
||||
routing::retrieve_linked_routing_config(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
auth.profile_id,
|
||||
query_params,
|
||||
transaction_type,
|
||||
)
|
||||
},
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::HeaderAuth(auth::ApiKeyAuth),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
} else {
|
||||
Box::pin(oss_api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
query.clone(),
|
||||
|state, auth: AuthenticationData, query_params, _| {
|
||||
routing::retrieve_linked_routing_config(
|
||||
state,
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
auth.profile_id,
|
||||
query_params,
|
||||
transaction_type,
|
||||
)
|
||||
@ -661,6 +766,7 @@ pub async fn routing_retrieve_linked_config(
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
@ -687,7 +793,7 @@ pub async fn routing_retrieve_linked_config(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
wrapper,
|
||||
wrapper.clone(),
|
||||
|state, auth: AuthenticationData, wrapper, _| {
|
||||
routing::retrieve_routing_config_under_profile(
|
||||
state,
|
||||
@ -701,11 +807,17 @@ pub async fn routing_retrieve_linked_config(
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::HeaderAuth(auth::ApiKeyAuth),
|
||||
&auth::JWTAuth(Permission::RoutingRead),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: wrapper.profile_id,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuth(Permission::RoutingRead),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: wrapper.profile_id,
|
||||
required_permission: Permission::RoutingRead,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
@ -765,7 +877,7 @@ pub async fn routing_update_default_config_for_profile(
|
||||
Flow::RoutingUpdateDefaultConfig,
|
||||
state,
|
||||
&req,
|
||||
routing_payload_wrapper,
|
||||
routing_payload_wrapper.clone(),
|
||||
|state, auth: auth::AuthenticationData, wrapper, _| {
|
||||
routing::update_default_routing_config_for_profile(
|
||||
state,
|
||||
@ -779,11 +891,17 @@ pub async fn routing_update_default_config_for_profile(
|
||||
#[cfg(not(feature = "release"))]
|
||||
auth::auth_type(
|
||||
&auth::HeaderAuth(auth::ApiKeyAuth),
|
||||
&auth::JWTAuth(Permission::RoutingWrite),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: routing_payload_wrapper.profile_id,
|
||||
required_permission: Permission::RoutingWrite,
|
||||
},
|
||||
req.headers(),
|
||||
),
|
||||
#[cfg(feature = "release")]
|
||||
&auth::JWTAuth(Permission::RoutingWrite),
|
||||
&auth::JWTAuthProfileFromRoute {
|
||||
profile_id: routing_payload_wrapper.profile_id,
|
||||
required_permission: Permission::RoutingWrite,
|
||||
},
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
|
||||
@ -1329,7 +1329,6 @@ where
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JWTAuthMerchantAndProfileFromRoute {
|
||||
pub merchant_id: id_type::MerchantId,
|
||||
pub profile_id: id_type::ProfileId,
|
||||
@ -1404,6 +1403,87 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct JWTAuthProfileFromRoute {
|
||||
pub profile_id: id_type::ProfileId,
|
||||
pub required_permission: Permission,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<A> AuthenticateAndFetch<AuthenticationData, A> for JWTAuthProfileFromRoute
|
||||
where
|
||||
A: SessionStateInfo + Sync,
|
||||
{
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &A,
|
||||
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
|
||||
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||
if payload.check_in_blacklist(state).await? {
|
||||
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||
}
|
||||
|
||||
let permissions = authorization::get_permissions(state, &payload).await?;
|
||||
authorization::check_authorization(&self.required_permission, &permissions)?;
|
||||
let key_manager_state = &(&state.session_state()).into();
|
||||
let key_store = state
|
||||
.store()
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&payload.merchant_id,
|
||||
&state.store().get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::InvalidJwtToken)
|
||||
.attach_printable("Failed to fetch merchant key store for the merchant id")?;
|
||||
|
||||
let merchant = state
|
||||
.store()
|
||||
.find_merchant_account_by_merchant_id(
|
||||
key_manager_state,
|
||||
&payload.merchant_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::InvalidJwtToken)
|
||||
.attach_printable("Failed to fetch merchant account for the merchant id")?;
|
||||
|
||||
if let Some(ref payload_profile_id) = payload.profile_id {
|
||||
if *payload_profile_id != self.profile_id {
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidJwtToken));
|
||||
} else {
|
||||
// if both of them are same then proceed with the profile id present in the request
|
||||
let auth = AuthenticationData {
|
||||
merchant_account: merchant,
|
||||
key_store,
|
||||
profile_id: Some(self.profile_id.clone()),
|
||||
};
|
||||
Ok((
|
||||
auth.clone(),
|
||||
AuthenticationType::MerchantJwt {
|
||||
merchant_id: auth.merchant_account.get_id().clone(),
|
||||
user_id: Some(payload.user_id),
|
||||
},
|
||||
))
|
||||
}
|
||||
} else {
|
||||
// if profile_id is not present in the auth_layer itself then no change in behaviour
|
||||
let auth = AuthenticationData {
|
||||
merchant_account: merchant,
|
||||
key_store,
|
||||
profile_id: payload.profile_id,
|
||||
};
|
||||
Ok((
|
||||
auth.clone(),
|
||||
AuthenticationType::MerchantJwt {
|
||||
merchant_id: auth.merchant_account.get_id().clone(),
|
||||
user_id: Some(payload.user_id),
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn parse_jwt_payload<A, T>(headers: &HeaderMap, state: &A) -> RouterResult<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
|
||||
Reference in New Issue
Block a user