mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-04-06 09:09:21 -07:00
Rotate refresh-tokens on sstamp reset (#7031)
When a security-stamp gets reset/rotated we should also rotate all device refresh-tokens to invalidate them. Else clients are still able to use old refresh tokens. Signed-off-by: BlackDex <black.dex@gmail.com>
This commit is contained in:
committed by
GitHub
parent
3a1378f469
commit
f62a7a66c8
@@ -49,11 +49,16 @@ impl Device {
|
||||
|
||||
push_uuid: Some(PushId(get_uuid())),
|
||||
push_token: None,
|
||||
refresh_token: crypto::encode_random_bytes::<64>(&BASE64URL),
|
||||
refresh_token: Device::generate_refresh_token(),
|
||||
twofactor_remember: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generate_refresh_token() -> String {
|
||||
crypto::encode_random_bytes::<64>(&BASE64URL)
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Value {
|
||||
json!({
|
||||
"id": self.uuid,
|
||||
@@ -260,6 +265,17 @@ impl Device {
|
||||
.unwrap_or(0) != 0
|
||||
}}
|
||||
}
|
||||
|
||||
pub async fn rotate_refresh_tokens_by_user(user_uuid: &UserId, conn: &DbConn) -> EmptyResult {
|
||||
// Generate a new token per device.
|
||||
// We cannot do a single UPDATE with one value because each device needs a unique token.
|
||||
let devices = Self::find_by_user(user_uuid, conn).await;
|
||||
for mut device in devices {
|
||||
device.refresh_token = Device::generate_refresh_token();
|
||||
device.save(false, conn).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
|
||||
@@ -185,13 +185,14 @@ impl User {
|
||||
/// These routes are able to use the previous stamp id for the next 2 minutes.
|
||||
/// After these 2 minutes this stamp will expire.
|
||||
///
|
||||
pub fn set_password(
|
||||
pub async fn set_password(
|
||||
&mut self,
|
||||
password: &str,
|
||||
new_key: Option<String>,
|
||||
reset_security_stamp: bool,
|
||||
allow_next_route: Option<Vec<String>>,
|
||||
) {
|
||||
conn: &DbConn,
|
||||
) -> EmptyResult {
|
||||
self.password_hash = crypto::hash_password(password.as_bytes(), &self.salt, self.password_iterations as u32);
|
||||
|
||||
if let Some(route) = allow_next_route {
|
||||
@@ -203,12 +204,15 @@ impl User {
|
||||
}
|
||||
|
||||
if reset_security_stamp {
|
||||
self.reset_security_stamp()
|
||||
self.reset_security_stamp(conn).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn reset_security_stamp(&mut self) {
|
||||
pub async fn reset_security_stamp(&mut self, conn: &DbConn) -> EmptyResult {
|
||||
self.security_stamp = get_uuid();
|
||||
Device::rotate_refresh_tokens_by_user(&self.uuid, conn).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the stamp_exception to only allow a subsequent request matching a specific route using the current security-stamp.
|
||||
|
||||
Reference in New Issue
Block a user