Skip to content

Commit 716d76c

Browse files
feat(core): Add mTLS certificates for each request (#5636)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 4585e16 commit 716d76c

File tree

10 files changed

+101
-89
lines changed

10 files changed

+101
-89
lines changed

crates/connector_configs/toml/development.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1617,9 +1617,11 @@ merchant_secret="Source verification key"
16171617
[itaubank]
16181618
[[itaubank.bank_transfer]]
16191619
payment_method_type = "pix"
1620-
[itaubank.connector_auth.BodyKey]
1620+
[itaubank.connector_auth.MultiAuthKey]
16211621
key1="Client Id"
16221622
api_key="Client Secret"
1623+
api_secret="Certificates"
1624+
key2="Certificate Key"
16231625

16241626
[klarna]
16251627
[[klarna.pay_later]]

crates/connector_configs/toml/production.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1373,9 +1373,11 @@ merchant_secret="Source verification key"
13731373
[itaubank]
13741374
[[itaubank.bank_transfer]]
13751375
payment_method_type = "pix"
1376-
[itaubank.connector_auth.BodyKey]
1376+
[itaubank.connector_auth.MultiAuthKey]
13771377
key1="Client Id"
13781378
api_key="Client Secret"
1379+
api_secret="Certificates"
1380+
key2="Certificate Key"
13791381

13801382
[klarna]
13811383
[[klarna.pay_later]]

crates/connector_configs/toml/sandbox.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1615,9 +1615,11 @@ merchant_secret="Source verification key"
16151615
[itaubank]
16161616
[[itaubank.bank_transfer]]
16171617
payment_method_type = "pix"
1618-
[itaubank.connector_auth.BodyKey]
1618+
[itaubank.connector_auth.MultiAuthKey]
16191619
key1="Client Id"
16201620
api_key="Client Secret"
1621+
api_secret="Certificates"
1622+
key2="Certificate Key"
16211623

16221624
[klarna]
16231625
[[klarna.pay_later]]

crates/router/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ rand = "0.8.5"
9393
rand_chacha = "0.3.1"
9494
rdkafka = "0.36.2"
9595
regex = "1.10.4"
96-
reqwest = { version = "0.11.27", features = ["json", "native-tls", "__rustls", "gzip", "multipart"] }
96+
reqwest = { version = "0.11.27", features = ["json", "rustls-tls", "gzip", "multipart"] }
9797
ring = "0.17.8"
9898
roxmltree = "0.19.0"
9999
rust_decimal = { version = "1.35.0", features = ["serde-with-float", "serde-with-str"] }

crates/router/src/connector/itaubank.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,15 @@ impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, t
197197
req: &types::RefreshTokenRouterData,
198198
connectors: &settings::Connectors,
199199
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
200+
let auth_details = itaubank::ItaubankAuthType::try_from(&req.connector_auth_type)?;
200201
let req = Some(
201202
services::RequestBuilder::new()
202203
.method(services::Method::Post)
203204
.attach_default_headers()
204205
.headers(types::RefreshTokenType::get_headers(self, req, connectors)?)
205206
.url(&types::RefreshTokenType::get_url(self, req, connectors)?)
207+
.add_certificate(auth_details.certificate)
208+
.add_certificate_key(auth_details.certificate_key)
206209
.set_body(types::RefreshTokenType::get_request_body(
207210
self, req, connectors,
208211
)?)
@@ -326,6 +329,7 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
326329
req: &types::PaymentsAuthorizeRouterData,
327330
connectors: &settings::Connectors,
328331
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
332+
let auth_details = itaubank::ItaubankAuthType::try_from(&req.connector_auth_type)?;
329333
Ok(Some(
330334
services::RequestBuilder::new()
331335
.method(services::Method::Post)
@@ -336,6 +340,8 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
336340
.headers(types::PaymentsAuthorizeType::get_headers(
337341
self, req, connectors,
338342
)?)
343+
.add_certificate(auth_details.certificate)
344+
.add_certificate_key(auth_details.certificate_key)
339345
.set_body(types::PaymentsAuthorizeType::get_request_body(
340346
self, req, connectors,
341347
)?)
@@ -406,12 +412,15 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
406412
req: &types::PaymentsSyncRouterData,
407413
connectors: &settings::Connectors,
408414
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
415+
let auth_details = itaubank::ItaubankAuthType::try_from(&req.connector_auth_type)?;
409416
Ok(Some(
410417
services::RequestBuilder::new()
411418
.method(services::Method::Get)
412419
.url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
413420
.attach_default_headers()
414421
.headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
422+
.add_certificate(auth_details.certificate)
423+
.add_certificate_key(auth_details.certificate_key)
415424
.build(),
416425
))
417426
}
@@ -480,6 +489,7 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
480489
req: &types::PaymentsCaptureRouterData,
481490
connectors: &settings::Connectors,
482491
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
492+
let auth_details = itaubank::ItaubankAuthType::try_from(&req.connector_auth_type)?;
483493
Ok(Some(
484494
services::RequestBuilder::new()
485495
.method(services::Method::Post)
@@ -488,6 +498,8 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
488498
.headers(types::PaymentsCaptureType::get_headers(
489499
self, req, connectors,
490500
)?)
501+
.add_certificate(auth_details.certificate)
502+
.add_certificate_key(auth_details.certificate_key)
491503
.set_body(types::PaymentsCaptureType::get_request_body(
492504
self, req, connectors,
493505
)?)
@@ -597,13 +609,16 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
597609
req: &types::RefundsRouterData<api::Execute>,
598610
connectors: &settings::Connectors,
599611
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
612+
let auth_details = itaubank::ItaubankAuthType::try_from(&req.connector_auth_type)?;
600613
let request = services::RequestBuilder::new()
601614
.method(services::Method::Put)
602615
.url(&types::RefundExecuteType::get_url(self, req, connectors)?)
603616
.attach_default_headers()
604617
.headers(types::RefundExecuteType::get_headers(
605618
self, req, connectors,
606619
)?)
620+
.add_certificate(auth_details.certificate)
621+
.add_certificate_key(auth_details.certificate_key)
607622
.set_body(types::RefundExecuteType::get_request_body(
608623
self, req, connectors,
609624
)?)
@@ -679,12 +694,15 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
679694
req: &types::RefundSyncRouterData,
680695
connectors: &settings::Connectors,
681696
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
697+
let auth_details = itaubank::ItaubankAuthType::try_from(&req.connector_auth_type)?;
682698
Ok(Some(
683699
services::RequestBuilder::new()
684700
.method(services::Method::Get)
685701
.url(&types::RefundSyncType::get_url(self, req, connectors)?)
686702
.attach_default_headers()
687703
.headers(types::RefundSyncType::get_headers(self, req, connectors)?)
704+
.add_certificate(auth_details.certificate)
705+
.add_certificate_key(auth_details.certificate_key)
688706
.set_body(types::RefundSyncType::get_request_body(
689707
self, req, connectors,
690708
)?)

crates/router/src/connector/itaubank/transformers.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,30 @@ impl TryFrom<&ItaubankRouterData<&types::PaymentsAuthorizeRouterData>> for Itaub
133133
pub struct ItaubankAuthType {
134134
pub(super) client_id: Secret<String>,
135135
pub(super) client_secret: Secret<String>,
136+
pub(super) certificate: Option<Secret<String>>,
137+
pub(super) certificate_key: Option<Secret<String>>,
136138
}
137139

138140
impl TryFrom<&types::ConnectorAuthType> for ItaubankAuthType {
139141
type Error = error_stack::Report<errors::ConnectorError>;
140142
fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
141143
match auth_type {
144+
types::ConnectorAuthType::MultiAuthKey {
145+
api_key,
146+
key1,
147+
api_secret,
148+
key2,
149+
} => Ok(Self {
150+
client_secret: api_key.to_owned(),
151+
client_id: key1.to_owned(),
152+
certificate: Some(api_secret.to_owned()),
153+
certificate_key: Some(key2.to_owned()),
154+
}),
142155
types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
143156
client_secret: api_key.to_owned(),
144157
client_id: key1.to_owned(),
158+
certificate: None,
159+
certificate_key: None,
145160
}),
146161
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
147162
}

crates/router/src/core/admin.rs

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use api_models::{
44
admin::{self as admin_types},
55
enums as api_enums, routing as routing_types,
66
};
7-
use base64::Engine;
87
use common_utils::{
98
date_time,
109
ext_traits::{AsyncExt, Encode, OptionExt, ValueExt},
@@ -24,7 +23,7 @@ use uuid::Uuid;
2423
#[cfg(any(feature = "v1", feature = "v2"))]
2524
use crate::types::transformers::ForeignFrom;
2625
use crate::{
27-
consts::{self, BASE64_ENGINE},
26+
consts,
2827
core::{
2928
encryption::transfer_encryption_key,
3029
errors::{self, RouterResponse, RouterResult, StorageErrorExt},
@@ -35,7 +34,11 @@ use crate::{
3534
},
3635
db::StorageInterface,
3736
routes::{metrics, SessionState},
38-
services::{self, api as service_api, authentication, pm_auth as payment_initiation_service},
37+
services::{
38+
self,
39+
api::{self as service_api, client},
40+
authentication, pm_auth as payment_initiation_service,
41+
},
3942
types::{
4043
self,
4144
api::{self, admin},
@@ -198,6 +201,10 @@ pub async fn create_merchant_account(
198201
let identifier = km_types::Identifier::Merchant(merchant_id.clone());
199202
#[cfg(feature = "keymanager_create")]
200203
{
204+
use base64::Engine;
205+
206+
use crate::consts::BASE64_ENGINE;
207+
201208
keymanager::transfer_key_to_key_manager(
202209
key_manager_state,
203210
EncryptionTransferRequest {
@@ -1604,7 +1611,7 @@ impl<'a> ConnectorAuthTypeValidation<'a> {
16041611
certificate,
16051612
private_key,
16061613
} => {
1607-
helpers::create_identity_from_certificate_and_key(
1614+
client::create_identity_from_certificate_and_key(
16081615
certificate.to_owned(),
16091616
private_key.to_owned(),
16101617
)
@@ -1695,34 +1702,6 @@ impl<'a> PaymentMethodsEnabled<'a> {
16951702
}
16961703
}
16971704

1698-
struct CertificateAndCertificateKey<'a> {
1699-
certificate: &'a Secret<String>,
1700-
certificate_key: &'a Secret<String>,
1701-
}
1702-
1703-
impl<'a> CertificateAndCertificateKey<'a> {
1704-
pub fn create_identity_from_certificate_and_key(
1705-
&self,
1706-
) -> Result<reqwest::Identity, error_stack::Report<errors::ApiClientError>> {
1707-
let decoded_certificate = BASE64_ENGINE
1708-
.decode(self.certificate.clone().expose())
1709-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
1710-
1711-
let decoded_certificate_key = BASE64_ENGINE
1712-
.decode(self.certificate_key.clone().expose())
1713-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
1714-
1715-
let certificate = String::from_utf8(decoded_certificate)
1716-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
1717-
1718-
let certificate_key = String::from_utf8(decoded_certificate_key)
1719-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
1720-
1721-
reqwest::Identity::from_pkcs8_pem(certificate.as_bytes(), certificate_key.as_bytes())
1722-
.change_context(errors::ApiClientError::CertificateDecodeFailed)
1723-
}
1724-
}
1725-
17261705
struct ConnectorMetadata<'a> {
17271706
connector_metadata: &'a Option<pii::SecretSerdeValue>,
17281707
}
@@ -1739,11 +1718,7 @@ impl<'a> ConnectorMetadata<'a> {
17391718
})?
17401719
.and_then(|metadata| metadata.get_apple_pay_certificates())
17411720
.map(|(certificate, certificate_key)| {
1742-
let certificate_and_certificate_key = CertificateAndCertificateKey {
1743-
certificate: &certificate,
1744-
certificate_key: &certificate_key,
1745-
};
1746-
certificate_and_certificate_key.create_identity_from_certificate_and_key()
1721+
client::create_identity_from_certificate_and_key(certificate, certificate_key)
17471722
})
17481723
.transpose()
17491724
.change_context(errors::ApiErrorResponse::InvalidDataValue {

crates/router/src/core/payments/helpers.rs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -99,41 +99,6 @@ use crate::{
9999
core::payment_methods::cards::create_encrypted_data, types::storage::CustomerUpdate::Update,
100100
};
101101

102-
pub fn create_identity_from_certificate_and_key(
103-
encoded_certificate: masking::Secret<String>,
104-
encoded_certificate_key: masking::Secret<String>,
105-
) -> Result<reqwest::Identity, error_stack::Report<errors::ApiClientError>> {
106-
let decoded_certificate = BASE64_ENGINE
107-
.decode(encoded_certificate.expose())
108-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
109-
110-
let decoded_certificate_key = BASE64_ENGINE
111-
.decode(encoded_certificate_key.expose())
112-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
113-
114-
let certificate = String::from_utf8(decoded_certificate)
115-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
116-
117-
let certificate_key = String::from_utf8(decoded_certificate_key)
118-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
119-
120-
reqwest::Identity::from_pkcs8_pem(certificate.as_bytes(), certificate_key.as_bytes())
121-
.change_context(errors::ApiClientError::CertificateDecodeFailed)
122-
}
123-
124-
pub fn create_certificate(
125-
encoded_certificate: masking::Secret<String>,
126-
) -> Result<Vec<reqwest::Certificate>, error_stack::Report<errors::ApiClientError>> {
127-
let decoded_certificate = BASE64_ENGINE
128-
.decode(encoded_certificate.expose())
129-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
130-
131-
let certificate = String::from_utf8(decoded_certificate)
132-
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
133-
reqwest::Certificate::from_pem_bundle(certificate.as_bytes())
134-
.change_context(errors::ApiClientError::CertificateDecodeFailed)
135-
}
136-
137102
pub fn filter_mca_based_on_profile_and_connector_type(
138103
merchant_connector_accounts: Vec<domain::MerchantConnectorAccount>,
139104
profile_id: &id_type::ProfileId,

0 commit comments

Comments
 (0)