refactor(router): appstate as trait in authentication (#588)

This commit is contained in:
Rachit Naithani
2023-02-14 12:30:08 +05:30
committed by GitHub
parent 6c2a1fea9a
commit eaf98e66bc
2 changed files with 32 additions and 18 deletions

View File

@ -29,16 +29,19 @@ where
pub struct ApiKeyAuth; pub struct ApiKeyAuth;
#[async_trait] #[async_trait]
impl AuthenticateAndFetch<storage::MerchantAccount, AppState> for ApiKeyAuth { impl<A> AuthenticateAndFetch<storage::MerchantAccount, A> for ApiKeyAuth
where
A: AppStateInfo + Sync,
{
async fn authenticate_and_fetch( async fn authenticate_and_fetch(
&self, &self,
request_headers: &HeaderMap, request_headers: &HeaderMap,
state: &AppState, state: &A,
) -> RouterResult<storage::MerchantAccount> { ) -> RouterResult<storage::MerchantAccount> {
let api_key = let api_key =
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?; get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
state state
.store .store()
.find_merchant_account_by_api_key(api_key) .find_merchant_account_by_api_key(api_key)
.await .await
.change_context(errors::ApiErrorResponse::Unauthorized) .change_context(errors::ApiErrorResponse::Unauthorized)
@ -50,15 +53,19 @@ impl AuthenticateAndFetch<storage::MerchantAccount, AppState> for ApiKeyAuth {
pub struct AdminApiAuth; pub struct AdminApiAuth;
#[async_trait] #[async_trait]
impl AuthenticateAndFetch<(), AppState> for AdminApiAuth { impl<A> AuthenticateAndFetch<(), A> for AdminApiAuth
where
A: AppStateInfo + Sync,
{
async fn authenticate_and_fetch( async fn authenticate_and_fetch(
&self, &self,
request_headers: &HeaderMap, request_headers: &HeaderMap,
state: &AppState, state: &A,
) -> RouterResult<()> { ) -> RouterResult<()> {
let admin_api_key = let admin_api_key =
get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?; get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?;
if admin_api_key != state.conf.secrets.admin_api_key { let conf = state.conf();
if admin_api_key != conf.secrets.admin_api_key {
Err(report!(errors::ApiErrorResponse::Unauthorized) Err(report!(errors::ApiErrorResponse::Unauthorized)
.attach_printable("Admin Authentication Failure"))?; .attach_printable("Admin Authentication Failure"))?;
} }
@ -115,11 +122,14 @@ struct JwtAuthPayloadFetchUnit {
} }
#[async_trait] #[async_trait]
impl AuthenticateAndFetch<(), AppState> for JWTAuth { impl<A> AuthenticateAndFetch<(), A> for JWTAuth
where
A: AppStateInfo + Sync,
{
async fn authenticate_and_fetch( async fn authenticate_and_fetch(
&self, &self,
request_headers: &HeaderMap, request_headers: &HeaderMap,
state: &AppState, state: &A,
) -> RouterResult<()> { ) -> RouterResult<()> {
let mut token = get_jwt(request_headers)?; let mut token = get_jwt(request_headers)?;
token = strip_jwt_token(token)?; token = strip_jwt_token(token)?;
@ -133,17 +143,20 @@ struct JwtAuthPayloadFetchMerchantAccount {
} }
#[async_trait] #[async_trait]
impl AuthenticateAndFetch<storage::MerchantAccount, AppState> for JWTAuth { impl<A> AuthenticateAndFetch<storage::MerchantAccount, A> for JWTAuth
where
A: AppStateInfo + Sync,
{
async fn authenticate_and_fetch( async fn authenticate_and_fetch(
&self, &self,
request_headers: &HeaderMap, request_headers: &HeaderMap,
state: &AppState, state: &A,
) -> RouterResult<storage::MerchantAccount> { ) -> RouterResult<storage::MerchantAccount> {
let mut token = get_jwt(request_headers)?; let mut token = get_jwt(request_headers)?;
token = strip_jwt_token(token)?; token = strip_jwt_token(token)?;
let payload = decode_jwt::<JwtAuthPayloadFetchMerchantAccount>(token, state)?; let payload = decode_jwt::<JwtAuthPayloadFetchMerchantAccount>(token, state)?;
state state
.store .store()
.find_merchant_account_by_merchant_id(&payload.merchant_id) .find_merchant_account_by_merchant_id(&payload.merchant_id)
.await .await
.change_context(errors::ApiErrorResponse::InvalidJwtToken) .change_context(errors::ApiErrorResponse::InvalidJwtToken)
@ -250,15 +263,16 @@ pub async fn is_ephemeral_auth(
Ok(Box::new(MerchantIdAuth(ephemeral_key.merchant_id))) Ok(Box::new(MerchantIdAuth(ephemeral_key.merchant_id)))
} }
fn is_jwt_auth(headers: &HeaderMap) -> bool { pub fn is_jwt_auth(headers: &HeaderMap) -> bool {
headers.get(crate::headers::AUTHORIZATION).is_some() headers.get(crate::headers::AUTHORIZATION).is_some()
} }
pub fn decode_jwt<T>(token: &str, state: &AppState) -> RouterResult<T> pub fn decode_jwt<T>(token: &str, state: &impl AppStateInfo) -> RouterResult<T>
where where
T: serde::de::DeserializeOwned, T: serde::de::DeserializeOwned,
{ {
let secret = state.conf.secrets.jwt_secret.as_bytes(); let conf = state.conf();
let secret = conf.secrets.jwt_secret.as_bytes();
let key = DecodingKey::from_secret(secret); let key = DecodingKey::from_secret(secret);
decode::<T>(token, &key, &Validation::new(Algorithm::HS256)) decode::<T>(token, &key, &Validation::new(Algorithm::HS256))
.map(|decoded| decoded.claims) .map(|decoded| decoded.claims)
@ -266,7 +280,7 @@ where
.change_context(errors::ApiErrorResponse::InvalidJwtToken) .change_context(errors::ApiErrorResponse::InvalidJwtToken)
} }
fn get_api_key(headers: &HeaderMap) -> RouterResult<&str> { pub fn get_api_key(headers: &HeaderMap) -> RouterResult<&str> {
headers headers
.get("api-key") .get("api-key")
.get_required_value("api-key")? .get_required_value("api-key")?
@ -276,7 +290,7 @@ fn get_api_key(headers: &HeaderMap) -> RouterResult<&str> {
.attach_printable("Failed to convert API key to string") .attach_printable("Failed to convert API key to string")
} }
fn get_jwt(headers: &HeaderMap) -> RouterResult<&str> { pub fn get_jwt(headers: &HeaderMap) -> RouterResult<&str> {
headers headers
.get(crate::headers::AUTHORIZATION) .get(crate::headers::AUTHORIZATION)
.get_required_value(crate::headers::AUTHORIZATION)? .get_required_value(crate::headers::AUTHORIZATION)?
@ -286,7 +300,7 @@ fn get_jwt(headers: &HeaderMap) -> RouterResult<&str> {
.attach_printable("Failed to convert JWT token to string") .attach_printable("Failed to convert JWT token to string")
} }
fn strip_jwt_token(token: &str) -> RouterResult<&str> { pub fn strip_jwt_token(token: &str) -> RouterResult<&str> {
token token
.strip_prefix("Bearer ") .strip_prefix("Bearer ")
.ok_or_else(|| errors::ApiErrorResponse::InvalidJwtToken.into()) .ok_or_else(|| errors::ApiErrorResponse::InvalidJwtToken.into())

View File

@ -64,7 +64,7 @@ pub mod error_parser {
} }
} }
pub(crate) fn custom_json_error_handler(err: JsonPayloadError, _req: &HttpRequest) -> Error { pub fn custom_json_error_handler(err: JsonPayloadError, _req: &HttpRequest) -> Error {
actix_web::error::Error::from(CustomJsonError { err }) actix_web::error::Error::from(CustomJsonError { err })
} }
} }