Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ max_age = 365
outgoing_enabled = true
redis_lock_expiry_seconds = 180 # 3 * 60 seconds

[merchant_id_auth]
merchant_id_auth_enabled = false

[eph_key]
validity = 1

Expand Down
11 changes: 10 additions & 1 deletion crates/common_utils/src/id_type/merchant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Ids for merchant account are derived from the merchant name
//! If there are any special characters, they are removed

use std::fmt::Display;
use std::{fmt::Display, str::FromStr};

use crate::{
date_time,
Expand Down Expand Up @@ -38,6 +38,15 @@ impl From<MerchantId> for router_env::opentelemetry::Value {
}
}

impl FromStr for MerchantId {
type Err = error_stack::Report<ValidationError>;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let cow_string = std::borrow::Cow::Owned(s.to_string());
Self::try_from(cow_string)
}
}

impl MerchantId {
/// Create a Merchant id from MerchantName
pub fn from_merchant_name(merchant_name: MerchantName) -> Self {
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/configs/secrets_transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ pub(crate) async fn fetch_raw_secrets(
revenue_recovery: conf.revenue_recovery,
debit_routing_config: conf.debit_routing_config,
clone_connector_allowlist: conf.clone_connector_allowlist,
merchant_id_auth: conf.merchant_id_auth,
infra_values: conf.infra_values,
}
}
7 changes: 7 additions & 0 deletions crates/router/src/configs/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ pub struct Settings<S: SecretState> {
#[cfg(feature = "v2")]
pub revenue_recovery: revenue_recovery::RevenueRecoverySettings,
pub clone_connector_allowlist: Option<CloneConnectorAllowlistConfig>,
pub merchant_id_auth: MerchantIdAuthSettings,
#[serde(default)]
pub infra_values: Option<HashMap<String, String>>,
}
Expand Down Expand Up @@ -817,6 +818,12 @@ pub struct DrainerSettings {
pub loop_interval: u32, // in milliseconds
}

#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default)]
pub struct MerchantIdAuthSettings {
pub merchant_id_auth_enabled: bool,
}

#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default)]
pub struct WebhooksSettings {
Expand Down
38 changes: 22 additions & 16 deletions crates/router/src/routes/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,27 @@ pub async fn payments_create_and_confirm_intent(
}
};

let auth_type = if state.conf.merchant_id_auth.merchant_id_auth_enabled {
&auth::MerchantIdAuth()
} else {
match env::which() {
env::Env::Production => &auth::V2ApiKeyAuth {
is_connected_allowed: false,
is_platform_allowed: false,
},
_ => auth::auth_type(
&auth::V2ApiKeyAuth {
is_connected_allowed: false,
is_platform_allowed: false,
},
&auth::JWTAuth {
permission: Permission::ProfilePaymentWrite,
},
req.headers(),
),
}
};

Box::pin(api::server_wrap(
flow,
state,
Expand All @@ -280,22 +301,7 @@ pub async fn payments_create_and_confirm_intent(
header_payload.clone(),
)
},
match env::which() {
env::Env::Production => &auth::V2ApiKeyAuth {
is_connected_allowed: false,
is_platform_allowed: false,
},
_ => auth::auth_type(
&auth::V2ApiKeyAuth {
is_connected_allowed: false,
is_platform_allowed: false,
},
&auth::JWTAuth {
permission: Permission::ProfilePaymentWrite,
},
req.headers(),
),
},
auth_type,
api_locking::LockAction::NotApplicable,
))
.await
Expand Down
14 changes: 11 additions & 3 deletions crates/router/src/services/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2184,6 +2184,7 @@ where
}

#[derive(Debug)]
#[cfg(feature = "v1")]
pub struct MerchantIdAuth(pub id_type::MerchantId);

#[cfg(feature = "v1")]
Expand Down Expand Up @@ -2233,6 +2234,10 @@ where
}
}

#[derive(Debug)]
#[cfg(feature = "v2")]
pub struct MerchantIdAuth();

#[cfg(feature = "v2")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for MerchantIdAuth
Expand All @@ -2249,14 +2254,17 @@ where
}

let key_manager_state = &(&state.session_state()).into();
let merchant_id =
&get_id_type_by_key_from_headers(headers::X_MERCHANT_ID.to_string(), request_headers)?
.get_required_value(headers::X_MERCHANT_ID)?;
let profile_id =
get_id_type_by_key_from_headers(headers::X_PROFILE_ID.to_string(), request_headers)?
.get_required_value(headers::X_PROFILE_ID)?;
let key_store = state
.store()
.get_merchant_key_store_by_merchant_id(
key_manager_state,
&self.0,
merchant_id,
&state.store().get_master_key().to_vec().into(),
)
.await
Expand All @@ -2267,14 +2275,14 @@ where
.find_business_profile_by_merchant_id_profile_id(
key_manager_state,
&key_store,
&self.0,
merchant_id,
&profile_id,
)
.await
.to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;
let merchant = state
.store()
.find_merchant_account_by_merchant_id(key_manager_state, &self.0, &key_store)
.find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
.await
.to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

Expand Down
Loading