From 97e2ffb5693f244fa68bf16a87d990699a032864 Mon Sep 17 00:00:00 2001 From: Olivier Leger Date: Mon, 30 Oct 2023 11:19:15 -0400 Subject: [PATCH] Separate tests with required auth and not required auth for OpenRosa endpoints --- .../api/tests/viewsets/test_xform_list_api.py | 357 +++++++++++------- 1 file changed, 214 insertions(+), 143 deletions(-) diff --git a/onadata/apps/api/tests/viewsets/test_xform_list_api.py b/onadata/apps/api/tests/viewsets/test_xform_list_api.py index f988f9caf..9ee6472fc 100644 --- a/onadata/apps/api/tests/viewsets/test_xform_list_api.py +++ b/onadata/apps/api/tests/viewsets/test_xform_list_api.py @@ -5,6 +5,7 @@ from django.conf import settings from django_digest.test import DigestAuth from guardian.shortcuts import assign_perm +from rest_framework.reverse import reverse from onadata.apps.api.tests.viewsets.test_abstract_viewset import ( TestAbstractViewSet @@ -17,14 +18,197 @@ from onadata.apps.logger.models.xform import XForm -class TestXFormListApi(TestAbstractViewSet): +class TestXFormListApiBase(TestAbstractViewSet): + def setUp(self): super().setUp() self.view = XFormListApi.as_view({ - "get": "list" + 'get': 'list' }) self.publish_xls_form() + def _load_metadata(self, xform=None): + data_value = "screenshot.png" + data_type = 'media' + fixture_dir = os.path.join( + settings.ONADATA_DIR, "apps", "main", "tests", "fixtures", + "transportation" + ) + path = os.path.join(fixture_dir, data_value) + xform = xform or self.xform + + self._add_form_metadata(xform, data_type, data_value, path) + + +class TestXFormListApiWithoutAuthRequired(TestXFormListApiBase): + + """ + Tests should point to `https://kc//*` + """ + + def setUp(self): + super().setUp() + self.xform_without_auth = self.xform + self.xform_without_auth.require_auth = False + self.xform_without_auth.save(update_fields=['require_auth']) + + data = { + 'owner': self.user.username, + 'public': False, + 'public_data': False, + 'description': 'transportation_with_attachment', + 'downloadable': True, + 'encrypted': False, + 'id_string': 'transportation_with_attachment', + 'title': 'transportation_with_attachment', + } + + path = os.path.join( + settings.ONADATA_DIR, + 'apps', + 'main', + 'tests', + 'fixtures', + 'transportation', + 'transportation_with_attachment.xls', + ) + self.publish_xls_form(data=data, path=path) + self.assertNotEqual(self.xform.pk, self.xform_without_auth) + self.assertEqual(XForm.objects.all().count(), 2) + self.assertEqual(XForm.objects.filter(require_auth=False).count(), 1) + + def test_get_xform_list_as_anonymous_user(self): + + request = self.factory.get('/') + response = self.view(request, username=self.user.username) + self.assertEqual(response.status_code, 200) + + path = os.path.join( + os.path.dirname(__file__), '..', 'fixtures', 'formList.xml' + ) + # Response should contain only xform + with open(path, 'r') as f: + form_list_xml = f.read().strip() + data = { + 'hash': self.xform_without_auth.md5_hash, + 'pk': self.xform_without_auth.pk, + } + content = response.render().content + self.assertEqual(content.decode('utf-8'), form_list_xml % data) + self.assertTrue(response.has_header('X-OpenRosa-Version')) + self.assertTrue( + response.has_header('X-OpenRosa-Accept-Content-Length')) + self.assertTrue(response.has_header('Date')) + self.assertEqual(response['Content-Type'], + 'text/xml; charset=utf-8') + + def test_get_xform_list_as_owner(self): + + """ + Same test as `test_get_xform_list_as_anonymous_user()` except + we want the user to be authenticated right away. Do not use Digest, but + session auth. + User should only see their projects that allow data submission without + authentication (like anonymous user) + """ + + # Use session auth + response = self.client.get( + reverse('form-list', kwargs={'username': self.user.username}) + ) + self.assertEqual(response.status_code, 200) + + path = os.path.join( + os.path.dirname(__file__), '..', 'fixtures', 'formList.xml' + ) + # Response should contain only xform + with open(path, 'r') as f: + form_list_xml = f.read().strip() + data = { + 'hash': self.xform_without_auth.md5_hash, + 'pk': self.xform_without_auth.pk, + } + content = response.render().content + self.assertEqual(content.decode('utf-8'), form_list_xml % data) + self.assertTrue(response.has_header('X-OpenRosa-Version')) + self.assertTrue( + response.has_header('X-OpenRosa-Accept-Content-Length')) + self.assertTrue(response.has_header('Date')) + self.assertEqual(response['Content-Type'], + 'text/xml; charset=utf-8') + + def test_retrieve_xform_manifest_as_owner(self): + + self._load_metadata(self.xform_without_auth) + self.view = XFormListApi.as_view({ + 'get': 'manifest' + }) + request = self.factory.get('/') + response = self.view(request, pk=self.xform_without_auth.pk) + self.assertEqual(response.status_code, 401) + response = self.view( + request, pk=self.xform_without_auth.pk, username=self.user.username + ) + self.assertEqual(response.status_code, 200) + + manifest_xml = ( + '\n' + '' + ' ' + ' screenshot.png' + ' %(hash)s' + ' http://testserver/bob/xformsMedia/%(xform)s/%(pk)s.png' + ' ' + '' + ) + + manifest_xml = re.sub(r'> +<', '><', manifest_xml).strip() + + data = { + 'hash': self.metadata.md5_hash, + 'pk': self.metadata.pk, + 'xform': self.xform_without_auth.pk, + } + + content = response.render().content.decode('utf-8').strip() + self.assertEqual(content, manifest_xml % data) + self.assertTrue(response.has_header('X-OpenRosa-Version')) + self.assertTrue( + response.has_header('X-OpenRosa-Accept-Content-Length')) + self.assertTrue(response.has_header('Date')) + self.assertEqual(response['Content-Type'], 'text/xml; charset=utf-8') + + def test_retrieve_xform_media_as_anonymous_user(self): + + self._load_metadata(self.xform_without_auth) + self.view = XFormListApi.as_view({ + 'get': 'media' + }) + request = self.factory.get('/') + response = self.view( + request, + pk=self.xform_without_auth.pk, + metadata=self.metadata.pk, + format='png', + ) + self.assertEqual(response.status_code, 401) + + response = self.view( + request, + pk=self.xform_without_auth.pk, + username=self.user.username, + metadata=self.metadata.pk, + format='png', + ) + self.assertEqual(response.status_code, 200) + + +class TestXFormListApiWithAuthRequired(TestXFormListApiBase): + + """ + Tests should point to `https://kc/*` + """ + def test_head_xform_list(self): request = self.factory.head('/') response = self.view(request) @@ -84,61 +268,7 @@ def test_get_xform_list_inactive_form(self): self.assertEqual(response['Content-Type'], 'text/xml; charset=utf-8') - def test_get_xform_list_anonymous_user_no_auth_required(self): - - xform_without_auth = self.xform - xform_without_auth.require_auth = False - xform_without_auth.save(update_fields=['require_auth']) - - data = { - 'owner': self.user.username, - 'public': False, - 'public_data': False, - 'description': 'transportation_with_attachment', - 'downloadable': True, - 'encrypted': False, - 'id_string': 'transportation_with_attachment', - 'title': 'transportation_with_attachment', - } - - path = os.path.join( - settings.ONADATA_DIR, - 'apps', - 'main', - 'tests', - 'fixtures', - 'transportation', - 'transportation_with_attachment.xls', - ) - self.publish_xls_form(data=data, path=path) - - self.assertEqual(XForm.objects.all().count(), 2) - self.assertEqual(XForm.objects.filter(require_auth=False).count(), 1) - - request = self.factory.get('/') - response = self.view(request, username=self.user.username) - self.assertEqual(response.status_code, 200) - - path = os.path.join( - os.path.dirname(__file__), '..', 'fixtures', 'formList.xml' - ) - # Response should contain only xform - with open(path, 'r') as f: - form_list_xml = f.read().strip() - data = { - 'hash': xform_without_auth.md5_hash, - 'pk': xform_without_auth.pk, - } - content = response.render().content - self.assertEqual(content.decode('utf-8'), form_list_xml % data) - self.assertTrue(response.has_header('X-OpenRosa-Version')) - self.assertTrue( - response.has_header('X-OpenRosa-Accept-Content-Length')) - self.assertTrue(response.has_header('Date')) - self.assertEqual(response['Content-Type'], - 'text/xml; charset=utf-8') - - def test_get_xform_list_anonymous_user_with_auth_required(self): + def test_get_xform_list_as_anonymous_user(self): request = self.factory.get('/') # Get formList without username requires auth unconditionally response = self.view(request) @@ -282,7 +412,7 @@ def test_get_xform_list_with_formid_parameter(self): def test_retrieve_xform_xml(self): self.view = XFormListApi.as_view({ - "get": "retrieve" + 'get': 'retrieve' }) request = self.factory.head('/') response = self.view(request, pk=self.xform.pk) @@ -305,39 +435,14 @@ def test_retrieve_xform_xml(self): with open(path) as f: form_xml = f.read().strip() - data = {"form_uuid": self.xform.uuid} + data = {'form_uuid': self.xform.uuid} content = response.render().content.decode('utf-8').strip() self.assertEqual(content, form_xml % data) - def _load_metadata(self, xform=None): - data_value = "screenshot.png" - data_type = 'media' - fixture_dir = os.path.join( - settings.ONADATA_DIR, "apps", "main", "tests", "fixtures", - "transportation" - ) - path = os.path.join(fixture_dir, data_value) - xform = xform or self.xform - - self._add_form_metadata(xform, data_type, data_value, path) - - def test_head_xform_manifest(self): - self._load_metadata(self.xform) - self.view = XFormListApi.as_view({ - "get": "manifest" - }) - request = self.factory.head('/') - response = self.view(request, pk=self.xform.pk) - self.assertEqual(response.status_code, 401) - auth = DigestAuth('bob', 'bobbob') - request.META.update(auth(request.META, response)) - response = self.view(request, pk=self.xform.pk) - self.validate_openrosa_head_response(response) - def test_retrieve_xform_manifest(self): self._load_metadata(self.xform) self.view = XFormListApi.as_view({ - "get": "manifest" + 'get': 'manifest' }) request = self.factory.head('/') response = self.view(request, pk=self.xform.pk) @@ -360,36 +465,11 @@ def test_retrieve_xform_manifest(self): manifest_xml = re.sub(r'> +<', '><', manifest_xml).strip() - data = {"hash": self.metadata.md5_hash, "pk": self.metadata.pk, - "xform": self.xform.pk} - content = response.render().content.decode('utf-8').strip() - self.assertEqual(content, manifest_xml % data) - self.assertTrue(response.has_header('X-OpenRosa-Version')) - self.assertTrue( - response.has_header('X-OpenRosa-Accept-Content-Length')) - self.assertTrue(response.has_header('Date')) - self.assertEqual(response['Content-Type'], 'text/xml; charset=utf-8') - - def test_retrieve_xform_manifest_anonymous_user(self): - # Allow anonymous access to manifest - self.xform.require_auth = False - self.xform.save(update_fields=['require_auth']) - - self._load_metadata(self.xform) - self.view = XFormListApi.as_view({ - "get": "manifest" - }) - request = self.factory.get('/') - response = self.view(request, pk=self.xform.pk) - self.assertEqual(response.status_code, 401) - response = self.view(request, pk=self.xform.pk, - username=self.user.username) - self.assertEqual(response.status_code, 200) - - manifest_xml = """ -screenshot.png%(hash)shttp://testserver/bob/xformsMedia/%(xform)s/%(pk)s.png""" # noqa - data = {"hash": self.metadata.md5_hash, "pk": self.metadata.pk, - "xform": self.xform.pk} + data = { + 'hash': self.metadata.md5_hash, + 'pk': self.metadata.pk, + 'xform': self.xform.pk, + } content = response.render().content.decode('utf-8').strip() self.assertEqual(content, manifest_xml % data) self.assertTrue(response.has_header('X-OpenRosa-Version')) @@ -398,77 +478,68 @@ def test_retrieve_xform_manifest_anonymous_user(self): self.assertTrue(response.has_header('Date')) self.assertEqual(response['Content-Type'], 'text/xml; charset=utf-8') - def test_retrieve_xform_manifest_anonymous_user_require_auth(self): + def test_retrieve_xform_manifest_as_anonymous(self): self._load_metadata(self.xform) self.view = XFormListApi.as_view({ - "get": "manifest" + 'get': 'manifest' }) request = self.factory.get('/') - # Require auth - response = self.view(request, pk=self.xform.pk) - self.assertEqual(response.status_code, 401) - # Not auth required but XForm cannot be found except if `required_auth` is True # See `test_retrieve_xform_manifest_anonymous_user()` response = self.view(request, pk=self.xform.pk, username=self.user.username) self.assertEqual(response.status_code, 404) - def test_head_xform_media(self): + def test_head_xform_manifest(self): self._load_metadata(self.xform) self.view = XFormListApi.as_view({ - "get": "media" + 'get': 'manifest' }) request = self.factory.head('/') - response = self.view(request, pk=self.xform.pk, - metadata=self.metadata.pk, format='png') + response = self.view(request, pk=self.xform.pk) self.assertEqual(response.status_code, 401) auth = DigestAuth('bob', 'bobbob') request.META.update(auth(request.META, response)) - response = self.view(request, pk=self.xform.pk, - metadata=self.metadata.pk, format='png') + response = self.view(request, pk=self.xform.pk) self.validate_openrosa_head_response(response) - def test_retrieve_xform_media(self): + def test_head_xform_media(self): self._load_metadata(self.xform) self.view = XFormListApi.as_view({ - "get": "media" + 'get': 'media' }) request = self.factory.head('/') response = self.view(request, pk=self.xform.pk, metadata=self.metadata.pk, format='png') self.assertEqual(response.status_code, 401) auth = DigestAuth('bob', 'bobbob') - request = self.factory.get('/') request.META.update(auth(request.META, response)) response = self.view(request, pk=self.xform.pk, metadata=self.metadata.pk, format='png') - self.assertEqual(response.status_code, 200) - - def test_retrieve_xform_media_anonymous_user(self): - # Allow anonymous access to media - self.xform.require_auth = False - self.xform.save(update_fields=['require_auth']) + self.validate_openrosa_head_response(response) + def test_retrieve_xform_media(self): self._load_metadata(self.xform) self.view = XFormListApi.as_view({ "get": "media" }) - request = self.factory.get('/') + request = self.factory.head('/') response = self.view(request, pk=self.xform.pk, metadata=self.metadata.pk, format='png') self.assertEqual(response.status_code, 401) - + auth = DigestAuth('bob', 'bobbob') + request = self.factory.get('/') + request.META.update(auth(request.META, response)) response = self.view(request, pk=self.xform.pk, - username=self.user.username, metadata=self.metadata.pk, format='png') self.assertEqual(response.status_code, 200) - def test_retrieve_xform_media_anonymous_user_require_auth(self): + def test_retrieve_xform_media_as_anonymous(self): self._load_metadata(self.xform) self.view = XFormListApi.as_view({ - "get": "media" + 'get': 'media' }) request = self.factory.get('/') - response = self.view(request, pk=self.xform.pk, - metadata=self.metadata.pk, format='png') + response = self.view( + request, pk=self.xform.pk, metadata=self.metadata.pk, format='png' + ) self.assertEqual(response.status_code, 401)