Skip to content

Commit

Permalink
refactor(euclid): check the authenticity of profile_id being used (#5647
Browse files Browse the repository at this point in the history
)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
prajjwalkumar17 and hyperswitch-bot[bot] authored Sep 3, 2024
1 parent 8ed942c commit 0fb8e85
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 59 deletions.
6 changes: 3 additions & 3 deletions crates/api_models/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
57 changes: 46 additions & 11 deletions crates/router/src/core/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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)
Expand All @@ -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> {
Expand All @@ -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,
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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, &[]);
Expand All @@ -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,
Expand All @@ -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")?;
Expand All @@ -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, &[]);
Expand All @@ -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,
Expand All @@ -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")?;
Expand Down Expand Up @@ -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();

Expand All @@ -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,
Expand All @@ -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")]
Expand Down Expand Up @@ -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> {
Expand All @@ -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(
key_manager_state,
&key_store,
merchant_account.get_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)?;
core_utils::filter_objects_based_on_profile_id_list(
authentication_profile_id.map(|profile_id| vec![profile_id]),
business_profile.clone(),
)
.await
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?
};

let mut active_algorithms = Vec::new();
Expand Down Expand Up @@ -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();

Expand Down
36 changes: 31 additions & 5 deletions crates/router/src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1368,16 +1368,29 @@ impl GetProfileId for diesel_models::Refund {
}
}

#[cfg(feature = "payouts")]
impl GetProfileId for storage::Payouts {
#[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)
}
}
#[cfg(feature = "payouts")]
impl<T, F> GetProfileId for (storage::Payouts, T, F) {

impl GetProfileId for api_models::routing::RoutingRetrieveLinkQuery {
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
self.0.get_profile_id()
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)
}
}

Expand All @@ -1387,6 +1400,19 @@ impl GetProfileId for domain::BusinessProfile {
}
}

#[cfg(feature = "payouts")]
impl GetProfileId for storage::Payouts {
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
Some(&self.profile_id)
}
}
#[cfg(feature = "payouts")]
impl<T, F> GetProfileId for (storage::Payouts, T, F) {
fn get_profile_id(&self) -> Option<&common_utils::id_type::ProfileId> {
self.0.get_profile_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>>,
Expand Down
11 changes: 11 additions & 0 deletions crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down
Loading

0 comments on commit 0fb8e85

Please sign in to comment.