Skip to content

Commit 02479a1

Browse files
authored
refactor(authn): Enable cookies in Integ (#6599)
1 parent 29a0885 commit 02479a1

File tree

11 files changed

+71
-12
lines changed

11 files changed

+71
-12
lines changed

config/config.example.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should
403403
totp_issuer_name = "Hyperswitch" # Name of the issuer for TOTP
404404
base_url = "" # Base url used for user specific redirects and emails
405405
force_two_factor_auth = false # Whether to force two factor authentication for all users
406+
force_cookies = true # Whether to use only cookies for JWT extraction and authentication
406407

407408
#tokenization configuration which describe token lifetime and payment method for specific connector
408409
[tokenization]

config/deployments/integration_test.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ two_factor_auth_expiry_in_secs = 300
145145
totp_issuer_name = "Hyperswitch Integ"
146146
base_url = "https://integ.hyperswitch.io"
147147
force_two_factor_auth = false
148+
force_cookies = true
148149

149150
[frm]
150151
enabled = true

config/deployments/production.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ two_factor_auth_expiry_in_secs = 300
152152
totp_issuer_name = "Hyperswitch Production"
153153
base_url = "https://live.hyperswitch.io"
154154
force_two_factor_auth = true
155+
force_cookies = false
155156

156157
[frm]
157158
enabled = false

config/deployments/sandbox.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ two_factor_auth_expiry_in_secs = 300
152152
totp_issuer_name = "Hyperswitch Sandbox"
153153
base_url = "https://app.hyperswitch.io"
154154
force_two_factor_auth = false
155+
force_cookies = false
155156

156157
[frm]
157158
enabled = true

config/development.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ two_factor_auth_expiry_in_secs = 300
329329
totp_issuer_name = "Hyperswitch Dev"
330330
base_url = "http://localhost:8080"
331331
force_two_factor_auth = false
332+
force_cookies = true
332333

333334
[bank_config.eps]
334335
stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" }

config/docker_compose.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ two_factor_auth_expiry_in_secs = 300
5757
totp_issuer_name = "Hyperswitch"
5858
base_url = "http://localhost:8080"
5959
force_two_factor_auth = false
60+
force_cookies = true
6061

6162
[locker]
6263
host = ""

crates/router/src/configs/settings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ pub struct UserSettings {
557557
pub totp_issuer_name: String,
558558
pub base_url: String,
559559
pub force_two_factor_auth: bool,
560+
pub force_cookies: bool,
560561
}
561562

562563
#[derive(Debug, Deserialize, Clone)]

crates/router/src/core/user.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ pub async fn connect_account(
294294

295295
pub async fn signout(
296296
state: SessionState,
297-
user_from_token: auth::UserFromToken,
297+
user_from_token: auth::UserIdFromAuth,
298298
) -> UserResponse<()> {
299299
tfa_utils::delete_totp_from_redis(&state, &user_from_token.user_id).await?;
300300
tfa_utils::delete_recovery_code_from_redis(&state, &user_from_token.user_id).await?;

crates/router/src/routes/user.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub async fn signout(state: web::Data<AppState>, http_req: HttpRequest) -> HttpR
130130
&http_req,
131131
(),
132132
|state, user, _, _| user_core::signout(state, user),
133-
&auth::DashboardNoPermissionAuth,
133+
&auth::AnyPurposeOrLoginTokenAuth,
134134
api_locking::LockAction::NotApplicable,
135135
))
136136
.await

crates/router/src/services/authentication.rs

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,47 @@ where
871871
}
872872
}
873873

874+
#[cfg(feature = "olap")]
875+
#[derive(Debug)]
876+
pub struct AnyPurposeOrLoginTokenAuth;
877+
878+
#[cfg(feature = "olap")]
879+
#[async_trait]
880+
impl<A> AuthenticateAndFetch<UserIdFromAuth, A> for AnyPurposeOrLoginTokenAuth
881+
where
882+
A: SessionStateInfo + Sync,
883+
{
884+
async fn authenticate_and_fetch(
885+
&self,
886+
request_headers: &HeaderMap,
887+
state: &A,
888+
) -> RouterResult<(UserIdFromAuth, AuthenticationType)> {
889+
let payload =
890+
parse_jwt_payload::<A, SinglePurposeOrLoginToken>(request_headers, state).await?;
891+
if payload.check_in_blacklist(state).await? {
892+
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
893+
}
894+
895+
let purpose_exists = payload.purpose.is_some();
896+
let role_id_exists = payload.role_id.is_some();
897+
898+
if purpose_exists ^ role_id_exists {
899+
Ok((
900+
UserIdFromAuth {
901+
user_id: payload.user_id.clone(),
902+
},
903+
AuthenticationType::SinglePurposeOrLoginJwt {
904+
user_id: payload.user_id,
905+
purpose: payload.purpose,
906+
role_id: payload.role_id,
907+
},
908+
))
909+
} else {
910+
Err(errors::ApiErrorResponse::InvalidJwtToken.into())
911+
}
912+
}
913+
}
914+
874915
#[derive(Debug, Default)]
875916
pub struct AdminApiAuth;
876917

@@ -2504,17 +2545,27 @@ where
25042545
T: serde::de::DeserializeOwned,
25052546
A: SessionStateInfo + Sync,
25062547
{
2507-
let token = match get_cookie_from_header(headers).and_then(cookies::parse_cookie) {
2508-
Ok(cookies) => cookies,
2509-
Err(error) => {
2510-
let token = get_jwt_from_authorization_header(headers);
2511-
if token.is_err() {
2512-
logger::error!(?error);
2513-
}
2514-
token?.to_owned()
2515-
}
2548+
let cookie_token_result = get_cookie_from_header(headers).and_then(cookies::parse_cookie);
2549+
let auth_header_token_result = get_jwt_from_authorization_header(headers);
2550+
let force_cookie = state.conf().user.force_cookies;
2551+
2552+
logger::info!(
2553+
user_agent = ?headers.get(headers::USER_AGENT),
2554+
header_names = ?headers.keys().collect::<Vec<_>>(),
2555+
is_token_equal =
2556+
auth_header_token_result.as_deref().ok() == cookie_token_result.as_deref().ok(),
2557+
cookie_error = ?cookie_token_result.as_ref().err(),
2558+
token_error = ?auth_header_token_result.as_ref().err(),
2559+
force_cookie,
2560+
);
2561+
2562+
let final_token = if force_cookie {
2563+
cookie_token_result?
2564+
} else {
2565+
auth_header_token_result?.to_owned()
25162566
};
2517-
decode_jwt(&token, state).await
2567+
2568+
decode_jwt(&final_token, state).await
25182569
}
25192570

25202571
#[cfg(feature = "v1")]

0 commit comments

Comments
 (0)