Improvements in the throttling code

remotes/origin/issue/4217/improving-mail-design
Jesús Espino 2017-03-02 07:47:31 +01:00 committed by David Barragán Merino
parent 8dfcbe4006
commit 8df7df763c
2 changed files with 53 additions and 19 deletions

View File

@ -18,6 +18,9 @@
from taiga.base.api import throttling from taiga.base.api import throttling
from django.conf import settings from django.conf import settings
from ipware.ip import get_ip
from netaddr import all_matching_cidrs
from netaddr.core import AddrFormatError
class GlobalThrottlingMixin: class GlobalThrottlingMixin:
@ -26,9 +29,7 @@ class GlobalThrottlingMixin:
logged in or not. logged in or not.
""" """
def get_cache_key(self, request, view): def get_cache_key(self, request, view):
ident = request.META.get("HTTP_X_FORWARDED_FOR") ident = get_ip(request)
if ident is None:
ident = request.META.get("REMOTE_ADDR")
return self.cache_format % { return self.cache_format % {
"scope": self.scope, "scope": self.scope,
@ -67,11 +68,24 @@ class CommonThrottle(throttling.SimpleRateThrottle):
def has_to_finalize(self, request, response, view): def has_to_finalize(self, request, response, view):
return False return False
def is_whitelisted(self, ident):
for whitelisted in settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST']:
if isinstance(whitelisted, int) and whitelisted == ident:
return True
elif isinstance(whitelisted, str):
try:
if all_matching_cidrs(ident, [whitelisted]) != []:
return True
except(AddrFormatError, ValueError):
pass
return False
def allow_request(self, request, view): def allow_request(self, request, view):
scope = self.get_scope(request) scope = self.get_scope(request)
ident = self.get_ident(request) ident = self.get_ident(request)
rates = self.get_rates(scope) rates = self.get_rates(scope)
if ident in settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST']:
if self.is_whitelisted(ident):
return True return True
if rates is None or rates == []: if rates is None or rates == []:
@ -145,25 +159,15 @@ class CommonThrottle(throttling.SimpleRateThrottle):
return (rate, num_requests, duration) return (rate, num_requests, duration)
def get_scope(self, request): def get_scope(self, request):
if request.user.is_authenticated(): scope_prefix = "user" if request.user.is_authenticated() else "anon"
if request.method in ["POST", "PUT", "PATCH", "DELETE"]: scope_sufix = "write" if request.method in ["POST", "PUT", "PATCH", "DELETE"] else "read"
scope = "user-write" scope = "{}-{}".format(scope_prefix, scope_sufix)
else:
scope = "user-read"
else:
if request.method in ["POST", "PUT", "PATCH", "DELETE"]:
scope = "anon-write"
else:
scope = "anon-read"
return scope return scope
def get_ident(self, request): def get_ident(self, request):
if request.user.is_authenticated(): if request.user.is_authenticated():
ident = request.user.id return request.user.id
else: ident = get_ip(request)
ident = request.META.get("HTTP_X_FORWARDED_FOR")
if ident is None:
ident = request.META.get("REMOTE_ADDR")
return ident return ident
def get_cache_key(self, ident, scope, rate): def get_cache_key(self, ident, scope, rate):

View File

@ -263,3 +263,33 @@ def test_not_whitelisted_anon_throttling(settings, rf):
cache.clear() cache.clear()
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon-read'] = None settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon-read'] = None
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST'] = [] settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST'] = []
def test_whitelisted_subnet_anon_throttling(settings, rf):
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon-read'] = "1/min"
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST'] = ["192.168.0.0/24"]
request = rf.get("/test")
request.user = AnonymousUser()
request.META["REMOTE_ADDR"] = "192.168.0.123"
throttling = CommonThrottle()
assert throttling.allow_request(request, None)
assert throttling.allow_request(request, None)
for x in range(100):
assert throttling.allow_request(request, None)
cache.clear()
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon-read'] = None
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST'] = []
def test_not_whitelisted_subnet_anon_throttling(settings, rf):
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon-read'] = "1/min"
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST'] = ["192.168.0.0/24"]
request = rf.get("/test")
request.user = AnonymousUser()
request.META["REMOTE_ADDR"] = "192.168.1.123"
throttling = CommonThrottle()
assert throttling.allow_request(request, None)
assert throttling.allow_request(request, None) is False
for x in range(100):
assert throttling.allow_request(request, None) is False
cache.clear()
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon-read'] = None
settings.REST_FRAMEWORK['DEFAULT_THROTTLE_WHITELIST'] = []