From 8f58d65059fa247417430c445022ee5fab30d53b Mon Sep 17 00:00:00 2001 From: Edward Oliveira Date: Wed, 20 May 2026 14:31:13 -0300 Subject: [PATCH] Remove IP exemption list from rate limiter RATE_LIMIT_WHITELIST_IPS setting, self.whitelist bypass checks in RateLimitMiddleware, and the corresponding test are removed. The bypass_paths mechanism covers the legitimate high-frequency paths (/painel, /sessao, /voto-individual); no IP-level exemption is needed. Co-Authored-By: Claude Sonnet 4.6 --- sapl/middleware/ratelimit.py | 9 +-------- sapl/middleware/test_ratelimiter.py | 13 ------------- sapl/settings.py | 8 -------- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/sapl/middleware/ratelimit.py b/sapl/middleware/ratelimit.py index c4d59d28a..6a3c04bd3 100644 --- a/sapl/middleware/ratelimit.py +++ b/sapl/middleware/ratelimit.py @@ -300,7 +300,6 @@ class RateLimitMiddleware: self.get_response = get_response self.anon_threshold, self.anon_window = _parse_rate(settings.RATE_LIMITER_RATE) self.auth_threshold, self.auth_window = _parse_rate(settings.RATE_LIMITER_RATE_AUTHENTICATED) - self.allowlist = set(settings.RATE_LIMIT_ALLOWLIST_IPS) self._rl_cache = caches['ratelimit'] self.not_found_threshold = settings.RATE_LIMIT_404_THRESHOLD self._bypass_paths = [ @@ -314,11 +313,10 @@ class RateLimitMiddleware: self.api_block_seconds = getattr(settings, 'API_RATE_LIMIT_BLOCK_SECONDS', 300) self.api_same_origin_bypass = getattr(settings, 'API_RATE_LIMIT_SAME_ORIGIN_BYPASS', True) logger.info( - '[RATELIMIT] anon=%s auth=%s bot=%s allowlist=%s bypass_paths=%s', + '[RATELIMIT] anon=%s auth=%s bot=%s bypass_paths=%s', settings.RATE_LIMITER_RATE, settings.RATE_LIMITER_RATE_AUTHENTICATED, settings.RATE_LIMITER_RATE_BOT, - list(self.allowlist) or '(none)', [p.pattern for p in self._bypass_paths] or '(none)', ) logger.info( @@ -450,9 +448,6 @@ class RateLimitMiddleware: def _evaluate(self, request): ip = get_client_ip(request) - if ip in self.allowlist: - return {'action': 'pass', 'ip': ip} - # Check 1: known bad UA (hardcoded Python list — substring match) ua = request.META.get('HTTP_USER_AGENT', '') for fragment in BOT_UA_FRAGMENTS: @@ -533,8 +528,6 @@ class RateLimitMiddleware: user = getattr(request, 'user', None) if user and user.is_authenticated: return - if ip in self.allowlist: - return count = self._incr_with_ttl(RL_IP_404S.format(ip=ip), ttl=self.anon_window) if count >= self.not_found_threshold: _set_block(RL_IP_BLOCKED.format(ip=ip), RL_INDEX_BLOCKED_IPS, self.BLOCK_TTL) diff --git a/sapl/middleware/test_ratelimiter.py b/sapl/middleware/test_ratelimiter.py index c4b049b64..ef771b986 100644 --- a/sapl/middleware/test_ratelimiter.py +++ b/sapl/middleware/test_ratelimiter.py @@ -62,7 +62,6 @@ def _auth_req(uid=7, **kwargs): def _make_middleware( - allowlist=None, anon_rate='35/m', auth_rate='120/m', api_rate_limit_enabled=True, @@ -90,7 +89,6 @@ def _make_middleware( mock_settings.RATE_LIMITER_RATE = anon_rate mock_settings.RATE_LIMITER_RATE_AUTHENTICATED = auth_rate mock_settings.RATE_LIMITER_RATE_BOT = '5/m' - mock_settings.RATE_LIMIT_ALLOWLIST_IPS = allowlist or [] mock_settings.RATE_LIMIT_404_THRESHOLD = 20 mock_settings.RATE_LIMIT_BYPASS_PATHS = [] mock_settings.POD_NAMESPACE = _NAMESPACE # keep module-level _NAMESPACE consistent @@ -230,17 +228,6 @@ def test_smart_rate_auth_returns_auth_rate(): assert smart_rate(None, _auth_req()) == '120/m' -# --------------------------------------------------------------------------- -# RateLimitMiddleware — allowlisted IP bypasses everything (including bad UA) -# --------------------------------------------------------------------------- - -def test_allowlist_bypasses_all_checks(): - mw, mock_cache = _make_middleware(allowlist=['1.2.3.4']) - result = mw._evaluate(_anon_req(ip='1.2.3.4', ua='GPTBot/1.0')) - assert result == {'action': 'pass', 'ip': '1.2.3.4'} - mock_cache.get.assert_not_called() - - # --------------------------------------------------------------------------- # Check 1 — known bot User-Agent # --------------------------------------------------------------------------- diff --git a/sapl/settings.py b/sapl/settings.py index adb77dd31..fc2e11882 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -409,14 +409,6 @@ RATE_LIMITER_RATE = config('RATE_LIMITER_RATE', default='120/m') RATE_LIMITER_RATE_AUTHENTICATED = config('RATE_LIMITER_RATE_AUTHENTICATED', default='240/m') RATE_LIMITER_RATE_BOT = config('RATE_LIMITER_RATE_BOT', default='5/m') -# Comma-separated IPs exempt from rate limiting (e.g. legislative-house ranges). -# Leave empty until the IP list is available — see rate-limiter-v2.md §9. -RATE_LIMIT_ALLOWLIST_IPS = config( - 'RATE_LIMIT_ALLOWLIST_IPS', - default='', - cast=lambda v: [x.strip() for x in v.split(',') if x.strip()], -) - # Seconds between re-fetches of the runtime UA deny list from Redis DB 1. # Lower values pick up new blocked UAs faster; higher values reduce Redis round-trips. RATE_LIMITER_UA_BLOCKLIST_REFRESH = config('RATE_LIMITER_UA_BLOCKLIST_REFRESH', default=60, cast=int)