Skip to content

Commit 42673a7

Browse files
committed
Throttle API users based on user group
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 8801c90 commit 42673a7

File tree

5 files changed

+44
-19
lines changed

5 files changed

+44
-19
lines changed

vulnerabilities/api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from vulnerabilities.models import get_purl_query_lookups
3535
from vulnerabilities.severity_systems import EPSS
3636
from vulnerabilities.severity_systems import SCORING_SYSTEMS
37-
from vulnerabilities.throttling import StaffUserRateThrottle
37+
from vulnerabilities.throttling import GroupUserRateThrottle
3838
from vulnerabilities.utils import get_severity_range
3939

4040

@@ -471,7 +471,7 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet):
471471
serializer_class = PackageSerializer
472472
filter_backends = (filters.DjangoFilterBackend,)
473473
filterset_class = PackageFilterSet
474-
throttle_classes = [StaffUserRateThrottle, AnonRateThrottle]
474+
throttle_classes = [AnonRateThrottle, GroupUserRateThrottle]
475475

476476
def get_queryset(self):
477477
return super().get_queryset().with_is_vulnerable()
@@ -688,7 +688,7 @@ def get_queryset(self):
688688
serializer_class = VulnerabilitySerializer
689689
filter_backends = (filters.DjangoFilterBackend,)
690690
filterset_class = VulnerabilityFilterSet
691-
throttle_classes = [StaffUserRateThrottle, AnonRateThrottle]
691+
throttle_classes = [AnonRateThrottle, GroupUserRateThrottle]
692692

693693

694694
class CPEFilterSet(filters.FilterSet):

vulnerabilities/api_extension.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from vulnerabilities.models import VulnerabilitySeverity
3434
from vulnerabilities.models import Weakness
3535
from vulnerabilities.models import get_purl_query_lookups
36-
from vulnerabilities.throttling import StaffUserRateThrottle
36+
from vulnerabilities.throttling import GroupUserRateThrottle
3737

3838

3939
class SerializerExcludeFieldsMixin:
@@ -259,7 +259,7 @@ class V2PackageViewSet(viewsets.ReadOnlyModelViewSet):
259259
lookup_field = "purl"
260260
filter_backends = (filters.DjangoFilterBackend,)
261261
filterset_class = V2PackageFilterSet
262-
throttle_classes = [StaffUserRateThrottle, AnonRateThrottle]
262+
throttle_classes = [GroupUserRateThrottle, AnonRateThrottle]
263263

264264
def get_queryset(self):
265265
return super().get_queryset().with_is_vulnerable().prefetch_related("vulnerabilities")
@@ -345,7 +345,7 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet):
345345
lookup_field = "vulnerability_id"
346346
filter_backends = (filters.DjangoFilterBackend,)
347347
filterset_class = V2VulnerabilityFilterSet
348-
throttle_classes = [StaffUserRateThrottle, AnonRateThrottle]
348+
throttle_classes = [GroupUserRateThrottle, AnonRateThrottle]
349349

350350
def get_queryset(self):
351351
"""
@@ -381,7 +381,7 @@ class CPEViewSet(viewsets.ReadOnlyModelViewSet):
381381
).distinct()
382382
serializer_class = V2VulnerabilitySerializer
383383
filter_backends = (filters.DjangoFilterBackend,)
384-
throttle_classes = [StaffUserRateThrottle, AnonRateThrottle]
384+
throttle_classes = [GroupUserRateThrottle, AnonRateThrottle]
385385
filterset_class = CPEFilterSet
386386

387387
@action(detail=False, methods=["post"])
@@ -420,4 +420,4 @@ class AliasViewSet(viewsets.ReadOnlyModelViewSet):
420420
serializer_class = V2VulnerabilitySerializer
421421
filter_backends = (filters.DjangoFilterBackend,)
422422
filterset_class = AliasFilterSet
423-
throttle_classes = [StaffUserRateThrottle, AnonRateThrottle]
423+
throttle_classes = [GroupUserRateThrottle, AnonRateThrottle]

vulnerabilities/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from cwe2.mappings import xml_database_path
2929
from cwe2.weakness import Weakness as DBWeakness
3030
from django.contrib.auth import get_user_model
31+
from django.contrib.auth.models import Group
3132
from django.contrib.auth.models import UserManager
3233
from django.core import exceptions
3334
from django.core.exceptions import ValidationError
@@ -1472,6 +1473,10 @@ def create_api_user(self, username, first_name="", last_name="", **extra_fields)
14721473
user.set_unusable_password()
14731474
user.save()
14741475

1476+
# Assign the default basic group
1477+
default_group, _ = Group.objects.get_or_create(name="silver")
1478+
user.groups.add(default_group)
1479+
14751480
Token._default_manager.get_or_create(user=user)
14761481

14771482
return user

vulnerabilities/throttling.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,31 @@
66
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
9+
910
from rest_framework.exceptions import Throttled
1011
from rest_framework.throttling import UserRateThrottle
1112
from rest_framework.views import exception_handler
1213

1314

14-
class StaffUserRateThrottle(UserRateThrottle):
15+
class GroupUserRateThrottle(UserRateThrottle):
16+
scope = "bronze"
17+
1518
def allow_request(self, request, view):
16-
"""
17-
Do not apply throttling for superusers and admins.
18-
"""
19-
if request.user.is_superuser or request.user.is_staff:
20-
return True
19+
user = request.user
20+
21+
if user and user.is_authenticated:
22+
if user.is_superuser or user.is_staff:
23+
return True
24+
25+
user_groups = user.groups.all()
26+
if any([group.name == "gold" for group in user_groups]):
27+
return True
28+
29+
if any([group.name == "silver" for group in user_groups]):
30+
self.scope = "silver"
31+
32+
self.rate = self.THROTTLE_RATES.get(self.scope)
33+
self.num_requests, self.duration = self.parse_rate(self.rate)
2134

2235
return super().allow_request(request, view)
2336

vulnerablecode/settings.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,20 @@
190190
LOGIN_REDIRECT_URL = "/"
191191
LOGOUT_REDIRECT_URL = "/"
192192

193-
REST_FRAMEWORK_DEFAULT_THROTTLE_RATES = {"anon": "3600/hour", "user": "10800/hour"}
193+
REST_FRAMEWORK_DEFAULT_THROTTLE_RATES = {
194+
# No throttling for users in gold group.
195+
"silver": "10800/hour",
196+
"bronze": "7200/hour",
197+
"anon": "3600/hour",
198+
}
194199

195200
if IS_TESTS:
196201
VULNERABLECODEIO_REQUIRE_AUTHENTICATION = False
197-
REST_FRAMEWORK_DEFAULT_THROTTLE_RATES = {"anon": "10/day", "user": "20/day"}
198-
202+
REST_FRAMEWORK_DEFAULT_THROTTLE_RATES = {
203+
"silver": "20/day",
204+
"bronze": "15/day",
205+
"anon": "10/day",
206+
}
199207

200208
USE_L10N = True
201209

@@ -235,9 +243,8 @@
235243
"rest_framework.filters.SearchFilter",
236244
),
237245
"DEFAULT_THROTTLE_CLASSES": [
238-
"vulnerabilities.throttling.StaffUserRateThrottle",
246+
"vulnerabilities.throttling.GroupUserRateThrottle",
239247
"rest_framework.throttling.AnonRateThrottle",
240-
"rest_framework.throttling.UserRateThrottle",
241248
],
242249
"DEFAULT_THROTTLE_RATES": REST_FRAMEWORK_DEFAULT_THROTTLE_RATES,
243250
"EXCEPTION_HANDLER": "vulnerabilities.throttling.throttled_exception_handler",

0 commit comments

Comments
 (0)