Parcourir la source

fix(api): skip authentication for auth action redirects, fixes #494

Peter Thomassen il y a 4 ans
Parent
commit
52dff2060a

+ 2 - 1
api/api/settings_quick_test.py

@@ -26,7 +26,8 @@ CACHES = {
 }
 
 REST_FRAMEWORK['PAGE_SIZE'] = 20
-REST_FRAMEWORK['DEFAULT_THROTTLE_CLASSES'] = []
+REST_FRAMEWORK['DEFAULT_THROTTLE_CLASSES'] = ['rest_framework.throttling.UserRateThrottle']
+REST_FRAMEWORK['DEFAULT_THROTTLE_RATES'] = {'user': '1000/s'}
 
 # Carry email backend connection over to test mail outbox
 CELERY_EMAIL_MESSAGE_EXTRA_ATTRIBUTES = ['connection']

+ 5 - 0
api/desecapi/tests/test_user_management.py

@@ -506,6 +506,11 @@ class NoUserAccountTestCase(UserLifeCycleTestCase):
     def test_home(self):
         self.assertResponse(self.client.get(reverse('v1:root')), status.HTTP_200_OK)
 
+    def test_authenticated_action_redirect_with_invalid_code(self):
+        # This tests that the code is not processed when Accept: text/html is not set (redirect without further ado)
+        confirmation_link = self.reverse('v1:confirm-activate-account', code='foobar')
+        self.assertConfirmationLinkRedirect(confirmation_link)
+
     def test_registration(self):
         self._test_registration(password=self.random_password())
 

+ 11 - 6
api/desecapi/views.py

@@ -593,13 +593,23 @@ class AuthenticatedActionView(generics.GenericAPIView):
     """
     Abstract class. Deserializes the given payload according the serializers specified by the view extending
     this class. If the `serializer.is_valid`, `act` is called on the action object.
+
+    Summary of the behavior depending on HTTP method and Accept: header:
+
+                        GET	                                POST                other method
+    Accept: text/html	forward to `self.html_url` if any   perform action      405 Method Not Allowed
+    else                HTTP 406 Not Acceptable             perform action      405 Method Not Allowed
     """
     action = None
-    authentication_classes = (auth.AuthenticatedBasicUserActionAuthentication,)
     html_url = None  # Redirect GET requests to this webapp GUI URL
     http_method_names = ['get', 'post']  # GET is for redirect only
     renderer_classes = [JSONRenderer, StaticHTMLRenderer]
 
+    @property
+    def authentication_classes(self):
+        # This prevents both code evaluation and user-specific throttling when we only want a redirect
+        return () if self.request.method in SAFE_METHODS else (auth.AuthenticatedBasicUserActionAuthentication,)
+
     @property
     def throttle_scope(self):
         return 'account_management_passive' if self.request.method in SAFE_METHODS else 'account_management_active'
@@ -611,11 +621,6 @@ class AuthenticatedActionView(generics.GenericAPIView):
             'validity_period': self.get_serializer_class().validity_period,
         }
 
-    def perform_authentication(self, request):
-        # Delay authentication until request.auth or request.user is first accessed.
-        # This allows returning a redirect or status 405 without validating the action code.
-        pass
-
     def get(self, request, *args, **kwargs):
         # Redirect browsers to frontend if available
         is_redirect = (request.accepted_renderer.format == 'html') and self.html_url is not None