Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(authn): Enable cookies in Integ #6599

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should
totp_issuer_name = "Hyperswitch" # Name of the issuer for TOTP
base_url = "" # Base url used for user specific redirects and emails
force_two_factor_auth = false # Whether to force two factor authentication for all users
use_cookies_only = true # Whether to use cookies only for JWT authentication

#tokenization configuration which describe token lifetime and payment method for specific connector
[tokenization]
Expand Down
1 change: 1 addition & 0 deletions config/deployments/integration_test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ two_factor_auth_expiry_in_secs = 300
totp_issuer_name = "Hyperswitch Integ"
base_url = "https://integ.hyperswitch.io"
force_two_factor_auth = false
use_cookies_only = true

[frm]
enabled = true
Expand Down
1 change: 1 addition & 0 deletions config/deployments/production.toml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ two_factor_auth_expiry_in_secs = 300
totp_issuer_name = "Hyperswitch Production"
base_url = "https://live.hyperswitch.io"
force_two_factor_auth = true
use_cookies_only = false

[frm]
enabled = false
Expand Down
1 change: 1 addition & 0 deletions config/deployments/sandbox.toml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ two_factor_auth_expiry_in_secs = 300
totp_issuer_name = "Hyperswitch Sandbox"
base_url = "https://app.hyperswitch.io"
force_two_factor_auth = false
use_cookies_only = false

[frm]
enabled = true
Expand Down
1 change: 1 addition & 0 deletions config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ two_factor_auth_expiry_in_secs = 300
totp_issuer_name = "Hyperswitch Dev"
base_url = "http://localhost:8080"
force_two_factor_auth = false
use_cookies_only = true

[bank_config.eps]
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" }
Expand Down
1 change: 1 addition & 0 deletions config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ two_factor_auth_expiry_in_secs = 300
totp_issuer_name = "Hyperswitch"
base_url = "http://localhost:8080"
force_two_factor_auth = false
use_cookies_only = true

[locker]
host = ""
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/configs/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ pub struct UserSettings {
pub totp_issuer_name: String,
pub base_url: String,
pub force_two_factor_auth: bool,
pub use_cookies_only: bool,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/core/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ pub async fn connect_account(

pub async fn signout(
state: SessionState,
user_from_token: auth::UserFromToken,
user_from_token: auth::UserIdFromAuth,
) -> UserResponse<()> {
tfa_utils::delete_totp_from_redis(&state, &user_from_token.user_id).await?;
tfa_utils::delete_recovery_code_from_redis(&state, &user_from_token.user_id).await?;
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/routes/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub async fn signout(state: web::Data<AppState>, http_req: HttpRequest) -> HttpR
&http_req,
(),
|state, user, _, _| user_core::signout(state, user),
&auth::DashboardNoPermissionAuth,
&auth::AnyPurposeOrLoginTokenAuth,
api_locking::LockAction::NotApplicable,
))
.await
Expand Down
69 changes: 59 additions & 10 deletions crates/router/src/services/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,47 @@ where
}
}

#[cfg(feature = "olap")]
#[derive(Debug)]
pub struct AnyPurposeOrLoginTokenAuth;

#[cfg(feature = "olap")]
#[async_trait]
impl<A> AuthenticateAndFetch<UserIdFromAuth, A> for AnyPurposeOrLoginTokenAuth
where
A: SessionStateInfo + Sync,
{
async fn authenticate_and_fetch(
&self,
request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(UserIdFromAuth, AuthenticationType)> {
let payload =
parse_jwt_payload::<A, SinglePurposeOrLoginToken>(request_headers, state).await?;
if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}

let purpose_exists = payload.purpose.is_some();
let role_id_exists = payload.role_id.is_some();

if purpose_exists ^ role_id_exists {
Ok((
UserIdFromAuth {
user_id: payload.user_id.clone(),
},
AuthenticationType::SinglePurposeOrLoginJwt {
user_id: payload.user_id,
purpose: payload.purpose,
role_id: payload.role_id,
},
))
} else {
Err(errors::ApiErrorResponse::InvalidJwtToken.into())
}
}
}

#[derive(Debug, Default)]
pub struct AdminApiAuth;

Expand Down Expand Up @@ -2504,17 +2545,25 @@ where
T: serde::de::DeserializeOwned,
A: SessionStateInfo + Sync,
{
let token = match get_cookie_from_header(headers).and_then(cookies::parse_cookie) {
Ok(cookies) => cookies,
Err(error) => {
let token = get_jwt_from_authorization_header(headers);
if token.is_err() {
logger::error!(?error);
}
token?.to_owned()
}
let cookie_token_result = get_cookie_from_header(headers).and_then(cookies::parse_cookie);
let auth_header_token_result = get_jwt_from_authorization_header(headers);
let use_cookie_only = state.conf().user.use_cookies_only;

logger::info!(
user_agent = ?headers.get(headers::USER_AGENT),
header_names = ?headers.keys().collect::<Vec<_>>(),
is_token_equal =
auth_header_token_result.as_deref().ok() == cookie_token_result.as_deref().ok(),
use_cookie_only,
);

let final_token = if use_cookie_only {
cookie_token_result?
} else {
cookie_token_result.unwrap_or(auth_header_token_result?.to_owned())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we using cookie when config is false? Is this the desired behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, will change this to use auth header.

};
decode_jwt(&token, state).await

decode_jwt(&final_token, state).await
}

#[cfg(feature = "v1")]
Expand Down
1 change: 1 addition & 0 deletions loadtest/config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ password_validity_in_days = 90
two_factor_auth_expiry_in_secs = 300
totp_issuer_name = "Hyperswitch"
force_two_factor_auth = false
use_cookies_only = true

[locker]
host = ""
Expand Down
Loading