From b9133018a5f86fc857415c87e10eb709991945ff Mon Sep 17 00:00:00 2001 From: Ashwin Kumar Sivakumar Date: Tue, 14 Jul 2026 16:12:52 +0530 Subject: [PATCH] fix(admin-auth): add rate limiting to admin login endpoint The admin/employee login handler had no brute-force protection, unlike the regular user login path. Given these accounts hold internal/ super-admin privileges, add a tighter limit (5 attempts/15min vs 10 for regular users) using the existing sliding-window Redis limiter. Co-Authored-By: Claude Sonnet 5 --- apps/employees/src/handlers/auth.rs | 7 ++++++- crates/cache/src/rate_limit.rs | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/employees/src/handlers/auth.rs b/apps/employees/src/handlers/auth.rs index 5d38ec4..3d8872e 100644 --- a/apps/employees/src/handlers/auth.rs +++ b/apps/employees/src/handlers/auth.rs @@ -54,7 +54,12 @@ async fn login( Json(payload): Json, ) -> Result)> { let email = payload.email.to_lowercase(); - + let mut redis = state.redis.clone(); + + if !cache::rate_limit::check_admin_login(&mut redis, &email).await.unwrap_or(true) { + return Err(err(StatusCode::TOO_MANY_REQUESTS, "Too many login attempts. Try again in 15 minutes.", "RATE_LIMITED")); + } + let employee = EmployeeRepository::get_by_email(&state.pool, &email) .await .map_err(|_| err(StatusCode::INTERNAL_SERVER_ERROR, "DB error", "DB_ERROR"))? diff --git a/crates/cache/src/rate_limit.rs b/crates/cache/src/rate_limit.rs index 2416d03..9028b8b 100644 --- a/crates/cache/src/rate_limit.rs +++ b/crates/cache/src/rate_limit.rs @@ -41,6 +41,12 @@ pub async fn check_login(redis: &mut RedisPool, email: &str) -> Result Result { + check(redis, "admin_login", email, 5, 900).await +} + /// Lead request: max 5 per hour per professional pub async fn check_lead(redis: &mut RedisPool, professional_id: &str) -> Result { check(redis, "lead", professional_id, 5, 3_600).await