Skip to content
Snippets Groups Projects
Commit 978b83d2 authored by Tanner Prestegard's avatar Tanner Prestegard Committed by GraceDB
Browse files

Update throttles and add anonymous throttles

All throttles now use a database-backed cache since that is the
only way to do centralized throttling (important for production
deployment with multiple workers). We also add default throttles
for anonymous users for the entire API.
parent e0996f4a
No related branches found
No related tags found
No related merge requests found
...@@ -221,7 +221,11 @@ CACHES = { ...@@ -221,7 +221,11 @@ CACHES = {
'default': { 'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211', 'LOCATION': '127.0.0.1:11211',
} },
'throttles': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'api_throttle_cache', # Table name
},
} }
# List of settings for all template engines. Each item is a dict # List of settings for all template engines. Each item is a dict
...@@ -347,7 +351,11 @@ REST_FRAMEWORK = { ...@@ -347,7 +351,11 @@ REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.LimitOffsetPagination', 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 1e7, 'PAGE_SIZE': 1e7,
'DEFAULT_THROTTLE_CLASSES': (
'api.throttling.BurstAnonRateThrottle',
),
'DEFAULT_THROTTLE_RATES': { 'DEFAULT_THROTTLE_RATES': {
'anon_burst': '3/second',
'event_creation': '1/second', 'event_creation': '1/second',
'annotation' : '10/second', 'annotation' : '10/second',
}, },
......
from rest_framework.throttling import UserRateThrottle from django.core.cache import caches
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
class PostOrPutUserRateThrottle(UserRateThrottle):
# NOTE: we have to use database-backed throttles to have a centralized location
# where multiple workers (like in the production instance) can access and
# update the same throttling information.
###############################################################################
# Base throttle classes #######################################################
###############################################################################
class DbCachedThrottleMixin(object):
"""Uses a non-default (database-backed) cache"""
cache = caches['throttles']
###############################################################################
# Throttles for unauthenticated users #########################################
###############################################################################
class BurstAnonRateThrottle(DbCachedThrottleMixin, AnonRateThrottle):
scope = 'anon_burst'
class SustainedAnonRateThrottle(DbCachedThrottleMixin, AnonRateThrottle):
scope = 'anon_sustained'
###############################################################################
# Throttles for authenticated users #########################################
###############################################################################
class PostOrPutUserRateThrottle(DbCachedThrottleMixin, UserRateThrottle):
def allow_request(self, request, view): def allow_request(self, request, view):
""" """
......
...@@ -4,6 +4,7 @@ from api.throttling import PostOrPutUserRateThrottle ...@@ -4,6 +4,7 @@ from api.throttling import PostOrPutUserRateThrottle
class EventCreationThrottle(PostOrPutUserRateThrottle): class EventCreationThrottle(PostOrPutUserRateThrottle):
scope = 'event_creation' scope = 'event_creation'
class AnnotationThrottle(PostOrPutUserRateThrottle): class AnnotationThrottle(PostOrPutUserRateThrottle):
scope = 'annotation' scope = 'annotation'
...@@ -34,6 +34,7 @@ from rest_framework.views import APIView ...@@ -34,6 +34,7 @@ from rest_framework.views import APIView
from alerts.events.utils import EventAlertIssuer, EventLogAlertIssuer, \ from alerts.events.utils import EventAlertIssuer, EventLogAlertIssuer, \
EventVOEventAlertIssuer, EventPermissionsAlertIssuer EventVOEventAlertIssuer, EventPermissionsAlertIssuer
from api.throttling import BurstAnonRateThrottle
from core.http import check_and_serve_file from core.http import check_and_serve_file
from core.vfile import VersionedFile from core.vfile import VersionedFile
from events.buildVOEvent import buildVOEvent, VOEventBuilderException from events.buildVOEvent import buildVOEvent, VOEventBuilderException
...@@ -52,7 +53,7 @@ from events.view_utils import eventToDict, eventLogToDict, labelToDict, \ ...@@ -52,7 +53,7 @@ from events.view_utils import eventToDict, eventLogToDict, labelToDict, \
from search.forms import SimpleSearchForm from search.forms import SimpleSearchForm
from search.query.events import parseQuery, ParseException from search.query.events import parseQuery, ParseException
from superevents.models import Superevent from superevents.models import Superevent
from .throttles import EventCreationThrottle, AnnotationThrottle from .throttling import EventCreationThrottle, AnnotationThrottle
from ...utils import api_reverse from ...utils import api_reverse
# Set up logger # Set up logger
...@@ -348,7 +349,7 @@ class EventList(APIView): ...@@ -348,7 +349,7 @@ class EventList(APIView):
permission_classes = (IsAuthenticated,IsAuthorizedForPipeline) permission_classes = (IsAuthenticated,IsAuthorizedForPipeline)
parser_classes = (parsers.MultiPartParser,) parser_classes = (parsers.MultiPartParser,)
renderer_classes = (JSONRenderer, BrowsableAPIRenderer, LigoLwRenderer, TSVRenderer,) renderer_classes = (JSONRenderer, BrowsableAPIRenderer, LigoLwRenderer, TSVRenderer,)
throttle_classes = (EventCreationThrottle,) throttle_classes = (BurstAnonRateThrottle, EventCreationThrottle,)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
...@@ -728,7 +729,7 @@ class EventLogList(APIView): ...@@ -728,7 +729,7 @@ class EventLogList(APIView):
POST param 'message' POST param 'message'
""" """
permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) permission_classes = (IsAuthenticated,IsAuthorizedForEvent,)
throttle_classes = (AnnotationThrottle,) throttle_classes = (BurstAnonRateThrottle, AnnotationThrottle,)
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
...@@ -874,7 +875,7 @@ class EMBBEventLogList(APIView): ...@@ -874,7 +875,7 @@ class EMBBEventLogList(APIView):
POST param 'message' POST param 'message'
""" """
permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) permission_classes = (IsAuthenticated,IsAuthorizedForEvent,)
throttle_classes = (AnnotationThrottle,) throttle_classes = (BurstAnonRateThrottle, AnnotationThrottle,)
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
...@@ -939,7 +940,7 @@ class EMObservationList(APIView): ...@@ -939,7 +940,7 @@ class EMObservationList(APIView):
POST param 'message' POST param 'message'
""" """
permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) permission_classes = (IsAuthenticated,IsAuthorizedForEvent,)
throttle_classes = (AnnotationThrottle,) throttle_classes = (BurstAnonRateThrottle, AnnotationThrottle,)
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
...@@ -1559,7 +1560,7 @@ class VOEventList(APIView): ...@@ -1559,7 +1560,7 @@ class VOEventList(APIView):
"""VOEvent List Resource """VOEvent List Resource
""" """
permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) permission_classes = (IsAuthenticated,IsAuthorizedForEvent,)
throttle_classes = (AnnotationThrottle,) throttle_classes = (BurstAnonRateThrottle, AnnotationThrottle,)
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
...@@ -1693,7 +1694,7 @@ class OperatorSignoffList(APIView): ...@@ -1693,7 +1694,7 @@ class OperatorSignoffList(APIView):
At present, this only supports GET At present, this only supports GET
""" """
permission_classes = (IsAuthenticated,IsAuthorizedForEvent,) permission_classes = (IsAuthenticated,IsAuthorizedForEvent,)
throttle_classes = (AnnotationThrottle,) throttle_classes = (BurstAnonRateThrottle, AnnotationThrottle,)
@event_and_auth_required @event_and_auth_required
def get(self, request, event): def get(self, request, event):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment