mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
refactor(router): Refactored Authentication (#327)
This commit is contained in:
@ -8,7 +8,7 @@ use crate::{
|
||||
compatibility::{stripe::errors, wrap},
|
||||
core::customers,
|
||||
routes,
|
||||
services::api,
|
||||
services::{api, authentication as auth},
|
||||
types::api::customers as customer_types,
|
||||
};
|
||||
|
||||
@ -44,7 +44,7 @@ pub async fn customer_create(
|
||||
|state, merchant_account, req| {
|
||||
customers::create_customer(&*state.store, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -75,7 +75,7 @@ pub async fn customer_retrieve(
|
||||
|state, merchant_account, req| {
|
||||
customers::retrieve_customer(&*state.store, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -115,7 +115,7 @@ pub async fn customer_update(
|
||||
|state, merchant_account, req| {
|
||||
customers::update_customer(&*state.store, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -144,7 +144,7 @@ pub async fn customer_delete(
|
||||
&req,
|
||||
payload,
|
||||
customers::delete_customer,
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
compatibility::{stripe::errors, wrap},
|
||||
core::payments,
|
||||
routes,
|
||||
services::api,
|
||||
services::{api, authentication as auth},
|
||||
types::api::{self as api_types},
|
||||
};
|
||||
|
||||
@ -58,7 +58,7 @@ pub async fn payment_intents_create(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -78,11 +78,10 @@ pub async fn payment_intents_retrieve(
|
||||
param: None,
|
||||
};
|
||||
|
||||
let auth_type = match api::get_auth_type(&req) {
|
||||
Ok(auth_type) => auth_type,
|
||||
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(report!(err)),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
@ -107,7 +106,7 @@ pub async fn payment_intents_retrieve(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -138,12 +137,11 @@ pub async fn payment_intents_update(
|
||||
|
||||
payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(payment_id));
|
||||
|
||||
let auth_type;
|
||||
(payload, auth_type) = match api::get_auth_type_and_check_client_secret(&req, payload) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(report!(err)),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
_,
|
||||
@ -168,7 +166,7 @@ pub async fn payment_intents_update(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -200,12 +198,12 @@ pub async fn payment_intents_confirm(
|
||||
payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(payment_id));
|
||||
payload.confirm = Some(true);
|
||||
|
||||
let auth_type;
|
||||
(payload, auth_type) = match api::get_auth_type_and_check_client_secret(&req, payload) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
let (auth_type, auth_flow) =
|
||||
match auth::check_client_secret_and_get_auth(req.headers(), &payload) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
_,
|
||||
@ -230,7 +228,7 @@ pub async fn payment_intents_confirm(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -280,7 +278,7 @@ pub async fn payment_intents_capture(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -307,11 +305,11 @@ pub async fn payment_intents_cancel(
|
||||
let mut payload: payment_types::PaymentsCancelRequest = stripe_payload.into();
|
||||
payload.payment_id = payment_id;
|
||||
|
||||
let auth_type = match api::get_auth_type(&req) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(report!(err)),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
_,
|
||||
@ -335,7 +333,7 @@ pub async fn payment_intents_cancel(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -366,7 +364,7 @@ pub async fn payment_intent_list(
|
||||
|state, merchant_account, req| {
|
||||
payments::list_payments(&*state.store, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ use crate::{
|
||||
compatibility::{stripe::errors, wrap},
|
||||
core::refunds,
|
||||
routes,
|
||||
services::api,
|
||||
services::authentication as auth,
|
||||
types::api::refunds as refund_types,
|
||||
};
|
||||
|
||||
@ -34,7 +34,7 @@ pub async fn refund_create(
|
||||
&req,
|
||||
create_refund_req,
|
||||
refunds::refund_create_core,
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -67,7 +67,7 @@ pub async fn refund_retrieve(
|
||||
refunds::refund_retrieve_core,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -99,7 +99,7 @@ pub async fn refund_update(
|
||||
|state, merchant_account, req| {
|
||||
refunds::refund_update_core(&*state.store, merchant_account, &refund_id, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
compatibility::{stripe::errors, wrap},
|
||||
core::payments,
|
||||
routes,
|
||||
services::api,
|
||||
services::{api, authentication as auth},
|
||||
types::api as api_types,
|
||||
};
|
||||
|
||||
@ -55,7 +55,7 @@ pub async fn setup_intents_create(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -75,11 +75,10 @@ pub async fn setup_intents_retrieve(
|
||||
param: None,
|
||||
};
|
||||
|
||||
let auth_type = match api::get_auth_type(&req) {
|
||||
Ok(auth_type) => auth_type,
|
||||
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(report!(err)),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
@ -104,7 +103,7 @@ pub async fn setup_intents_retrieve(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -131,12 +130,12 @@ pub async fn setup_intents_update(
|
||||
let mut payload: payment_types::PaymentsRequest = stripe_payload.into();
|
||||
payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));
|
||||
|
||||
let auth_type;
|
||||
(payload, auth_type) = match api::get_auth_type_and_check_client_secret(&req, payload) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
let (auth_type, auth_flow) =
|
||||
match auth::check_client_secret_and_get_auth(req.headers(), &payload) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
_,
|
||||
@ -161,7 +160,7 @@ pub async fn setup_intents_update(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -189,12 +188,12 @@ pub async fn setup_intents_confirm(
|
||||
payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));
|
||||
payload.confirm = Some(true);
|
||||
|
||||
let auth_type;
|
||||
(payload, auth_type) = match api::get_auth_type_and_check_client_secret(&req, payload) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
let (auth_type, auth_flow) =
|
||||
match auth::check_client_secret_and_get_auth(req.headers(), &payload) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
wrap::compatibility_api_wrap::<
|
||||
_,
|
||||
_,
|
||||
@ -219,7 +218,7 @@ pub async fn setup_intents_confirm(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -8,28 +8,25 @@ use serde::Serialize;
|
||||
use crate::{
|
||||
core::errors::{self, RouterResult},
|
||||
routes,
|
||||
services::{api, logger},
|
||||
types::storage,
|
||||
services::{api, authentication as auth, logger},
|
||||
};
|
||||
|
||||
#[instrument(skip(request, payload, state, func))]
|
||||
pub async fn compatibility_api_wrap<'a, 'b, A, T, Q, F, Fut, S, E>(
|
||||
#[instrument(skip(request, payload, state, func, api_authentication))]
|
||||
pub async fn compatibility_api_wrap<'a, 'b, U, T, Q, F, Fut, S, E>(
|
||||
state: &'b routes::AppState,
|
||||
request: &'a HttpRequest,
|
||||
payload: T,
|
||||
func: F,
|
||||
api_authentication: A,
|
||||
api_authentication: &dyn auth::AuthenticateAndFetch<U>,
|
||||
) -> HttpResponse
|
||||
where
|
||||
A: Into<api::ApiAuthentication<'a>> + std::fmt::Debug,
|
||||
F: Fn(&'b routes::AppState, storage::MerchantAccount, T) -> Fut,
|
||||
F: Fn(&'b routes::AppState, U, T) -> Fut,
|
||||
Fut: Future<Output = RouterResult<api::BachResponse<Q>>>,
|
||||
Q: Serialize + std::fmt::Debug + 'a,
|
||||
S: From<Q> + Serialize,
|
||||
E: From<errors::ApiErrorResponse> + Serialize + error_stack::Context + actix_web::ResponseError,
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
let api_authentication = api_authentication.into();
|
||||
let resp = api::server_wrap_util(state, request, payload, func, api_authentication).await;
|
||||
match resp {
|
||||
Ok(api::BachResponse::Json(router_resp)) => {
|
||||
|
||||
@ -593,37 +593,6 @@ pub(crate) async fn call_payment_method(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn client_secret_auth<P>(
|
||||
payload: P,
|
||||
auth_type: &services::api::MerchantAuthentication<'_>,
|
||||
) -> RouterResult<P>
|
||||
where
|
||||
P: services::Authenticate,
|
||||
{
|
||||
match auth_type {
|
||||
services::MerchantAuthentication::PublishableKey => {
|
||||
payload
|
||||
.get_client_secret()
|
||||
.check_value_present("client_secret")
|
||||
.change_context(errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "client_secret".to_owned(),
|
||||
})?;
|
||||
Ok(payload)
|
||||
}
|
||||
services::api::MerchantAuthentication::ApiKey => {
|
||||
if payload.get_client_secret().is_some() {
|
||||
Err(report!(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "client_secret is not a valid parameter".to_owned(),
|
||||
}))
|
||||
} else {
|
||||
Ok(payload)
|
||||
}
|
||||
}
|
||||
_ => Err(report!(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Unexpected Auth type")),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_customer_from_details(
|
||||
db: &dyn StorageInterface,
|
||||
customer_id: Option<String>,
|
||||
|
||||
@ -2,7 +2,11 @@ use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
|
||||
use super::app::AppState;
|
||||
use crate::{core::admin::*, services::api, types::api::admin};
|
||||
use crate::{
|
||||
core::admin::*,
|
||||
services::{api, authentication as auth},
|
||||
types::api::admin,
|
||||
};
|
||||
|
||||
/// Merchant Account - Create
|
||||
///
|
||||
@ -28,7 +32,7 @@ pub async fn merchant_account_create(
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req| create_merchant_account(&*state.store, req),
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -49,7 +53,7 @@ pub async fn retrieve_merchant_account(
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req| get_merchant_account(&*state.store, req),
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -68,7 +72,7 @@ pub async fn update_merchant_account(
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req| merchant_account_update(&*state.store, &merchant_id, req),
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -89,7 +93,7 @@ pub async fn delete_merchant_account(
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req| merchant_account_delete(&*state.store, req.merchant_id),
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -109,7 +113,7 @@ pub async fn payment_connector_create(
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req| create_payment_connector(&*state.store, req, &merchant_id),
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -134,7 +138,7 @@ pub async fn payment_connector_retrieve(
|
||||
|state, _, req| {
|
||||
retrieve_payment_connector(&*state.store, req.merchant_id, req.merchant_connector_id)
|
||||
},
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -152,7 +156,7 @@ pub async fn payment_connector_list(
|
||||
&req,
|
||||
merchant_id,
|
||||
|state, _, merchant_id| list_payment_connectors(&*state.store, merchant_id),
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -173,7 +177,7 @@ pub async fn payment_connector_update(
|
||||
|state, _, req| {
|
||||
update_payment_connector(&*state.store, &merchant_id, merchant_connector_id, req)
|
||||
},
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -198,7 +202,7 @@ pub async fn payment_connector_delete(
|
||||
|state, _, req| {
|
||||
delete_payment_connector(&*state.store, req.merchant_id, req.merchant_connector_id)
|
||||
},
|
||||
api::MerchantAuthentication::AdminApiKey,
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use router_env::{instrument, tracing, Flow};
|
||||
use super::app::AppState;
|
||||
use crate::{
|
||||
core::customers::*,
|
||||
services::{self, api},
|
||||
services::{api, authentication as auth},
|
||||
types::api::customers,
|
||||
};
|
||||
|
||||
@ -20,7 +20,7 @@ pub async fn customers_create(
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, merchant_account, req| create_customer(&*state.store, merchant_account, req),
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -36,22 +36,19 @@ pub async fn customers_retrieve(
|
||||
customer_id: path.into_inner(),
|
||||
})
|
||||
.into_inner();
|
||||
let auth_type = match services::authenticate_eph_key(
|
||||
&req,
|
||||
&*state.store,
|
||||
payload.customer_id.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(auth_type) => auth_type,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
let auth =
|
||||
match auth::is_ephemeral_auth(req.headers(), &*state.store, &payload.customer_id).await {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
api::server_wrap(
|
||||
&state,
|
||||
&req,
|
||||
payload,
|
||||
|state, merchant_account, req| retrieve_customer(&*state.store, merchant_account, req),
|
||||
auth_type,
|
||||
&*auth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -71,7 +68,7 @@ pub async fn customers_update(
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, merchant_account, req| update_customer(&*state.store, merchant_account, req),
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -87,14 +84,7 @@ pub async fn customers_delete(
|
||||
customer_id: path.into_inner(),
|
||||
})
|
||||
.into_inner();
|
||||
api::server_wrap(
|
||||
&state,
|
||||
&req,
|
||||
payload,
|
||||
delete_customer,
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
)
|
||||
.await
|
||||
api::server_wrap(&state, &req, payload, delete_customer, &auth::ApiKeyAuth).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::CustomersGetMandates))]
|
||||
@ -115,7 +105,7 @@ pub async fn get_customer_mandates(
|
||||
|state, merchant_account, req| {
|
||||
crate::core::mandate::get_customer_mandates(state, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -2,7 +2,11 @@ use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
|
||||
use super::AppState;
|
||||
use crate::{core::payments::helpers, services::api, types::api::customers};
|
||||
use crate::{
|
||||
core::payments::helpers,
|
||||
services::{api, authentication as auth},
|
||||
types::api::customers,
|
||||
};
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::EphemeralKeyCreate))]
|
||||
pub async fn ephemeral_key_create(
|
||||
@ -18,7 +22,7 @@ pub async fn ephemeral_key_create(
|
||||
|state, merchant_account, req| {
|
||||
helpers::make_ephemeral_key(state, req.customer_id, merchant_account.merchant_id)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -35,7 +39,7 @@ pub async fn ephemeral_key_delete(
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req| helpers::delete_ephemeral_key(&*state.store, req),
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -2,7 +2,11 @@ use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
|
||||
use super::app::AppState;
|
||||
use crate::{core::mandate, services::api, types::api::mandates};
|
||||
use crate::{
|
||||
core::mandate,
|
||||
services::{api, authentication as auth},
|
||||
types::api::mandates,
|
||||
};
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::MandatesRetrieve))]
|
||||
// #[get("/{id}")]
|
||||
@ -19,7 +23,7 @@ pub async fn get_mandate(
|
||||
&req,
|
||||
mandate_id,
|
||||
mandate::get_mandate,
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -41,7 +45,7 @@ pub async fn revoke_mandate(
|
||||
|state, merchant_account, req| {
|
||||
mandate::revoke_mandate(&*state.store, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -4,8 +4,7 @@ use router_env::{instrument, tracing, Flow};
|
||||
use super::app::AppState;
|
||||
use crate::{
|
||||
core::payment_methods::cards,
|
||||
services,
|
||||
services::api,
|
||||
services::{api, authentication as auth},
|
||||
types::api::payment_methods::{self, PaymentMethodId},
|
||||
};
|
||||
|
||||
@ -23,7 +22,7 @@ pub async fn create_payment_method_api(
|
||||
|state, merchant_account, req| async move {
|
||||
cards::add_payment_method(state, req, &merchant_account).await
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -36,12 +35,12 @@ pub async fn list_payment_method_api(
|
||||
_merchant_id: web::Path<String>,
|
||||
json_payload: web::Query<payment_methods::ListPaymentMethodRequest>,
|
||||
) -> HttpResponse {
|
||||
//let merchant_id = merchant_id.into_inner();
|
||||
let (payload, auth_type) =
|
||||
match api::get_auth_type_and_check_client_secret(&req, json_payload.into_inner()) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
let payload = json_payload.into_inner();
|
||||
|
||||
let (auth, _) = match auth::check_client_secret_and_get_auth(req.headers(), &payload) {
|
||||
Ok((auth, _auth_flow)) => (auth, _auth_flow),
|
||||
Err(e) => return api::log_and_return_error_response(e),
|
||||
};
|
||||
|
||||
api::server_wrap(
|
||||
&state,
|
||||
@ -50,7 +49,7 @@ pub async fn list_payment_method_api(
|
||||
|state, merchant_account, req| {
|
||||
cards::list_payment_methods(&*state.store, merchant_account, req)
|
||||
},
|
||||
auth_type,
|
||||
&*auth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -65,11 +64,11 @@ pub async fn list_customer_payment_method_api(
|
||||
) -> HttpResponse {
|
||||
let customer_id = customer_id.into_inner().0;
|
||||
|
||||
let auth_type =
|
||||
match services::authenticate_eph_key(&req, &*state.store, customer_id.clone()).await {
|
||||
Ok(auth_type) => auth_type,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
let auth_type = match auth::is_ephemeral_auth(req.headers(), &*state.store, &customer_id).await
|
||||
{
|
||||
Ok(auth_type) => auth_type,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
|
||||
api::server_wrap(
|
||||
&state,
|
||||
@ -78,7 +77,7 @@ pub async fn list_customer_payment_method_api(
|
||||
|state, merchant_account, _| {
|
||||
cards::list_customer_payment_method(state, merchant_account, &customer_id)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -100,7 +99,7 @@ pub async fn payment_method_retrieve_api(
|
||||
&req,
|
||||
payload,
|
||||
|state, merchant_account, pm| cards::retrieve_payment_method(state, pm, merchant_account),
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -126,7 +125,7 @@ pub async fn payment_method_update_api(
|
||||
&payment_method_id,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -146,7 +145,7 @@ pub async fn payment_method_delete_api(
|
||||
&req,
|
||||
pm,
|
||||
cards::delete_payment_method,
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use actix_web::{web, Responder};
|
||||
use error_stack::report;
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
@ -7,7 +5,7 @@ use router_env::{instrument, tracing, Flow};
|
||||
use crate::{
|
||||
self as app,
|
||||
core::{errors::http_not_implemented, payments},
|
||||
services::api,
|
||||
services::{api, authentication as auth},
|
||||
types::api::{self as api_types, enums as api_enums, payments as payment_types},
|
||||
};
|
||||
|
||||
@ -37,7 +35,7 @@ pub async fn payments_create(
|
||||
api::AuthFlow::Merchant,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -69,7 +67,7 @@ pub async fn payments_start(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::MerchantId(Cow::Borrowed(&merchant_id)),
|
||||
&auth::MerchantIdAuth(merchant_id),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -89,11 +87,10 @@ pub async fn payments_retrieve(
|
||||
param: None,
|
||||
connector: None,
|
||||
};
|
||||
let auth_type = match api::get_auth_type(&req) {
|
||||
Ok(auth_type) => auth_type,
|
||||
let (auth_type, _auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(report!(err)),
|
||||
};
|
||||
let _auth_flow = api::get_auth_flow(&auth_type);
|
||||
|
||||
api::server_wrap(
|
||||
&state,
|
||||
@ -110,7 +107,7 @@ pub async fn payments_retrieve(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -133,14 +130,11 @@ pub async fn payments_update(
|
||||
|
||||
payload.payment_id = Some(payment_types::PaymentIdType::PaymentIntentId(payment_id));
|
||||
|
||||
let auth_type;
|
||||
(payload, auth_type) = match api::get_auth_type_and_check_client_secret(&req, payload) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
|
||||
Ok(auth) => auth,
|
||||
Err(err) => return api::log_and_return_error_response(report!(err)),
|
||||
};
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
|
||||
// return http_not_implemented();
|
||||
api::server_wrap(
|
||||
&state,
|
||||
&req,
|
||||
@ -154,7 +148,7 @@ pub async fn payments_update(
|
||||
auth_flow,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -177,13 +171,12 @@ pub async fn payments_confirm(
|
||||
payload.payment_id = Some(payment_types::PaymentIdType::PaymentIntentId(payment_id));
|
||||
payload.confirm = Some(true);
|
||||
|
||||
let auth_type;
|
||||
(payload, auth_type) = match api::get_auth_type_and_check_client_secret(&req, payload) {
|
||||
Ok(values) => values,
|
||||
Err(err) => return api::log_and_return_error_response(err),
|
||||
};
|
||||
let (auth_type, auth_flow) =
|
||||
match auth::check_client_secret_and_get_auth(req.headers(), &payload) {
|
||||
Ok(auth) => auth,
|
||||
Err(e) => return api::log_and_return_error_response(e),
|
||||
};
|
||||
|
||||
let auth_flow = api::get_auth_flow(&auth_type);
|
||||
api::server_wrap(
|
||||
&state,
|
||||
&req,
|
||||
@ -197,7 +190,7 @@ pub async fn payments_confirm(
|
||||
auth_flow,
|
||||
)
|
||||
},
|
||||
auth_type,
|
||||
&*auth_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -230,7 +223,7 @@ pub async fn payments_capture(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -264,7 +257,7 @@ pub async fn payments_connector_session(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::PublishableKey,
|
||||
&auth::PublishableKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -296,7 +289,7 @@ pub async fn payments_response(
|
||||
req,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::MerchantId(Cow::Borrowed(&merchant_id)),
|
||||
&auth::MerchantIdAuth(merchant_id),
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -328,7 +321,7 @@ pub async fn payments_cancel(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -348,7 +341,7 @@ pub async fn payments_list(
|
||||
|state, merchant_account, req| {
|
||||
payments::list_payments(&*state.store, merchant_account, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -2,7 +2,11 @@ use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
|
||||
use super::app::AppState;
|
||||
use crate::{core::refunds::*, services::api, types::api::refunds};
|
||||
use crate::{
|
||||
core::refunds::*,
|
||||
services::{api, authentication as auth},
|
||||
types::api::refunds,
|
||||
};
|
||||
|
||||
/// Refunds - Create
|
||||
///
|
||||
@ -28,7 +32,7 @@ pub async fn refunds_create(
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
refund_create_core,
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -49,7 +53,7 @@ pub async fn refunds_retrieve(
|
||||
|state, merchant_account, refund_id| {
|
||||
refund_response_wrapper(state, merchant_account, refund_id, refund_retrieve_core)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -70,7 +74,7 @@ pub async fn refunds_update(
|
||||
|state, merchant_account, req| {
|
||||
refund_update_core(&*state.store, merchant_account, &refund_id, req)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -87,7 +91,7 @@ pub async fn refunds_list(
|
||||
&req,
|
||||
payload.into_inner(),
|
||||
|state, merchant_account, req| refund_list(&*state.store, merchant_account, req),
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -2,7 +2,10 @@ use actix_web::{web, HttpRequest, Responder};
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
|
||||
use super::app::AppState;
|
||||
use crate::{core::webhooks, services::api};
|
||||
use crate::{
|
||||
core::webhooks,
|
||||
services::{api, authentication as auth},
|
||||
};
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::IncomingWebhookReceive))]
|
||||
pub async fn receive_incoming_webhook(
|
||||
@ -20,7 +23,7 @@ pub async fn receive_incoming_webhook(
|
||||
|state, merchant_account, body| {
|
||||
webhooks::webhooks_core(state, &req, merchant_account, &connector_name, body)
|
||||
},
|
||||
api::ConnectorAuthentication::MerchantId(&merchant_id),
|
||||
&auth::MerchantIdAuth(merchant_id),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod api;
|
||||
pub mod authentication;
|
||||
pub mod encryption;
|
||||
pub mod logger;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
mod client;
|
||||
pub(crate) mod request;
|
||||
|
||||
use std::{borrow::Cow, collections::HashMap, fmt::Debug, future::Future, str, time::Instant};
|
||||
use std::{collections::HashMap, fmt::Debug, future::Future, str, time::Instant};
|
||||
|
||||
use actix_web::{body, HttpRequest, HttpResponse, Responder};
|
||||
use bytes::Bytes;
|
||||
@ -15,18 +15,18 @@ pub use self::request::{Method, Request, RequestBuilder};
|
||||
use crate::{
|
||||
configs::settings::Connectors,
|
||||
core::{
|
||||
errors::{self, CustomResult, RouterResponse, RouterResult, StorageErrorExt},
|
||||
errors::{self, CustomResult, RouterResponse, RouterResult},
|
||||
payments,
|
||||
},
|
||||
db::StorageInterface,
|
||||
logger,
|
||||
routes::AppState,
|
||||
services::authentication as auth,
|
||||
types::{
|
||||
self, api,
|
||||
storage::{self, enums},
|
||||
storage::{self},
|
||||
ErrorResponse,
|
||||
},
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
|
||||
pub type BoxedConnectorIntegration<'a, T, Req, Resp> =
|
||||
@ -363,104 +363,49 @@ impl RedirectForm {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ApiAuthentication<'a> {
|
||||
Merchant(MerchantAuthentication<'a>),
|
||||
Connector(ConnectorAuthentication<'a>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum MerchantAuthentication<'a> {
|
||||
ApiKey,
|
||||
MerchantId(Cow<'a, str>),
|
||||
AdminApiKey,
|
||||
PublishableKey,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConnectorAuthentication<'a> {
|
||||
MerchantId(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> From<MerchantAuthentication<'a>> for ApiAuthentication<'a> {
|
||||
fn from(merchant_auth: MerchantAuthentication<'a>) -> Self {
|
||||
ApiAuthentication::Merchant(merchant_auth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ConnectorAuthentication<'a>> for ApiAuthentication<'a> {
|
||||
fn from(connector_auth: ConnectorAuthentication<'a>) -> Self {
|
||||
ApiAuthentication::Connector(connector_auth)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AuthFlow {
|
||||
Client,
|
||||
Merchant,
|
||||
}
|
||||
|
||||
pub fn get_auth_flow(auth_type: &MerchantAuthentication<'_>) -> AuthFlow {
|
||||
match auth_type {
|
||||
MerchantAuthentication::ApiKey => AuthFlow::Merchant,
|
||||
_ => AuthFlow::Client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_auth_type(request: &HttpRequest) -> RouterResult<MerchantAuthentication<'_>> {
|
||||
let api_key = get_api_key(request).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
if api_key.starts_with("pk_") {
|
||||
Ok(MerchantAuthentication::PublishableKey)
|
||||
} else {
|
||||
Ok(MerchantAuthentication::ApiKey)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(request, payload, state, func))]
|
||||
pub async fn server_wrap_util<'a, 'b, T, Q, F, Fut>(
|
||||
#[instrument(skip(request, payload, state, func, api_auth))]
|
||||
pub async fn server_wrap_util<'a, 'b, U, T, Q, F, Fut>(
|
||||
state: &'b AppState,
|
||||
request: &'a HttpRequest,
|
||||
payload: T,
|
||||
func: F,
|
||||
api_authentication: ApiAuthentication<'a>,
|
||||
api_auth: &dyn auth::AuthenticateAndFetch<U>,
|
||||
) -> RouterResult<BachResponse<Q>>
|
||||
where
|
||||
F: Fn(&'b AppState, storage::MerchantAccount, T) -> Fut,
|
||||
F: Fn(&'b AppState, U, T) -> Fut,
|
||||
Fut: Future<Output = RouterResponse<Q>>,
|
||||
Q: Serialize + Debug + 'a,
|
||||
T: Debug,
|
||||
{
|
||||
let merchant_account = match api_authentication {
|
||||
ApiAuthentication::Merchant(merchant_auth) => {
|
||||
authenticate_merchant(request, state, merchant_auth).await?
|
||||
}
|
||||
ApiAuthentication::Connector(connector_auth) => {
|
||||
authenticate_connector(request, &*state.store, connector_auth).await?
|
||||
}
|
||||
};
|
||||
logger::debug!(request=?payload);
|
||||
func(state, merchant_account, payload).await
|
||||
let auth_out = api_auth
|
||||
.authenticate_and_fetch(request.headers(), state)
|
||||
.await?;
|
||||
func(state, auth_out, payload).await
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
skip(request, payload, state, func),
|
||||
skip(request, payload, state, func, api_auth),
|
||||
fields(request_method, request_url_path)
|
||||
)]
|
||||
pub async fn server_wrap<'a, 'b, A, T, Q, F, Fut>(
|
||||
pub async fn server_wrap<'a, 'b, T, U, Q, F, Fut>(
|
||||
state: &'b AppState,
|
||||
request: &'a HttpRequest,
|
||||
payload: T,
|
||||
func: F,
|
||||
api_authentication: A,
|
||||
api_auth: &dyn auth::AuthenticateAndFetch<U>,
|
||||
) -> HttpResponse
|
||||
where
|
||||
A: Into<ApiAuthentication<'a>> + Debug,
|
||||
F: Fn(&'b AppState, storage::MerchantAccount, T) -> Fut,
|
||||
F: Fn(&'b AppState, U, T) -> Fut,
|
||||
Fut: Future<Output = RouterResult<BachResponse<Q>>>,
|
||||
Q: Serialize + Debug + 'a,
|
||||
T: Debug,
|
||||
{
|
||||
let api_authentication = api_authentication.into();
|
||||
let request_method = request.method().as_str();
|
||||
let url_path = request.path();
|
||||
tracing::Span::current().record("request_method", request_method);
|
||||
@ -469,7 +414,7 @@ where
|
||||
let start_instant = Instant::now();
|
||||
logger::info!(tag = ?Tag::BeginRequest);
|
||||
|
||||
let res = match server_wrap_util(state, request, payload, func, api_authentication).await {
|
||||
let res = match server_wrap_util(state, request, payload, func, api_auth).await {
|
||||
Ok(BachResponse::Json(response)) => match serde_json::to_string(&response) {
|
||||
Ok(res) => http_response_json(res),
|
||||
Err(_) => http_response_err(
|
||||
@ -519,120 +464,6 @@ where
|
||||
error.current_context().error_response()
|
||||
}
|
||||
|
||||
pub async fn authenticate_merchant<'a>(
|
||||
request: &HttpRequest,
|
||||
state: &AppState,
|
||||
merchant_authentication: MerchantAuthentication<'a>,
|
||||
) -> RouterResult<storage::MerchantAccount> {
|
||||
match merchant_authentication {
|
||||
MerchantAuthentication::ApiKey => {
|
||||
let api_key =
|
||||
get_api_key(request).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
authenticate_by_api_key(&*state.store, api_key).await
|
||||
}
|
||||
|
||||
MerchantAuthentication::MerchantId(merchant_id) => (*state.store)
|
||||
.find_merchant_account_by_merchant_id(&merchant_id)
|
||||
.await
|
||||
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::Unauthorized)),
|
||||
|
||||
MerchantAuthentication::AdminApiKey => {
|
||||
let admin_api_key =
|
||||
get_api_key(request).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
utils::when(admin_api_key != state.conf.keys.admin_api_key, || {
|
||||
Err(errors::ApiErrorResponse::Unauthorized)
|
||||
.into_report()
|
||||
.attach_printable("Admin Authentication Failure")
|
||||
})?;
|
||||
|
||||
Ok(storage::MerchantAccount {
|
||||
id: -1,
|
||||
merchant_id: String::from("juspay"),
|
||||
merchant_name: None,
|
||||
api_key: None,
|
||||
merchant_details: None,
|
||||
return_url: None,
|
||||
webhook_details: None,
|
||||
routing_algorithm: None,
|
||||
custom_routing_rules: None,
|
||||
sub_merchants_enabled: None,
|
||||
parent_merchant_id: None,
|
||||
enable_payment_response_hash: false,
|
||||
payment_response_hash_key: None,
|
||||
redirect_to_merchant_with_http_post: false,
|
||||
publishable_key: None,
|
||||
storage_scheme: enums::MerchantStorageScheme::PostgresOnly,
|
||||
locker_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
MerchantAuthentication::PublishableKey => {
|
||||
let api_key =
|
||||
get_api_key(request).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
authenticate_by_publishable_key(&*state.store, api_key).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn authenticate_connector<'a>(
|
||||
_request: &HttpRequest,
|
||||
store: &dyn StorageInterface,
|
||||
connector_authentication: ConnectorAuthentication<'a>,
|
||||
) -> RouterResult<storage::MerchantAccount> {
|
||||
match connector_authentication {
|
||||
ConnectorAuthentication::MerchantId(merchant_id) => store
|
||||
.find_merchant_account_by_merchant_id(merchant_id)
|
||||
.await
|
||||
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::Unauthorized)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_auth_type_and_check_client_secret<P>(
|
||||
req: &HttpRequest,
|
||||
payload: P,
|
||||
) -> RouterResult<(P, MerchantAuthentication<'_>)>
|
||||
where
|
||||
P: Authenticate,
|
||||
{
|
||||
let auth_type = get_auth_type(req)?;
|
||||
Ok((
|
||||
payments::helpers::client_secret_auth(payload, &auth_type)?,
|
||||
auth_type,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn authenticate_eph_key<'a>(
|
||||
req: &'a HttpRequest,
|
||||
store: &dyn StorageInterface,
|
||||
customer_id: String,
|
||||
) -> RouterResult<MerchantAuthentication<'a>> {
|
||||
let api_key = get_api_key(req)?;
|
||||
if api_key.starts_with("epk") {
|
||||
let ek = store
|
||||
.get_ephemeral_key(api_key)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
utils::when(ek.customer_id.ne(&customer_id), || {
|
||||
Err(report!(errors::ApiErrorResponse::InvalidEphermeralKey))
|
||||
})?;
|
||||
Ok(MerchantAuthentication::MerchantId(Cow::Owned(
|
||||
ek.merchant_id,
|
||||
)))
|
||||
} else {
|
||||
Ok(MerchantAuthentication::ApiKey)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_api_key(req: &HttpRequest) -> RouterResult<&str> {
|
||||
req.headers()
|
||||
.get("api-key")
|
||||
.get_required_value("api-key")?
|
||||
.to_str()
|
||||
.into_report()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to convert API key to string")
|
||||
}
|
||||
|
||||
pub async fn authenticate_by_api_key(
|
||||
store: &dyn StorageInterface,
|
||||
api_key: &str,
|
||||
@ -644,17 +475,6 @@ pub async fn authenticate_by_api_key(
|
||||
.attach_printable("Merchant not authenticated")
|
||||
}
|
||||
|
||||
async fn authenticate_by_publishable_key(
|
||||
store: &dyn StorageInterface,
|
||||
publishable_key: &str,
|
||||
) -> RouterResult<storage::MerchantAccount> {
|
||||
store
|
||||
.find_merchant_account_by_publishable_key(publishable_key)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||
.attach_printable("Merchant not authenticated")
|
||||
}
|
||||
|
||||
pub fn http_response_json<T: body::MessageBody + 'static>(response: T) -> HttpResponse {
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
|
||||
194
crates/router/src/services/authentication.rs
Normal file
194
crates/router/src/services/authentication.rs
Normal file
@ -0,0 +1,194 @@
|
||||
use actix_web::http::header::HeaderMap;
|
||||
use api_models::{payment_methods::ListPaymentMethodRequest, payments::PaymentsRequest};
|
||||
use async_trait::async_trait;
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
|
||||
use crate::{
|
||||
core::errors::{self, RouterResult, StorageErrorExt},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services::api,
|
||||
types::storage,
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait AuthenticateAndFetch<T> {
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &AppState,
|
||||
) -> RouterResult<T>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiKeyAuth;
|
||||
|
||||
#[async_trait]
|
||||
impl AuthenticateAndFetch<storage::MerchantAccount> for ApiKeyAuth {
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &AppState,
|
||||
) -> RouterResult<storage::MerchantAccount> {
|
||||
let api_key =
|
||||
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
state
|
||||
.store
|
||||
.find_merchant_account_by_api_key(api_key)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||
.attach_printable("Merchant not authenticated")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AdminApiAuth;
|
||||
|
||||
#[async_trait]
|
||||
impl AuthenticateAndFetch<()> for AdminApiAuth {
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &AppState,
|
||||
) -> RouterResult<()> {
|
||||
let admin_api_key =
|
||||
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
if admin_api_key != state.conf.keys.admin_api_key {
|
||||
Err(report!(errors::ApiErrorResponse::Unauthorized)
|
||||
.attach_printable("Admin Authentication Failure"))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MerchantIdAuth(pub String);
|
||||
|
||||
#[async_trait]
|
||||
impl AuthenticateAndFetch<storage::MerchantAccount> for MerchantIdAuth {
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
_request_headers: &HeaderMap,
|
||||
state: &AppState,
|
||||
) -> RouterResult<storage::MerchantAccount> {
|
||||
state
|
||||
.store
|
||||
.find_merchant_account_by_merchant_id(self.0.as_ref())
|
||||
.await
|
||||
.map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::Unauthorized))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PublishableKeyAuth;
|
||||
|
||||
#[async_trait]
|
||||
impl AuthenticateAndFetch<storage::MerchantAccount> for PublishableKeyAuth {
|
||||
async fn authenticate_and_fetch(
|
||||
&self,
|
||||
request_headers: &HeaderMap,
|
||||
state: &AppState,
|
||||
) -> RouterResult<storage::MerchantAccount> {
|
||||
let publishable_key =
|
||||
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
state
|
||||
.store
|
||||
.find_merchant_account_by_publishable_key(publishable_key)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::Unauthorized)
|
||||
.attach_printable("Merchant not authenticated")
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ClientSecretFetch {
|
||||
fn get_client_secret(&self) -> Option<&String>;
|
||||
}
|
||||
|
||||
impl ClientSecretFetch for PaymentsRequest {
|
||||
fn get_client_secret(&self) -> Option<&String> {
|
||||
self.client_secret.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientSecretFetch for ListPaymentMethodRequest {
|
||||
fn get_client_secret(&self) -> Option<&String> {
|
||||
self.client_secret.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_auth_type_and_flow(
|
||||
headers: &HeaderMap,
|
||||
) -> RouterResult<(
|
||||
Box<dyn AuthenticateAndFetch<storage::MerchantAccount>>,
|
||||
api::AuthFlow,
|
||||
)> {
|
||||
let api_key = get_api_key(headers)?;
|
||||
|
||||
if api_key.starts_with("pk_") {
|
||||
return Ok((Box::new(PublishableKeyAuth), api::AuthFlow::Client));
|
||||
}
|
||||
Ok((Box::new(PublishableKeyAuth), api::AuthFlow::Merchant))
|
||||
}
|
||||
|
||||
pub fn check_client_secret_and_get_auth(
|
||||
headers: &HeaderMap,
|
||||
payload: &impl ClientSecretFetch,
|
||||
) -> RouterResult<(
|
||||
Box<dyn AuthenticateAndFetch<storage::MerchantAccount>>,
|
||||
api::AuthFlow,
|
||||
)> {
|
||||
let api_key = get_api_key(headers)?;
|
||||
|
||||
if api_key.starts_with("pk_") {
|
||||
payload
|
||||
.get_client_secret()
|
||||
.check_value_present("client_secret")
|
||||
.map_err(|_| errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "client_secret".to_owned(),
|
||||
})?;
|
||||
return Ok((Box::new(PublishableKeyAuth), api::AuthFlow::Client));
|
||||
}
|
||||
|
||||
if payload.get_client_secret().is_some() {
|
||||
return Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "client_secret is not a valid parameter".to_owned(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok((Box::new(ApiKeyAuth), api::AuthFlow::Merchant))
|
||||
}
|
||||
|
||||
pub async fn is_ephemeral_auth(
|
||||
headers: &HeaderMap,
|
||||
db: &dyn StorageInterface,
|
||||
customer_id: &str,
|
||||
) -> RouterResult<Box<dyn AuthenticateAndFetch<storage::MerchantAccount>>> {
|
||||
let api_key = get_api_key(headers)?;
|
||||
|
||||
if !api_key.starts_with("epk") {
|
||||
return Ok(Box::new(ApiKeyAuth));
|
||||
}
|
||||
|
||||
let ephemeral_key = db
|
||||
.get_ephemeral_key(api_key)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
|
||||
if ephemeral_key.customer_id.ne(customer_id) {
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidEphermeralKey));
|
||||
}
|
||||
|
||||
Ok(Box::new(MerchantIdAuth(ephemeral_key.merchant_id)))
|
||||
}
|
||||
|
||||
fn get_api_key(headers: &HeaderMap) -> RouterResult<&str> {
|
||||
headers
|
||||
.get("api-key")
|
||||
.get_required_value("api-key")?
|
||||
.to_str()
|
||||
.into_report()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to convert API key to string")
|
||||
}
|
||||
Reference in New Issue
Block a user