feat: use admin_api_key auth along with merchant_id for connector list, retrieve and update apis (#5613)

This commit is contained in:
Hrithikesh
2024-08-21 14:53:10 +05:30
committed by GitHub
parent beb4fb050f
commit b60ced02ff
13 changed files with 135 additions and 226 deletions

View File

@ -434,7 +434,7 @@ pub async fn connector_retrieve(
)
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::AdminApiAuthWithMerchantId::default(),
&auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantConnectorAccountRead,
@ -533,7 +533,7 @@ pub async fn payment_connector_list(
merchant_id.to_owned(),
|state, _auth, merchant_id, _| list_payment_connectors(state, merchant_id, None),
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::AdminApiAuthWithMerchantId::default(),
&auth::JWTAuthMerchantFromRoute {
merchant_id,
required_permission: Permission::MerchantConnectorAccountRead,
@ -593,7 +593,7 @@ pub async fn connector_update(
)
},
auth::auth_type(
&auth::HeaderAuth(auth::ApiKeyAuth),
&auth::AdminApiAuthWithMerchantId::default(),
&auth::JWTAuthMerchantFromRoute {
merchant_id: merchant_id.clone(),
required_permission: Permission::MerchantConnectorAccountWrite,

View File

@ -37,6 +37,7 @@ use crate::{
api_keys,
errors::{self, utils::StorageErrorExt, RouterResult},
},
headers,
routes::app::SessionStateInfo,
services::api,
types::domain,
@ -76,6 +77,9 @@ pub enum AuthenticationType {
key_id: String,
},
AdminApiKey,
AdminApiAuthWithMerchantId {
merchant_id: id_type::MerchantId,
},
MerchantJwt {
merchant_id: id_type::MerchantId,
user_id: Option<String>,
@ -122,6 +126,7 @@ impl AuthenticationType {
merchant_id,
key_id: _,
}
| Self::AdminApiAuthWithMerchantId { merchant_id }
| Self::MerchantId { merchant_id }
| Self::PublishableKey { merchant_id }
| Self::MerchantJwt {
@ -655,7 +660,7 @@ where
}
}
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct AdminApiAuth;
#[async_trait]
@ -683,6 +688,81 @@ where
}
}
#[derive(Debug, Default)]
pub struct AdminApiAuthWithMerchantId(AdminApiAuth);
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for AdminApiAuthWithMerchantId
where
A: SessionStateInfo + Sync,
{
async fn authenticate_and_fetch(
&self,
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
self.0
.authenticate_and_fetch(request_headers, state)
.await?;
let merchant_id =
get_header_value_by_key(headers::X_MERCHANT_ID.to_string(), request_headers)?
.get_required_value(headers::X_MERCHANT_ID)
.change_context(errors::ApiErrorResponse::InvalidRequestData {
message: format!("`{}` header is missing", headers::X_MERCHANT_ID),
})
.and_then(|merchant_id_str| {
id_type::MerchantId::try_from(std::borrow::Cow::from(
merchant_id_str.to_string(),
))
.change_context(
errors::ApiErrorResponse::InvalidRequestData {
message: format!("`{}` header is invalid", headers::X_MERCHANT_ID),
},
)
})?;
let key_manager_state = &(&state.session_state()).into();
let key_store = state
.store()
.get_merchant_key_store_by_merchant_id(
key_manager_state,
&merchant_id,
&state.store().get_master_key().to_vec().into(),
)
.await
.map_err(|e| {
if e.current_context().is_db_not_found() {
e.change_context(errors::ApiErrorResponse::Unauthorized)
} else {
e.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to fetch merchant key store for the merchant id")
}
})?;
let merchant = state
.store()
.find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
.await
.map_err(|e| {
if e.current_context().is_db_not_found() {
e.change_context(errors::ApiErrorResponse::Unauthorized)
} else {
e.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to fetch merchant account for the merchant id")
}
})?;
let auth = AuthenticationData {
merchant_account: merchant,
key_store,
profile_id: None,
};
Ok((
auth,
AuthenticationType::AdminApiAuthWithMerchantId { merchant_id },
))
}
}
#[derive(Debug)]
pub struct EphemeralKeyAuth;
@ -1425,7 +1505,7 @@ pub fn is_ephemeral_auth<A: SessionStateInfo + Sync + Send>(
}
pub fn is_jwt_auth(headers: &HeaderMap) -> bool {
headers.get(crate::headers::AUTHORIZATION).is_some()
headers.get(headers::AUTHORIZATION).is_some()
|| get_cookie_from_header(headers)
.and_then(cookies::parse_cookie)
.is_ok()
@ -1465,8 +1545,8 @@ pub fn get_header_value_by_key(key: String, headers: &HeaderMap) -> RouterResult
pub fn get_jwt_from_authorization_header(headers: &HeaderMap) -> RouterResult<&str> {
headers
.get(crate::headers::AUTHORIZATION)
.get_required_value(crate::headers::AUTHORIZATION)?
.get(headers::AUTHORIZATION)
.get_required_value(headers::AUTHORIZATION)?
.to_str()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to convert JWT token to string")?