From 1c036a4bb92d7ddc76babf729611a2473f2b1798 Mon Sep 17 00:00:00 2001 From: hugocasa Date: Mon, 23 Mar 2026 19:17:48 +0100 Subject: [PATCH] [ee] feat: enforce password.disabled in auth checks Co-Authored-By: Claude Opus 4.6 (1M context) --- ...1dc2127f42e33e5d98430fdcd48161b10f2fcecd.json | 15 --------------- backend/ee-repo-ref.txt | 2 +- backend/windmill-api-auth/src/auth.rs | 16 ++++++++++++++++ backend/windmill-api-users/src/users.rs | 2 +- backend/windmill-common/src/auth.rs | 9 +++++++++ 5 files changed, 27 insertions(+), 17 deletions(-) delete mode 100644 backend/.sqlx/query-db162dd3ee5036e00b7196e21dc2127f42e33e5d98430fdcd48161b10f2fcecd.json diff --git a/backend/.sqlx/query-db162dd3ee5036e00b7196e21dc2127f42e33e5d98430fdcd48161b10f2fcecd.json b/backend/.sqlx/query-db162dd3ee5036e00b7196e21dc2127f42e33e5d98430fdcd48161b10f2fcecd.json deleted file mode 100644 index 3a4d827c5e..0000000000 --- a/backend/.sqlx/query-db162dd3ee5036e00b7196e21dc2127f42e33e5d98430fdcd48161b10f2fcecd.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE usr SET disabled = $1 WHERE email = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bool", - "Text" - ] - }, - "nullable": [] - }, - "hash": "db162dd3ee5036e00b7196e21dc2127f42e33e5d98430fdcd48161b10f2fcecd" -} diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 0285ca3e3b..5d2e8edeeb 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -d6236db87c821b4abafe76c07294513b2c5434c1 \ No newline at end of file +2089be6a6e534865c11794452391f6e25708f32c \ No newline at end of file diff --git a/backend/windmill-api-auth/src/auth.rs b/backend/windmill-api-auth/src/auth.rs index 8e3a4c7822..3d9b952a98 100644 --- a/backend/windmill-api-auth/src/auth.rs +++ b/backend/windmill-api-auth/src/auth.rs @@ -233,6 +233,22 @@ impl AuthCache { .flatten(); if let Some(user) = user_o { + // Check if user is disabled at the instance level + if let Some(ref email) = user.1 { + let is_disabled = sqlx::query_scalar!( + "SELECT disabled FROM password WHERE email = $1", + email + ) + .fetch_optional(&self.db) + .await + .ok() + .flatten() + .unwrap_or(false); + if is_disabled { + return None; + } + } + let authed_o = { match user { (Some(owner), Some(email), super_admin, _, label) if w_id.is_some() => { diff --git a/backend/windmill-api-users/src/users.rs b/backend/windmill-api-users/src/users.rs index 8f7bec1398..aa67b26750 100644 --- a/backend/windmill-api-users/src/users.rs +++ b/backend/windmill-api-users/src/users.rs @@ -1687,7 +1687,7 @@ async fn login( }; let email_w_h: Option<(String, String, bool)> = sqlx::query_as( "SELECT email, password_hash, super_admin FROM password WHERE email = $1 AND login_type = \ - 'password'", + 'password' AND disabled = false", ) .bind(&email) .fetch_optional(&mut *tx) diff --git a/backend/windmill-common/src/auth.rs b/backend/windmill-common/src/auth.rs index 9872950ffb..4ebae52aac 100644 --- a/backend/windmill-common/src/auth.rs +++ b/backend/windmill-common/src/auth.rs @@ -328,6 +328,15 @@ async fn fetch_authed_from_permissioned_as_inner( w_id: &str, conn: &mut sqlx::PgConnection, ) -> Result { + let is_disabled = sqlx::query_scalar!("SELECT disabled FROM password WHERE email = $1", email) + .fetch_optional(&mut *conn) + .await + .map_err(|e| Error::internal_err(format!("fetching disabled: {e:#}")))? + .unwrap_or(false); + if is_disabled { + return Err(Error::NotAuthorized("User is disabled".to_string())); + } + let is_super_admin = permissioned_as == SUPERADMIN_SYNC_EMAIL || email == SUPERADMIN_SECRET_EMAIL || email == SUPERADMIN_NOTIFICATION_EMAIL