Skip to content

Commit 658c95c

Browse files
committed
feat: add mtls support for request
1 parent 4eab660 commit 658c95c

File tree

11 files changed

+101
-22
lines changed

11 files changed

+101
-22
lines changed

crates/common_utils/src/request.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ pub enum ContentType {
2424
Xml,
2525
}
2626

27+
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
28+
pub enum VerificationType {
29+
Tls,
30+
Mtls,
31+
}
32+
2733
fn default_request_headers() -> [(String, Maskable<String>); 1] {
2834
use http::header;
2935

@@ -38,6 +44,7 @@ pub struct Request {
3844
pub certificate: Option<Secret<String>>,
3945
pub certificate_key: Option<Secret<String>>,
4046
pub body: Option<RequestContent>,
47+
pub verificaton_type: Option<VerificationType>,
4148
}
4249

4350
impl std::fmt::Debug for RequestContent {
@@ -81,6 +88,7 @@ impl Request {
8188
certificate: None,
8289
certificate_key: None,
8390
body: None,
91+
verificaton_type: None,
8492
}
8593
}
8694

@@ -113,6 +121,7 @@ pub struct RequestBuilder {
113121
pub certificate: Option<Secret<String>>,
114122
pub certificate_key: Option<Secret<String>>,
115123
pub body: Option<RequestContent>,
124+
pub verificaton_type: Option<VerificationType>,
116125
}
117126

118127
impl RequestBuilder {
@@ -124,6 +133,7 @@ impl RequestBuilder {
124133
certificate: None,
125134
certificate_key: None,
126135
body: None,
136+
verificaton_type: None,
127137
}
128138
}
129139

@@ -157,8 +167,13 @@ impl RequestBuilder {
157167
self
158168
}
159169

160-
pub fn add_certificate(mut self, certificate: Option<Secret<String>>) -> Self {
170+
pub fn add_certificate(
171+
mut self,
172+
certificate: Option<Secret<String>>,
173+
verification_type: VerificationType,
174+
) -> Self {
161175
self.certificate = certificate;
176+
self.verificaton_type = Some(verification_type);
162177
self
163178
}
164179

@@ -175,6 +190,7 @@ impl RequestBuilder {
175190
certificate: self.certificate,
176191
certificate_key: self.certificate_key,
177192
body: self.body,
193+
verificaton_type: self.verificaton_type,
178194
}
179195
}
180196
}

crates/router/src/connector/gpayments.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,10 @@ impl
287287
self, req, connectors,
288288
)?,
289289
)
290-
.add_certificate(Some(gpayments_auth_type.certificate))
290+
.add_certificate(
291+
Some(gpayments_auth_type.certificate),
292+
services::VerificationType::Tls,
293+
)
291294
.add_certificate_key(Some(gpayments_auth_type.private_key))
292295
.build(),
293296
))
@@ -374,7 +377,10 @@ impl
374377
self, req, connectors,
375378
)?,
376379
)
377-
.add_certificate(Some(gpayments_auth_type.certificate))
380+
.add_certificate(
381+
Some(gpayments_auth_type.certificate),
382+
services::VerificationType::Tls,
383+
)
378384
.add_certificate_key(Some(gpayments_auth_type.private_key))
379385
.build(),
380386
))
@@ -482,7 +488,10 @@ impl
482488
self, req, connectors,
483489
)?,
484490
)
485-
.add_certificate(Some(gpayments_auth_type.certificate))
491+
.add_certificate(
492+
Some(gpayments_auth_type.certificate),
493+
services::VerificationType::Tls,
494+
)
486495
.add_certificate_key(Some(gpayments_auth_type.private_key))
487496
.build(),
488497
))
@@ -579,7 +588,7 @@ impl
579588
self, req, connectors,
580589
)?,
581590
)
582-
.add_certificate(Some(gpayments_auth_type.certificate))
591+
.add_certificate(Some(gpayments_auth_type.certificate), services::VerificationType::Tls)
583592
.add_certificate_key(Some(gpayments_auth_type.private_key))
584593
.build(),
585594
))

crates/router/src/connector/itaubank.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, t
204204
.attach_default_headers()
205205
.headers(types::RefreshTokenType::get_headers(self, req, connectors)?)
206206
.url(&types::RefreshTokenType::get_url(self, req, connectors)?)
207-
.add_certificate(auth_details.certificate)
207+
.add_certificate(auth_details.certificate, services::VerificationType::Mtls)
208208
.add_certificate_key(auth_details.certificate_key)
209209
.set_body(types::RefreshTokenType::get_request_body(
210210
self, req, connectors,
@@ -340,7 +340,7 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
340340
.headers(types::PaymentsAuthorizeType::get_headers(
341341
self, req, connectors,
342342
)?)
343-
.add_certificate(auth_details.certificate)
343+
.add_certificate(auth_details.certificate, services::VerificationType::Mtls)
344344
.add_certificate_key(auth_details.certificate_key)
345345
.set_body(types::PaymentsAuthorizeType::get_request_body(
346346
self, req, connectors,
@@ -419,7 +419,7 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
419419
.url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
420420
.attach_default_headers()
421421
.headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
422-
.add_certificate(auth_details.certificate)
422+
.add_certificate(auth_details.certificate, services::VerificationType::Mtls)
423423
.add_certificate_key(auth_details.certificate_key)
424424
.build(),
425425
))
@@ -498,7 +498,7 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
498498
.headers(types::PaymentsCaptureType::get_headers(
499499
self, req, connectors,
500500
)?)
501-
.add_certificate(auth_details.certificate)
501+
.add_certificate(auth_details.certificate, services::VerificationType::Mtls)
502502
.add_certificate_key(auth_details.certificate_key)
503503
.set_body(types::PaymentsCaptureType::get_request_body(
504504
self, req, connectors,
@@ -617,7 +617,7 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
617617
.headers(types::RefundExecuteType::get_headers(
618618
self, req, connectors,
619619
)?)
620-
.add_certificate(auth_details.certificate)
620+
.add_certificate(auth_details.certificate, services::VerificationType::Mtls)
621621
.add_certificate_key(auth_details.certificate_key)
622622
.set_body(types::RefundExecuteType::get_request_body(
623623
self, req, connectors,
@@ -701,7 +701,7 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
701701
.url(&types::RefundSyncType::get_url(self, req, connectors)?)
702702
.attach_default_headers()
703703
.headers(types::RefundSyncType::get_headers(self, req, connectors)?)
704-
.add_certificate(auth_details.certificate)
704+
.add_certificate(auth_details.certificate, services::VerificationType::Mtls)
705705
.add_certificate_key(auth_details.certificate_key)
706706
.set_body(types::RefundSyncType::get_request_body(
707707
self, req, connectors,

crates/router/src/connector/netcetera.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,10 @@ impl
298298
self, req, connectors,
299299
)?,
300300
)
301-
.add_certificate(Some(netcetera_auth_type.certificate))
301+
.add_certificate(
302+
Some(netcetera_auth_type.certificate),
303+
services::VerificationType::Tls,
304+
)
302305
.add_certificate_key(Some(netcetera_auth_type.private_key))
303306
.build(),
304307
))
@@ -408,7 +411,10 @@ impl
408411
self, req, connectors,
409412
)?,
410413
)
411-
.add_certificate(Some(netcetera_auth_type.certificate))
414+
.add_certificate(
415+
Some(netcetera_auth_type.certificate),
416+
services::VerificationType::Tls,
417+
)
412418
.add_certificate_key(Some(netcetera_auth_type.private_key))
413419
.build(),
414420
))

crates/router/src/core/admin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,7 @@ impl<'a> ConnectorAuthTypeValidation<'a> {
16171617
helpers::create_identity_from_certificate_and_key(
16181618
certificate.to_owned(),
16191619
private_key.to_owned(),
1620+
false,
16201621
)
16211622
.change_context(errors::ApiErrorResponse::InvalidDataFormat {
16221623
field_name:

crates/router/src/core/payments/flows/session_flow.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ fn build_apple_pay_session_request(
159159
"application/json".to_string().into(),
160160
)])
161161
.set_body(RequestContent::Json(Box::new(request)))
162-
.add_certificate(Some(apple_pay_merchant_cert))
162+
.add_certificate(
163+
Some(apple_pay_merchant_cert),
164+
services::VerificationType::Tls,
165+
)
163166
.add_certificate_key(Some(apple_pay_merchant_cert_key))
164167
.build();
165168
Ok(session_request)

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ use crate::{
9090
pub fn create_identity_from_certificate_and_key(
9191
encoded_certificate: masking::Secret<String>,
9292
encoded_certificate_key: masking::Secret<String>,
93+
should_concate_cert_and_key: bool,
9394
) -> Result<reqwest::Identity, error_stack::Report<errors::ApiClientError>> {
9495
let decoded_certificate = BASE64_ENGINE
9596
.decode(encoded_certificate.expose())
@@ -105,8 +106,14 @@ pub fn create_identity_from_certificate_and_key(
105106
let certificate_key = String::from_utf8(decoded_certificate_key)
106107
.change_context(errors::ApiClientError::CertificateDecodeFailed)?;
107108

108-
reqwest::Identity::from_pkcs8_pem(certificate.as_bytes(), certificate_key.as_bytes())
109-
.change_context(errors::ApiClientError::CertificateDecodeFailed)
109+
if should_concate_cert_and_key {
110+
let client_cert = format!("{}{}", certificate_key, certificate);
111+
reqwest::Identity::from_pem(client_cert.as_bytes())
112+
.change_context(errors::ApiClientError::CertificateDecodeFailed)
113+
} else {
114+
reqwest::Identity::from_pkcs8_pem(certificate.as_bytes(), certificate_key.as_bytes())
115+
.change_context(errors::ApiClientError::CertificateDecodeFailed)
116+
}
110117
}
111118

112119
pub fn create_certificate(

crates/router/src/core/verification.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
pub mod utils;
22
use api_models::verifications::{self, ApplepayMerchantResponse};
3-
use common_utils::{errors::CustomResult, request::RequestContent};
3+
use common_utils::{
4+
errors::CustomResult,
5+
request::{RequestContent, VerificationType},
6+
};
47
use error_stack::ResultExt;
58
use masking::ExposeInterface;
69

@@ -41,7 +44,7 @@ pub async fn verify_merchant_creds_for_applepay(
4144
"application/json".to_string().into(),
4245
)])
4346
.set_body(RequestContent::Json(Box::new(request_body)))
44-
.add_certificate(Some(cert_data))
47+
.add_certificate(Some(cert_data), VerificationType::Tls)
4548
.add_certificate_key(Some(key_data))
4649
.build();
4750

crates/router/src/services/api.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use actix_web::{
1919
};
2020
pub use client::{proxy_bypass_urls, ApiClient, MockApiClient, ProxyClient};
2121
pub use common_enums::enums::PaymentAction;
22-
pub use common_utils::request::{ContentType, Method, Request, RequestBuilder};
22+
pub use common_utils::request::{ContentType, Method, Request, RequestBuilder, VerificationType};
2323
use common_utils::{
2424
consts::{DEFAULT_TENANT, TENANT_HEADER, X_HS_LATENCY},
2525
errors::{ErrorSwitch, ReportSwitchExt},
@@ -433,6 +433,7 @@ pub async fn send_request(
433433
should_bypass_proxy,
434434
request.certificate,
435435
request.certificate_key,
436+
request.verificaton_type,
436437
)?;
437438

438439
let headers = request.headers.construct_header_map()?;

crates/router/src/services/api/client.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
payments,
1717
},
1818
routes::{app::settings::KeyManagerConfig, SessionState},
19+
services::VerificationType,
1920
};
2021

2122
static NON_PROXIED_CLIENT: OnceCell<reqwest::Client> = OnceCell::new();
@@ -85,14 +86,20 @@ pub fn create_client(
8586
should_bypass_proxy: bool,
8687
client_certificate: Option<masking::Secret<String>>,
8788
client_certificate_key: Option<masking::Secret<String>>,
89+
verification_type: Option<VerificationType>,
8890
) -> CustomResult<reqwest::Client, ApiClientError> {
89-
match (client_certificate, client_certificate_key) {
90-
(Some(encoded_certificate), Some(encoded_certificate_key)) => {
91+
match (
92+
verification_type,
93+
client_certificate,
94+
client_certificate_key,
95+
) {
96+
(Some(VerificationType::Tls), Some(encoded_certificate), Some(encoded_certificate_key)) => {
9197
let client_builder = get_client_builder(proxy_config, should_bypass_proxy)?;
9298

9399
let identity = payments::helpers::create_identity_from_certificate_and_key(
94100
encoded_certificate.clone(),
95101
encoded_certificate_key,
102+
false,
96103
)?;
97104
let certificate_list = payments::helpers::create_certificate(encoded_certificate)?;
98105
let client_builder = certificate_list
@@ -106,6 +113,31 @@ pub fn create_client(
106113
.change_context(ApiClientError::ClientConstructionFailed)
107114
.attach_printable("Failed to construct client with certificate and certificate key")
108115
}
116+
(
117+
Some(VerificationType::Mtls),
118+
Some(encoded_certificate),
119+
Some(encoded_certificate_key),
120+
) => {
121+
let client_builder = get_client_builder(proxy_config, should_bypass_proxy)?;
122+
123+
let identity = payments::helpers::create_identity_from_certificate_and_key(
124+
encoded_certificate.clone(),
125+
encoded_certificate_key,
126+
true,
127+
)?;
128+
let certificate_list = payments::helpers::create_certificate(encoded_certificate)?;
129+
let client_builder = certificate_list
130+
.into_iter()
131+
.fold(client_builder, |client_builder, certificate| {
132+
client_builder.add_root_certificate(certificate)
133+
});
134+
client_builder
135+
.identity(identity)
136+
.use_rustls_tls()
137+
.build()
138+
.change_context(ApiClientError::ClientConstructionFailed)
139+
.attach_printable("Failed to construct client with certificate and certificate key")
140+
}
109141
_ => get_base_client(proxy_config, should_bypass_proxy),
110142
}
111143
}
@@ -248,6 +280,7 @@ impl ProxyClient {
248280
let identity = payments::helpers::create_identity_from_certificate_and_key(
249281
certificate,
250282
certificate_key,
283+
false,
251284
)?;
252285
Ok(client_builder
253286
.identity(identity)

0 commit comments

Comments
 (0)