From 70714f6adf966fc1f313e5d92c8640461ece0fa7 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 20 Feb 2024 11:48:19 +0100 Subject: [PATCH] Check access_token expiration is enough --- src/auth.rs | 12 ++++++++++-- src/sso.rs | 18 +++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index b26aa861e10..f76d6e5bb9c 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,6 +1,6 @@ // JWT Handling // -use chrono::{Duration, Utc}; +use chrono::{Duration, NaiveDateTime, Utc}; use num_traits::FromPrimitive; use once_cell::sync::Lazy; @@ -20,6 +20,9 @@ use crate::{ const JWT_ALGORITHM: Algorithm = Algorithm::RS256; +// Limit when BitWarden consider the token as expired +pub static BW_EXPIRATION: Lazy = Lazy::new(|| chrono::Duration::minutes(5)); + pub static DEFAULT_REFRESH_VALIDITY: Lazy = Lazy::new(|| Duration::days(7)); pub static DEFAULT_ACCESS_VALIDITY: Lazy = Lazy::new(|| Duration::hours(2)); static JWT_HEADER: Lazy
= Lazy::new(|| Header::new(JWT_ALGORITHM)); @@ -154,7 +157,7 @@ pub struct LoginJwtClaims { } impl LoginJwtClaims { - pub fn new(device: &Device, user: &User, nbf: i64, exp: i64, scope: Vec) -> Self { + pub fn new(device: &Device, user: &User, nbf: i64, exp: i64, scope: Vec, now: NaiveDateTime) -> Self { // --- // Disabled these keys to be added to the JWT since they could cause the JWT to get too large // Also These key/value pairs are not used anywhere by either Vaultwarden or Bitwarden Clients @@ -167,6 +170,10 @@ impl LoginJwtClaims { // let orguser: Vec<_> = orgs.iter().filter(|o| o.atype == 2).map(|o| o.org_uuid.clone()).collect(); // let orgmanager: Vec<_> = orgs.iter().filter(|o| o.atype == 3).map(|o| o.org_uuid.clone()).collect(); + if exp <= (now + *BW_EXPIRATION).timestamp() { + warn!("Raise access_token lifetime to more than 5min.") + } + // Create the JWT claims struct, to send to the client Self { nbf, @@ -203,6 +210,7 @@ impl LoginJwtClaims { time_now.timestamp(), (time_now + *DEFAULT_ACCESS_VALIDITY).timestamp(), auth_method.scope_vec(), + time_now, ) } diff --git a/src/sso.rs b/src/sso.rs index 6b084ff86a7..19ab56a23a3 100644 --- a/src/sso.rs +++ b/src/sso.rs @@ -18,7 +18,7 @@ use openidconnect::{ use crate::{ api::ApiResult, auth, - auth::{AuthMethod, AuthMethodScope, AuthTokens, TokenWrapper, DEFAULT_REFRESH_VALIDITY}, + auth::{AuthMethod, AuthMethodScope, AuthTokens, TokenWrapper, BW_EXPIRATION, DEFAULT_REFRESH_VALIDITY}, db::{ models::{Device, SsoNonce, User}, DbConn, @@ -31,8 +31,6 @@ static AC_CACHE: Lazy> = static SSO_JWT_ISSUER: Lazy = Lazy::new(|| format!("{}|sso", CONFIG.domain_origin())); -static DEFAULT_BW_EXPIRATION: Lazy = Lazy::new(|| chrono::Duration::minutes(5)); - pub static NONCE_EXPIRATION: Lazy = Lazy::new(|| chrono::Duration::minutes(10)); trait AuthorizationRequestExt<'a> { @@ -303,6 +301,7 @@ pub async fn exchange_code(wrapped_code: &str, conn: &mut DbConn) -> ApiResult, ) -> ApiResult { if !CONFIG.sso_auth_only_not_session() { + let now = Utc::now().naive_utc(); + let (ap_nbf, ap_exp) = match (decode_token_claims("access_token", access_token), expires_in) { (Ok(ap), _) => (ap.nbf(), ap.exp), - (Err(_), Some(exp)) => { - let time_now = Utc::now().naive_utc(); - (time_now.timestamp(), (time_now + exp).timestamp()) - } + (Err(_), Some(exp)) => (now.timestamp(), (now + exp).timestamp()), _ => err!("Non jwt access_token and empty expires_in"), }; - let access_claims = auth::LoginJwtClaims::new(device, user, ap_nbf, ap_exp, auth::AuthMethod::Sso.scope_vec()); + let access_claims = + auth::LoginJwtClaims::new(device, user, ap_nbf, ap_exp, auth::AuthMethod::Sso.scope_vec(), now); _create_auth_tokens(device, refresh_token, access_claims, access_token) } else { @@ -461,7 +460,7 @@ pub async fn exchange_refresh_token( } Some(TokenWrapper::Access(access_token)) => { let now = Utc::now().naive_utc(); - let exp_limit = (now + *DEFAULT_BW_EXPIRATION).timestamp(); + let exp_limit = (now + *BW_EXPIRATION).timestamp(); if refresh_claims.exp < exp_limit { err_silent!("Access token is close to expiration but we have no refresh token") @@ -479,6 +478,7 @@ pub async fn exchange_refresh_token( now.timestamp(), refresh_claims.exp, auth::AuthMethod::Sso.scope_vec(), + now, ); _create_auth_tokens(device, None, access_claims, access_token) }