feat(router): Add new JWT authentication variants and use them (#2835)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Mani Chandra
2023-11-13 11:17:35 +05:30
committed by GitHub
parent 0eb81f04b3
commit f88eee7362
34 changed files with 3489 additions and 67 deletions

View File

@ -9,6 +9,10 @@ use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use masking::{PeekInterface, StrongSecret};
use serde::Serialize;
#[cfg(feature = "olap")]
use super::jwt;
#[cfg(feature = "olap")]
use crate::consts;
use crate::{
configs::settings,
core::{
@ -71,6 +75,37 @@ impl AuthenticationType {
}
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct AuthToken {
pub user_id: String,
pub merchant_id: String,
pub role_id: String,
pub exp: u64,
pub org_id: String,
}
#[cfg(feature = "olap")]
impl AuthToken {
pub async fn new_token(
user_id: String,
merchant_id: String,
role_id: String,
settings: &settings::Settings,
org_id: String,
) -> errors::UserResult<String> {
let exp_duration = std::time::Duration::from_secs(consts::JWT_TOKEN_TIME_IN_SECS);
let exp = jwt::generate_exp(exp_duration)?.as_secs();
let token_payload = Self {
user_id,
merchant_id,
role_id,
exp,
org_id,
};
jwt::generate_jwt(&token_payload, settings).await
}
}
pub trait AuthInfo {
fn get_merchant_id(&self) -> Option<&str>;
}
@ -366,14 +401,58 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let mut token = get_jwt(request_headers)?;
token = strip_jwt_token(token)?;
decode_jwt::<JwtAuthPayloadFetchUnit>(token, state)
.await
.map(|_| ((), AuthenticationType::NoAuth))
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
Ok((
(),
AuthenticationType::MerchantJWT {
merchant_id: payload.merchant_id,
user_id: Some(payload.user_id),
},
))
}
}
pub struct JWTAuthMerchantFromRoute {
pub merchant_id: String,
}
#[async_trait]
impl<A> AuthenticateAndFetch<(), A> for JWTAuthMerchantFromRoute
where
A: AppStateInfo + Sync,
{
async fn authenticate_and_fetch(
&self,
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
// Check if token has access to merchantID that has been requested through query param
if payload.merchant_id != self.merchant_id {
return Err(report!(errors::ApiErrorResponse::InvalidJwtToken));
}
Ok((
(),
AuthenticationType::MerchantJWT {
merchant_id: payload.merchant_id,
user_id: Some(payload.user_id),
},
))
}
}
pub async fn parse_jwt_payload<A, T>(headers: &HeaderMap, state: &A) -> RouterResult<T>
where
T: serde::de::DeserializeOwned,
A: AppStateInfo + Sync,
{
let token = get_jwt_from_authorization_header(headers)?;
let payload = decode_jwt(token, state).await?;
Ok(payload)
}
#[derive(serde::Deserialize)]
struct JwtAuthPayloadFetchMerchantAccount {
merchant_id: String,
@ -389,9 +468,9 @@ where
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
let mut token = get_jwt(request_headers)?;
token = strip_jwt_token(token)?;
let payload = decode_jwt::<JwtAuthPayloadFetchMerchantAccount>(token, state).await?;
let payload =
parse_jwt_payload::<A, JwtAuthPayloadFetchMerchantAccount>(request_headers, state)
.await?;
let key_store = state
.store()
.get_merchant_key_store_by_merchant_id(
@ -595,14 +674,16 @@ pub fn get_header_value_by_key(key: String, headers: &HeaderMap) -> RouterResult
.transpose()
}
pub fn get_jwt(headers: &HeaderMap) -> RouterResult<&str> {
pub fn get_jwt_from_authorization_header(headers: &HeaderMap) -> RouterResult<&str> {
headers
.get(crate::headers::AUTHORIZATION)
.get_required_value(crate::headers::AUTHORIZATION)?
.to_str()
.into_report()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to convert JWT token to string")
.attach_printable("Failed to convert JWT token to string")?
.strip_prefix("Bearer ")
.ok_or(errors::ApiErrorResponse::InvalidJwtToken.into())
}
pub fn strip_jwt_token(token: &str) -> RouterResult<&str> {