mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(users): Implemented cookie parsing for auth (#4298)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -427,6 +427,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
||||
| errors::ApiErrorResponse::InvalidJwtToken
|
||||
| errors::ApiErrorResponse::GenericUnauthorized { .. }
|
||||
| errors::ApiErrorResponse::AccessForbidden { .. }
|
||||
| errors::ApiErrorResponse::InvalidCookie
|
||||
| errors::ApiErrorResponse::InvalidEphemeralKey => Self::Unauthorized,
|
||||
errors::ApiErrorResponse::InvalidRequestUrl
|
||||
| errors::ApiErrorResponse::InvalidHttpMethod
|
||||
|
||||
@ -260,6 +260,11 @@ pub enum ApiErrorResponse {
|
||||
CurrencyConversionFailed,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
|
||||
PaymentMethodDeleteFailed,
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_26",
|
||||
message = "Invalid Cookie"
|
||||
)]
|
||||
InvalidCookie,
|
||||
}
|
||||
|
||||
impl PTError for ApiErrorResponse {
|
||||
|
||||
@ -292,6 +292,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon
|
||||
Self::PaymentMethodDeleteFailed => {
|
||||
AER::BadRequest(ApiError::new("IR", 25, "Cannot delete the default payment method", None))
|
||||
}
|
||||
Self::InvalidCookie => {
|
||||
AER::BadRequest(ApiError::new("IR", 26, "Invalid Cookie", None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ use common_utils::date_time;
|
||||
use error_stack::{report, ResultExt};
|
||||
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
||||
use masking::PeekInterface;
|
||||
use router_env::logger;
|
||||
use serde::Serialize;
|
||||
|
||||
use self::blacklist::BlackList;
|
||||
@ -33,7 +34,6 @@ use crate::{
|
||||
utils::OptionExt,
|
||||
};
|
||||
pub mod blacklist;
|
||||
#[cfg(feature = "olap")]
|
||||
pub mod cookies;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -598,6 +598,15 @@ where
|
||||
A: AppStateInfo + Sync,
|
||||
{
|
||||
let token = get_jwt_from_authorization_header(headers)?;
|
||||
if let Some(token_from_cookies) = get_cookie_from_header(headers)
|
||||
.ok()
|
||||
.and_then(|cookies| cookies::parse_cookie(cookies).ok())
|
||||
{
|
||||
logger::info!(
|
||||
"Cookie header and authorization header JWT comparison result: {}",
|
||||
token == token_from_cookies
|
||||
);
|
||||
}
|
||||
let payload = decode_jwt(token, state).await?;
|
||||
|
||||
Ok(payload)
|
||||
@ -959,6 +968,13 @@ pub fn get_jwt_from_authorization_header(headers: &HeaderMap) -> RouterResult<&s
|
||||
.ok_or(errors::ApiErrorResponse::InvalidJwtToken.into())
|
||||
}
|
||||
|
||||
pub fn get_cookie_from_header(headers: &HeaderMap) -> RouterResult<&str> {
|
||||
headers
|
||||
.get(cookies::get_cookie_header())
|
||||
.and_then(|header_value| header_value.to_str().ok())
|
||||
.ok_or(errors::ApiErrorResponse::InvalidCookie.into())
|
||||
}
|
||||
|
||||
pub fn strip_jwt_token(token: &str) -> RouterResult<&str> {
|
||||
token
|
||||
.strip_prefix("Bearer ")
|
||||
|
||||
@ -1,15 +1,27 @@
|
||||
use cookie::Cookie;
|
||||
#[cfg(feature = "olap")]
|
||||
use cookie::{
|
||||
time::{Duration, OffsetDateTime},
|
||||
Cookie, SameSite,
|
||||
SameSite,
|
||||
};
|
||||
use masking::{ExposeInterface, Mask, Secret};
|
||||
use error_stack::{report, ResultExt};
|
||||
#[cfg(feature = "olap")]
|
||||
use masking::Mask;
|
||||
#[cfg(feature = "olap")]
|
||||
use masking::{ExposeInterface, Secret};
|
||||
|
||||
use crate::{
|
||||
consts::{JWT_TOKEN_COOKIE_NAME, JWT_TOKEN_TIME_IN_SECS},
|
||||
consts::JWT_TOKEN_COOKIE_NAME,
|
||||
core::errors::{ApiErrorResponse, RouterResult},
|
||||
};
|
||||
#[cfg(feature = "olap")]
|
||||
use crate::{
|
||||
consts::JWT_TOKEN_TIME_IN_SECS,
|
||||
core::errors::{UserErrors, UserResponse},
|
||||
services::ApplicationResponse,
|
||||
};
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
pub fn set_cookie_response<R>(response: R, token: Secret<String>) -> UserResponse<R> {
|
||||
let jwt_expiry_in_seconds = JWT_TOKEN_TIME_IN_SECS
|
||||
.try_into()
|
||||
@ -19,16 +31,17 @@ pub fn set_cookie_response<R>(response: R, token: Secret<String>) -> UserRespons
|
||||
let header_value = create_cookie(token, expiry, max_age)
|
||||
.to_string()
|
||||
.into_masked();
|
||||
let header_key = get_cookie_header();
|
||||
let header_key = get_set_cookie_header();
|
||||
let header = vec![(header_key, header_value)];
|
||||
|
||||
Ok(ApplicationResponse::JsonWithHeaders((response, header)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
pub fn remove_cookie_response() -> UserResponse<()> {
|
||||
let (expiry, max_age) = get_expiry_and_max_age_from_seconds(0);
|
||||
|
||||
let header_key = get_cookie_header();
|
||||
let header_key = get_set_cookie_header();
|
||||
let header_value = create_cookie("".to_string().into(), expiry, max_age)
|
||||
.to_string()
|
||||
.into_masked();
|
||||
@ -36,6 +49,19 @@ pub fn remove_cookie_response() -> UserResponse<()> {
|
||||
Ok(ApplicationResponse::JsonWithHeaders(((), header)))
|
||||
}
|
||||
|
||||
pub fn parse_cookie(cookies: &str) -> RouterResult<String> {
|
||||
Cookie::split_parse(cookies)
|
||||
.find_map(|cookie| {
|
||||
cookie
|
||||
.ok()
|
||||
.filter(|parsed_cookie| parsed_cookie.name() == JWT_TOKEN_COOKIE_NAME)
|
||||
.map(|parsed_cookie| parsed_cookie.value().to_owned())
|
||||
})
|
||||
.ok_or(report!(ApiErrorResponse::InvalidCookie))
|
||||
.attach_printable("Cookie Parsing Failed")
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
fn create_cookie<'c>(
|
||||
token: Secret<String>,
|
||||
expires: OffsetDateTime,
|
||||
@ -51,12 +77,18 @@ fn create_cookie<'c>(
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
fn get_expiry_and_max_age_from_seconds(seconds: i64) -> (OffsetDateTime, Duration) {
|
||||
let max_age = Duration::seconds(seconds);
|
||||
let expiry = OffsetDateTime::now_utc().saturating_add(max_age);
|
||||
(expiry, max_age)
|
||||
}
|
||||
|
||||
fn get_cookie_header() -> String {
|
||||
#[cfg(feature = "olap")]
|
||||
fn get_set_cookie_header() -> String {
|
||||
actix_http::header::SET_COOKIE.to_string()
|
||||
}
|
||||
|
||||
pub fn get_cookie_header() -> String {
|
||||
actix_http::header::COOKIE.to_string()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user