From 1b5334dc391ae0aa0adee9995a54b676b60d3e8d Mon Sep 17 00:00:00 2001 From: Michiel Holtkamp Date: Wed, 8 Jan 2020 15:39:54 +0000 Subject: [PATCH] FIX: Check the scopes on the proxy-object, not the proxied object In case an authenticator will set set the scopes on the outer object and not on the inner. --- katka/viewsets.py | 4 ++-- tests/unit/test_viewsets.py | 10 ++++------ tests/unit/viewsets.py | 20 +++++++++++++++++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/katka/viewsets.py b/katka/viewsets.py index 59b59f5..ec4b351 100644 --- a/katka/viewsets.py +++ b/katka/viewsets.py @@ -15,9 +15,9 @@ def initialize_request(self, request, *args, **kwargs): drf_request = super().initialize_request(request, *args, **kwargs) auth_type = AuthType.ANONYMOUS - if getattr(request, "user", None) is not None and not request.user.is_anonymous: + if getattr(drf_request, "user", None) is not None and not drf_request.user.is_anonymous: auth_type = AuthType.GROUPS - elif getattr(request, "scopes", None) is not None: + elif getattr(drf_request, "scopes", None) is not None: auth_type = AuthType.SCOPES # set it on the django HttpRequest diff --git a/tests/unit/test_viewsets.py b/tests/unit/test_viewsets.py index abe9107..ebfbbda 100644 --- a/tests/unit/test_viewsets.py +++ b/tests/unit/test_viewsets.py @@ -20,7 +20,7 @@ def django_request(): class TestUserOrScopeViewSet: def test_anonymous(self, django_request): - vs = ViewSet(django_request) + vs = ViewSet(django_request, None) vs.get_user_restricted_queryset = mock.Mock(return_value=[]) qs = vs.get_queryset() @@ -30,7 +30,7 @@ def test_anonymous(self, django_request): def test_normal_user(self, django_request): django_request.user.is_authenticated = True django_request.user.is_anonymous = False - vs = ViewSet(django_request) + vs = ViewSet(django_request, None) vs.get_user_restricted_queryset = mock.Mock(return_value=[]) qs = vs.get_queryset() @@ -39,8 +39,7 @@ def test_normal_user(self, django_request): @override_settings(SCOPE_FULL_ACCESS="katka") def test_missing_scopes(self, django_request): - django_request.scopes = () - vs = ViewSet(django_request) + vs = ViewSet(django_request, ()) vs.get_user_restricted_queryset = mock.Mock(return_value=[]) with pytest.raises(PermissionDenied): vs.get_queryset() @@ -49,9 +48,8 @@ def test_missing_scopes(self, django_request): @override_settings(SCOPE_FULL_ACCESS="katka") def test_correct_scope(self, django_request): - django_request.scopes = ("katka",) django_request.user.is_authenticated = True - vs = ViewSet(django_request) + vs = ViewSet(django_request, ("katka",)) vs.get_user_restricted_queryset = mock.Mock(return_value=[]) qs = vs.get_queryset() diff --git a/tests/unit/viewsets.py b/tests/unit/viewsets.py index a2d23ad..820bb95 100644 --- a/tests/unit/viewsets.py +++ b/tests/unit/viewsets.py @@ -2,9 +2,27 @@ from tests.unit.models import SimpleModel +class AlwaysAuthenticate: + def __init__(self, scopes): + self.scopes = scopes + + def __call__(self): + """ + Authentication_classes is meant to be a list of classes, not instances, but we need a state + (the scopes), so we pass an instance. This will allow 'creating' an instance. + """ + return self + + def authenticate(self, request, **kwargs): + request.scopes = self.scopes + + return None, "token" + + class ViewSet(UserOrScopeViewSet): model = SimpleModel - def __init__(self, request, **kwargs): + def __init__(self, request, scopes, **kwargs): + self.authentication_classes = [AlwaysAuthenticate(scopes)] self.request = self.initialize_request(request) super().__init__(**kwargs)