Skip to content
This repository has been archived by the owner on Mar 15, 2018. It is now read-only.

Commit

Permalink
Introduce Apps:APIUnthrottled permission to prevent select API users …
Browse files Browse the repository at this point in the history
…from being throttled (bug 848869)
  • Loading branch information
chuckharmston committed Apr 9, 2013
1 parent 5be330a commit f74f1a8
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
17 changes: 10 additions & 7 deletions mkt/api/base.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from tastypie.exceptions import ImmediateHttpResponse, UnsupportedFormat from tastypie.exceptions import ImmediateHttpResponse, UnsupportedFormat
from tastypie.resources import Resource, ModelResource from tastypie.resources import Resource, ModelResource


from access import acl
import commonware.log import commonware.log
from translations.fields import PurifiedField, TranslatedField from translations.fields import PurifiedField, TranslatedField


Expand Down Expand Up @@ -142,13 +143,15 @@ def throttle_check(self, request):
Mostly a hook, this uses class assigned to ``throttle`` from Mostly a hook, this uses class assigned to ``throttle`` from
``Resource._meta``. ``Resource._meta``.
""" """
identifiers = [a.get_identifier(request) for a in self._auths()] # Never throttle users with Apps:APIUnthrottled.

if not acl.action_allowed(request, 'Apps', 'APIUnthrottled'):
# Check to see if they should be throttled. identifiers = [a.get_identifier(request) for a in self._auths()]
if any(self._meta.throttle.should_be_throttled(identifier)
for identifier in identifiers): # Check to see if they should be throttled.
# Throttle limit exceeded. if any(self._meta.throttle.should_be_throttled(identifier)
raise ImmediateHttpResponse(response=HttpTooManyRequests()) for identifier in identifiers):
# Throttle limit exceeded.
raise ImmediateHttpResponse(response=HttpTooManyRequests())


def log_throttled_access(self, request): def log_throttled_access(self, request):
""" """
Expand Down
57 changes: 56 additions & 1 deletion mkt/api/tests/test_base.py
Original file line number Original file line Diff line number Diff line change
@@ -1,17 +1,23 @@
import json import json
import urllib import urllib


from django.contrib.auth.models import User

from mock import patch from mock import patch
from nose.tools import eq_ from nose.tools import eq_


from tastypie import http from tastypie import http
from tastypie.authorization import Authorization from tastypie.authorization import Authorization
from tastypie.exceptions import ImmediateHttpResponse from tastypie.exceptions import ImmediateHttpResponse
from tastypie.throttle import BaseThrottle
from test_utils import RequestFactory from test_utils import RequestFactory


from access.middleware import ACLMiddleware
from amo.tests import TestCase from amo.tests import TestCase
from mkt.api.base import MarketplaceResource from mkt.api.base import MarketplaceResource
from mkt.api.http import HttpTooManyRequests
from mkt.api.serializers import Serializer from mkt.api.serializers import Serializer
from mkt.site.fixtures import fixture




class SampleResource(MarketplaceResource): class SampleResource(MarketplaceResource):
Expand All @@ -31,7 +37,7 @@ def _encode_data(self, data, content_type):
return urllib.urlencode(data) return urllib.urlencode(data)




class TestMarketplace(TestCase): class TestEncoding(TestCase):


def setUp(self): def setUp(self):
self.resource = SampleResource() self.resource = SampleResource()
Expand Down Expand Up @@ -70,3 +76,52 @@ def test_form_encoded(self, obj_create):
content_type='application/x-www-form-urlencoded') content_type='application/x-www-form-urlencoded')
self.resource.dispatch('list', request) self.resource.dispatch('list', request)
eq_(obj_create.call_args[0][0].data, {'foo': 'bar'}) eq_(obj_create.call_args[0][0].data, {'foo': 'bar'})


class ThrottleResource(MarketplaceResource):

class Meta(object):
authorization = Authorization()
throttle = BaseThrottle()


class TestThrottling(TestCase):
fixtures = fixture('user_2519')

def setUp(self):
self.resource = ThrottleResource()
self.request = RequestFactory().post('/')
self.user = User.objects.get(pk=2519)
self.request.user = self.user
self.throttle = self.resource._meta.throttle
self.request.META['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
self.mocked_sbt = patch.object(self.throttle, 'should_be_throttled')

def no_throttle_expected(self):
try:
self.resource.throttle_check(self.request)
except ImmediateHttpResponse, e:
if isinstance(e.response, HttpTooManyRequests):
self.fail('Unexpected 429')
raise e

def throttle_expected(self):
with self.assertImmediate(HttpTooManyRequests):
self.resource.throttle_check(self.request)

def test_should_throttle(self):
with self.mocked_sbt as sbt:
sbt.return_value = True
self.throttle_expected()

def test_shouldnt_throttle(self):
with self.mocked_sbt as sbt:
sbt.return_value = False
self.no_throttle_expected()

def test_unthrottled_user(self):
self.grant_permission(self.user.get_profile(), 'Apps:APIUnthrottled')
ACLMiddleware().process_request(self.request)
with self.mocked_sbt as sbt:
sbt.return_value = True
self.no_throttle_expected()

0 comments on commit f74f1a8

Please sign in to comment.