diff --git a/example.pgdog.toml b/example.pgdog.toml index 2204f3079..52c44de8f 100644 --- a/example.pgdog.toml +++ b/example.pgdog.toml @@ -250,8 +250,8 @@ auth_type = "scram" # Prevents brute-force authentication attacks by limiting the number # of authentication attempts from a single IP address. # -# Default: 10 -auth_rate_limit = 10 +# Default: unlimited (disabled) +# auth_rate_limit = 10 # Disable cross-shard queries. # diff --git a/pgdog/src/auth/rate_limit.rs b/pgdog/src/auth/rate_limit.rs index 4b06d1cf5..8b8767f4b 100644 --- a/pgdog/src/auth/rate_limit.rs +++ b/pgdog/src/auth/rate_limit.rs @@ -1,10 +1,6 @@ //! Rate limiting for authentication attempts. -use governor::{ - clock::DefaultClock, - state::keyed::DefaultKeyedStateStore, - Quota, RateLimiter, -}; +use governor::{clock::DefaultClock, state::keyed::DefaultKeyedStateStore, Quota, RateLimiter}; use once_cell::sync::Lazy; use parking_lot::RwLock; use std::net::{IpAddr, Ipv6Addr}; @@ -26,7 +22,16 @@ fn normalize_ip(ip: IpAddr) -> IpAddr { IpAddr::V6(v6) => { let segments = v6.segments(); // Keep first 4 segments (64 bits), zero out the rest - let masked = Ipv6Addr::new(segments[0], segments[1], segments[2], segments[3], 0, 0, 0, 0); + let masked = Ipv6Addr::new( + segments[0], + segments[1], + segments[2], + segments[3], + 0, + 0, + 0, + 0, + ); IpAddr::V6(masked) } } @@ -188,7 +193,10 @@ mod tests { // Use unique IP to avoid interference from other tests let ip: IpAddr = "10.0.0.1".parse().unwrap(); - // Exhaust default limit of 10 on global limiter + // Set up a known limit first (don't depend on config defaults) + reload(Some(10)); + + // Exhaust limit of 10 for _ in 0..10 { assert!(check(ip)); } @@ -220,6 +228,12 @@ mod tests { fn test_limit_of_one() { // Edge case: minimum limit of 1 let limiter = test_limiter(1); + let ip: IpAddr = "192.168.100.2".parse().unwrap(); + + assert!(check_with_limiter(&limiter, ip)); + assert!(!check_with_limiter(&limiter, ip)); + } + #[test] fn test_unlimited_mode_allows_all() { // Temporarily set global limiter to None and ensure check() always returns true @@ -231,11 +245,6 @@ mod tests { // Restore to default reasonable limit for other tests reload(Some(10)); } - let ip: IpAddr = "192.168.100.2".parse().unwrap(); - - assert!(check_with_limiter(&limiter, ip)); - assert!(!check_with_limiter(&limiter, ip)); - } // Note: Time-based recovery test is not included because: // 1. Governor crate uses DefaultClock (wall-clock time), not Tokio's time @@ -244,4 +253,4 @@ mod tests { // // The rate limiting behavior is well-tested by the governor crate itself. // Our tests verify correct integration with the library. -} \ No newline at end of file +}