Skip to content

Commit 9ffe4a6

Browse files
lsamprasAbhicodes-crypto
authored andcommitted
feat(events): add api auth type details to events (#2760)
1 parent 737f889 commit 9ffe4a6

File tree

4 files changed

+97
-26
lines changed

4 files changed

+97
-26
lines changed

crates/router/src/compatibility/wrap.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ where
2828
Q: Serialize + std::fmt::Debug + 'a,
2929
S: TryFrom<Q> + Serialize,
3030
E: Serialize + error_stack::Context + actix_web::ResponseError + Clone,
31-
U: auth::AuthInfo,
3231
error_stack::Report<E>: services::EmbedError,
3332
errors::ApiErrorResponse: ErrorSwitch<E>,
3433
T: std::fmt::Debug + Serialize,

crates/router/src/events/api_logs.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
use router_env::{tracing_actix_web::RequestId, types::FlowMetric};
2-
use serde::{Deserialize, Serialize};
2+
use serde::Serialize;
33
use time::OffsetDateTime;
44

55
use super::{EventType, RawEvent};
6+
use crate::services::authentication::AuthenticationType;
67

7-
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
8+
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
89
pub struct ApiEvent {
910
api_flow: String,
1011
created_at_timestamp: i128,
1112
request_id: String,
1213
latency: u128,
1314
status_code: i64,
15+
#[serde(flatten)]
16+
auth_type: AuthenticationType,
1417
request: serde_json::Value,
1518
response: Option<serde_json::Value>,
1619
}
@@ -23,6 +26,7 @@ impl ApiEvent {
2326
status_code: i64,
2427
request: serde_json::Value,
2528
response: Option<serde_json::Value>,
29+
auth_type: AuthenticationType,
2630
) -> Self {
2731
Self {
2832
api_flow: api_flow.to_string(),
@@ -32,6 +36,7 @@ impl ApiEvent {
3236
status_code,
3337
request,
3438
response,
39+
auth_type,
3540
}
3641
}
3742
}

crates/router/src/services/api.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use serde_json::json;
2525
use tera::{Context, Tera};
2626

2727
use self::request::{HeaderExt, RequestBuilderExt};
28-
use super::authentication::{AuthInfo, AuthenticateAndFetch};
28+
use super::authentication::AuthenticateAndFetch;
2929
use crate::{
3030
configs::settings::{Connectors, Settings},
3131
consts,
@@ -761,7 +761,6 @@ where
761761
Q: Serialize + Debug + 'a,
762762
T: Debug + Serialize,
763763
A: AppStateInfo + Clone,
764-
U: AuthInfo,
765764
E: ErrorSwitch<OErr> + error_stack::Context,
766765
OErr: ResponseError + error_stack::Context,
767766
errors::ApiErrorResponse: ErrorSwitch<OErr>,
@@ -782,12 +781,12 @@ where
782781
.change_context(errors::ApiErrorResponse::InternalServerError.switch())?;
783782

784783
// Currently auth failures are not recorded as API events
785-
let auth_out = api_auth
784+
let (auth_out, auth_type) = api_auth
786785
.authenticate_and_fetch(request.headers(), &request_state)
787786
.await
788787
.switch()?;
789788

790-
let merchant_id = auth_out
789+
let merchant_id = auth_type
791790
.get_merchant_id()
792791
.unwrap_or("MERCHANT_ID_NOT_FOUND")
793792
.to_string();
@@ -841,6 +840,7 @@ where
841840
status_code,
842841
serialized_request,
843842
serialized_response,
843+
auth_type,
844844
);
845845
match api_event.clone().try_into() {
846846
Ok(event) => {
@@ -874,7 +874,6 @@ where
874874
Fut: Future<Output = CustomResult<ApplicationResponse<Q>, E>>,
875875
Q: Serialize + Debug + 'a,
876876
T: Debug + Serialize,
877-
U: AuthInfo,
878877
A: AppStateInfo + Clone,
879878
ApplicationResponse<Q>: Debug,
880879
E: ErrorSwitch<api_models::errors::types::ApiErrorResponse> + error_stack::Context,

crates/router/src/services/authentication.rs

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use error_stack::{report, IntoReport, ResultExt};
77
use external_services::kms::{self, decrypt::KmsDecrypt};
88
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
99
use masking::{PeekInterface, StrongSecret};
10+
use serde::Serialize;
1011

1112
use crate::{
1213
configs::settings,
@@ -21,11 +22,51 @@ use crate::{
2122
utils::OptionExt,
2223
};
2324

25+
#[derive(Clone, Debug)]
2426
pub struct AuthenticationData {
2527
pub merchant_account: domain::MerchantAccount,
2628
pub key_store: domain::MerchantKeyStore,
2729
}
2830

31+
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
32+
#[serde(tag = "api_auth_type")]
33+
pub enum AuthenticationType {
34+
ApiKey {
35+
merchant_id: String,
36+
key_id: String,
37+
},
38+
AdminApiKey,
39+
MerchantJWT {
40+
merchant_id: String,
41+
user_id: Option<String>,
42+
},
43+
MerchantID {
44+
merchant_id: String,
45+
},
46+
PublishableKey {
47+
merchant_id: String,
48+
},
49+
NoAuth,
50+
}
51+
52+
impl AuthenticationType {
53+
pub fn get_merchant_id(&self) -> Option<&str> {
54+
match self {
55+
Self::ApiKey {
56+
merchant_id,
57+
key_id: _,
58+
}
59+
| Self::MerchantID { merchant_id }
60+
| Self::PublishableKey { merchant_id }
61+
| Self::MerchantJWT {
62+
merchant_id,
63+
user_id: _,
64+
} => Some(merchant_id.as_ref()),
65+
Self::AdminApiKey | Self::NoAuth => None,
66+
}
67+
}
68+
}
69+
2970
pub trait AuthInfo {
3071
fn get_merchant_id(&self) -> Option<&str>;
3172
}
@@ -46,13 +87,12 @@ impl AuthInfo for AuthenticationData {
4687
pub trait AuthenticateAndFetch<T, A>
4788
where
4889
A: AppStateInfo,
49-
T: AuthInfo,
5090
{
5191
async fn authenticate_and_fetch(
5292
&self,
5393
request_headers: &HeaderMap,
5494
state: &A,
55-
) -> RouterResult<T>;
95+
) -> RouterResult<(T, AuthenticationType)>;
5696
}
5797

5898
#[derive(Debug)]
@@ -69,8 +109,8 @@ where
69109
&self,
70110
_request_headers: &HeaderMap,
71111
_state: &A,
72-
) -> RouterResult<()> {
73-
Ok(())
112+
) -> RouterResult<((), AuthenticationType)> {
113+
Ok(((), AuthenticationType::NoAuth))
74114
}
75115
}
76116

@@ -83,7 +123,7 @@ where
83123
&self,
84124
request_headers: &HeaderMap,
85125
state: &A,
86-
) -> RouterResult<AuthenticationData> {
126+
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
87127
let api_key = get_api_key(request_headers)
88128
.change_context(errors::ApiErrorResponse::Unauthorized)?
89129
.trim();
@@ -139,10 +179,17 @@ where
139179
.await
140180
.to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;
141181

142-
Ok(AuthenticationData {
182+
let auth = AuthenticationData {
143183
merchant_account: merchant,
144184
key_store,
145-
})
185+
};
186+
Ok((
187+
auth.clone(),
188+
AuthenticationType::ApiKey {
189+
merchant_id: auth.merchant_account.merchant_id.clone(),
190+
key_id: stored_api_key.key_id,
191+
},
192+
))
146193
}
147194
}
148195

@@ -183,7 +230,7 @@ where
183230
&self,
184231
request_headers: &HeaderMap,
185232
state: &A,
186-
) -> RouterResult<()> {
233+
) -> RouterResult<((), AuthenticationType)> {
187234
let request_admin_api_key =
188235
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
189236
let conf = state.conf();
@@ -200,7 +247,7 @@ where
200247
.attach_printable("Admin Authentication Failure"))?;
201248
}
202249

203-
Ok(())
250+
Ok(((), AuthenticationType::AdminApiKey))
204251
}
205252
}
206253

@@ -216,7 +263,7 @@ where
216263
&self,
217264
_request_headers: &HeaderMap,
218265
state: &A,
219-
) -> RouterResult<AuthenticationData> {
266+
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
220267
let key_store = state
221268
.store()
222269
.get_merchant_key_store_by_merchant_id(
@@ -245,10 +292,16 @@ where
245292
}
246293
})?;
247294

248-
Ok(AuthenticationData {
295+
let auth = AuthenticationData {
249296
merchant_account: merchant,
250297
key_store,
251-
})
298+
};
299+
Ok((
300+
auth.clone(),
301+
AuthenticationType::MerchantID {
302+
merchant_id: auth.merchant_account.merchant_id.clone(),
303+
},
304+
))
252305
}
253306
}
254307

@@ -264,7 +317,7 @@ where
264317
&self,
265318
request_headers: &HeaderMap,
266319
state: &A,
267-
) -> RouterResult<AuthenticationData> {
320+
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
268321
let publishable_key =
269322
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
270323

@@ -279,6 +332,14 @@ where
279332
e.change_context(errors::ApiErrorResponse::InternalServerError)
280333
}
281334
})
335+
.map(|auth| {
336+
(
337+
auth.clone(),
338+
AuthenticationType::PublishableKey {
339+
merchant_id: auth.merchant_account.merchant_id.clone(),
340+
},
341+
)
342+
})
282343
}
283344
}
284345

@@ -300,12 +361,12 @@ where
300361
&self,
301362
request_headers: &HeaderMap,
302363
state: &A,
303-
) -> RouterResult<()> {
364+
) -> RouterResult<((), AuthenticationType)> {
304365
let mut token = get_jwt(request_headers)?;
305366
token = strip_jwt_token(token)?;
306367
decode_jwt::<JwtAuthPayloadFetchUnit>(token, state)
307368
.await
308-
.map(|_| ())
369+
.map(|_| ((), AuthenticationType::NoAuth))
309370
}
310371
}
311372

@@ -323,7 +384,7 @@ where
323384
&self,
324385
request_headers: &HeaderMap,
325386
state: &A,
326-
) -> RouterResult<AuthenticationData> {
387+
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
327388
let mut token = get_jwt(request_headers)?;
328389
token = strip_jwt_token(token)?;
329390
let payload = decode_jwt::<JwtAuthPayloadFetchMerchantAccount>(token, state).await?;
@@ -343,10 +404,17 @@ where
343404
.await
344405
.change_context(errors::ApiErrorResponse::InvalidJwtToken)?;
345406

346-
Ok(AuthenticationData {
407+
let auth = AuthenticationData {
347408
merchant_account: merchant,
348409
key_store,
349-
})
410+
};
411+
Ok((
412+
auth.clone(),
413+
AuthenticationType::MerchantJWT {
414+
merchant_id: auth.merchant_account.merchant_id.clone(),
415+
user_id: None,
416+
},
417+
))
350418
}
351419
}
352420

0 commit comments

Comments
 (0)