mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 11:24:45 +08:00
feat: use admin_api_key auth along with merchant_id for connector list, retrieve and update apis (#5613)
This commit is contained in:
@ -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,
|
||||
|
||||
@ -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")?
|
||||
|
||||
@ -484,7 +484,8 @@ Cypress.Commands.add("connectorRetrieveCall", (globalState) => {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"api-key": globalState.get("apiKey"),
|
||||
"api-key": globalState.get("adminApiKey"),
|
||||
"x-merchant-id": merchant_id,
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
}).then((response) => {
|
||||
@ -530,7 +531,8 @@ Cypress.Commands.add(
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"api-key": globalState.get("apiKey"),
|
||||
"api-key": globalState.get("adminApiKey"),
|
||||
"x-merchant-id": merchant_id,
|
||||
},
|
||||
body: updateConnectorBody,
|
||||
failOnStatusCode: false,
|
||||
@ -554,7 +556,8 @@ Cypress.Commands.add("connectorListByMid", (globalState) => {
|
||||
url: `${globalState.get("baseUrl")}/account/${merchant_id}/connectors`,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"api-key": globalState.get("apiKey"),
|
||||
"api-key": globalState.get("adminApiKey"),
|
||||
"X-Merchant-Id": merchant_id,
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
}).then((response) => {
|
||||
@ -2062,7 +2065,8 @@ Cypress.Commands.add("ListMCAbyMID", (globalState) => {
|
||||
url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"api-key": globalState.get("apiKey"),
|
||||
"api-key": globalState.get("adminApiKey"),
|
||||
"X-Merchant-Id": merchantId,
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
}).then((response) => {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
{
|
||||
"childrenOrder": [
|
||||
"API Key - Create",
|
||||
"Payment Connector - Create",
|
||||
"Payment Connector - Retrieve",
|
||||
"Payment Connector - Update",
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"eventOrder": ["event.test.js"]
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
// Validate status 2xx
|
||||
pm.test("[POST]::/api_keys/:merchant_id - Status code is 2xx", function () {
|
||||
pm.response.to.be.success;
|
||||
});
|
||||
|
||||
// Validate if response header has matching content-type
|
||||
pm.test(
|
||||
"[POST]::/api_keys/:merchant_id - Content-Type is application/json",
|
||||
function () {
|
||||
pm.expect(pm.response.headers.get("Content-Type")).to.include(
|
||||
"application/json",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Set response object as internal variable
|
||||
let jsonData = {};
|
||||
try {
|
||||
jsonData = pm.response.json();
|
||||
} catch (e) {}
|
||||
|
||||
// pm.collectionVariables - Set api_key_id as variable for jsonData.key_id
|
||||
if (jsonData?.key_id) {
|
||||
pm.collectionVariables.set("api_key_id", jsonData.key_id);
|
||||
console.log(
|
||||
"- use {{api_key_id}} as collection variable for value",
|
||||
jsonData.key_id,
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
"INFO - Unable to assign variable {{api_key_id}}, as jsonData.key_id is undefined.",
|
||||
);
|
||||
}
|
||||
|
||||
// pm.collectionVariables - Set api_key as variable for jsonData.api_key
|
||||
if (jsonData?.api_key) {
|
||||
pm.collectionVariables.set("api_key", jsonData.api_key);
|
||||
console.log(
|
||||
"- use {{api_key}} as collection variable for value",
|
||||
jsonData.api_key,
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
"INFO - Unable to assign variable {{api_key}}, as jsonData.api_key is undefined.",
|
||||
);
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
{
|
||||
"auth": {
|
||||
"type": "apikey",
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "key",
|
||||
"value": "api-key",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw_json_formatted": {
|
||||
"name": "API Key 1",
|
||||
"description": null,
|
||||
"expiration": "2069-09-23T01:02:03.000Z"
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api_keys/:merchant_id",
|
||||
"host": ["{{baseUrl}}"],
|
||||
"path": ["api_keys", ":merchant_id"],
|
||||
"variable": [
|
||||
{
|
||||
"key": "merchant_id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
[]
|
||||
@ -4,7 +4,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -19,6 +19,10 @@
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -24,6 +24,10 @@
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -28,6 +28,10 @@
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -28,6 +28,10 @@
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
|
||||
@ -1348,115 +1348,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "API Key - Create",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"// Validate status 2xx",
|
||||
"pm.test(\"[POST]::/api_keys/:merchant_id - Status code is 2xx\", function () {",
|
||||
" pm.response.to.be.success;",
|
||||
"});",
|
||||
"",
|
||||
"// Validate if response header has matching content-type",
|
||||
"pm.test(",
|
||||
" \"[POST]::/api_keys/:merchant_id - Content-Type is application/json\",",
|
||||
" function () {",
|
||||
" pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(",
|
||||
" \"application/json\",",
|
||||
" );",
|
||||
" },",
|
||||
");",
|
||||
"",
|
||||
"// Set response object as internal variable",
|
||||
"let jsonData = {};",
|
||||
"try {",
|
||||
" jsonData = pm.response.json();",
|
||||
"} catch (e) {}",
|
||||
"",
|
||||
"// pm.collectionVariables - Set api_key_id as variable for jsonData.key_id",
|
||||
"if (jsonData?.key_id) {",
|
||||
" pm.collectionVariables.set(\"api_key_id\", jsonData.key_id);",
|
||||
" console.log(",
|
||||
" \"- use {{api_key_id}} as collection variable for value\",",
|
||||
" jsonData.key_id,",
|
||||
" );",
|
||||
"} else {",
|
||||
" console.log(",
|
||||
" \"INFO - Unable to assign variable {{api_key_id}}, as jsonData.key_id is undefined.\",",
|
||||
" );",
|
||||
"}",
|
||||
"",
|
||||
"// pm.collectionVariables - Set api_key as variable for jsonData.api_key",
|
||||
"if (jsonData?.api_key) {",
|
||||
" pm.collectionVariables.set(\"api_key\", jsonData.api_key);",
|
||||
" console.log(",
|
||||
" \"- use {{api_key}} as collection variable for value\",",
|
||||
" jsonData.api_key,",
|
||||
" );",
|
||||
"} else {",
|
||||
" console.log(",
|
||||
" \"INFO - Unable to assign variable {{api_key}}, as jsonData.api_key is undefined.\",",
|
||||
" );",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "apikey",
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "key",
|
||||
"value": "api-key",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"name\":\"API Key 1\",\"description\":null,\"expiration\":\"2069-09-23T01:02:03.000Z\"}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api_keys/:merchant_id",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api_keys",
|
||||
":merchant_id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "merchant_id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Payment Connector - Create",
|
||||
"event": [
|
||||
@ -1637,7 +1528,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -1657,6 +1548,10 @@
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
@ -1752,7 +1647,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -1776,6 +1671,10 @@
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
@ -1849,7 +1748,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -1864,6 +1763,10 @@
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
@ -2684,7 +2587,7 @@
|
||||
"apikey": [
|
||||
{
|
||||
"key": "value",
|
||||
"value": "{{api_key}}",
|
||||
"value": "{{admin_api_key}}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@ -2708,6 +2611,10 @@
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "x-merchant-id",
|
||||
"value": "{{merchant_id}}"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
|
||||
Reference in New Issue
Block a user