From 55dc86ed4de51151ede426b7196aa575c565fecc Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 1 Oct 2024 15:23:39 +0200 Subject: [PATCH] :white_check_mark: [#4398] Tests for submission start with initial data reference --- ...ce_and_request_exception_raises_error.yaml | 58 +++++ ...ata_reference_user_is_owner_of_object.yaml | 106 ++++++++ .../tests/test_start_submission.py | 230 +++++++++++++++--- 3 files changed, 365 insertions(+), 29 deletions(-) create mode 100644 src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_and_request_exception_raises_error.yaml create mode 100644 src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_user_is_owner_of_object.yaml diff --git a/src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_and_request_exception_raises_error.yaml b/src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_and_request_exception_raises_error.yaml new file mode 100644 index 0000000000..9c612ed12b --- /dev/null +++ b/src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_and_request_exception_raises_error.yaml @@ -0,0 +1,58 @@ +interactions: +- request: + body: '{"type": "http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e", + "record": {"typeVersion": 1, "data": {"bsn": "111222333", "foo": "bar"}, "startAt": + "2024-10-01"}}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Authorization: + - Token 7657474c3d75f56ae0abd0d1bf7994b09964dca9 + Connection: + - keep-alive + Content-Crs: + - EPSG:4326 + Content-Length: + - '194' + Content-Type: + - application/json + User-Agent: + - python-requests/2.32.2 + method: POST + uri: http://localhost:8002/api/v2/objects + response: + body: + string: '{"url":"http://objects-web:8000/api/v2/objects/d9451574-1218-41b5-96fa-0da952260306","uuid":"d9451574-1218-41b5-96fa-0da952260306","type":"http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e","record":{"index":1,"typeVersion":1,"data":{"bsn":"111222333","foo":"bar"},"geometry":null,"startAt":"2024-10-01","endAt":null,"registrationAt":"2024-10-01","correctionFor":null,"correctedBy":null}}' + headers: + Allow: + - GET, POST, HEAD, OPTIONS + Connection: + - keep-alive + Content-Crs: + - EPSG:4326 + Content-Length: + - '422' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 01 Oct 2024 13:20:17 GMT + Location: + - http://localhost:8002/api/v2/objects/d9451574-1218-41b5-96fa-0da952260306 + Referrer-Policy: + - same-origin + Server: + - nginx/1.27.0 + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +version: 1 diff --git a/src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_user_is_owner_of_object.yaml b/src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_user_is_owner_of_object.yaml new file mode 100644 index 0000000000..816cedfa6e --- /dev/null +++ b/src/openforms/submissions/tests/data/vcr_cassettes/SubmissionStartTests/SubmissionStartTests.test_start_submission_with_initial_data_reference_user_is_owner_of_object.yaml @@ -0,0 +1,106 @@ +interactions: +- request: + body: '{"type": "http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e", + "record": {"typeVersion": 1, "data": {"bsn": "111222333", "foo": "bar"}, "startAt": + "2024-10-01"}}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Authorization: + - Token 7657474c3d75f56ae0abd0d1bf7994b09964dca9 + Connection: + - keep-alive + Content-Crs: + - EPSG:4326 + Content-Length: + - '194' + Content-Type: + - application/json + User-Agent: + - python-requests/2.32.2 + method: POST + uri: http://localhost:8002/api/v2/objects + response: + body: + string: '{"url":"http://objects-web:8000/api/v2/objects/c2212239-74d3-4a7f-8388-ac1eee514e1a","uuid":"c2212239-74d3-4a7f-8388-ac1eee514e1a","type":"http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e","record":{"index":1,"typeVersion":1,"data":{"bsn":"111222333","foo":"bar"},"geometry":null,"startAt":"2024-10-01","endAt":null,"registrationAt":"2024-10-01","correctionFor":null,"correctedBy":null}}' + headers: + Allow: + - GET, POST, HEAD, OPTIONS + Connection: + - keep-alive + Content-Crs: + - EPSG:4326 + Content-Length: + - '422' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 01 Oct 2024 13:20:17 GMT + Location: + - http://localhost:8002/api/v2/objects/c2212239-74d3-4a7f-8388-ac1eee514e1a + Referrer-Policy: + - same-origin + Server: + - nginx/1.27.0 + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Authorization: + - Token 7657474c3d75f56ae0abd0d1bf7994b09964dca9 + Connection: + - keep-alive + Content-Crs: + - EPSG:4326 + User-Agent: + - python-requests/2.32.2 + method: GET + uri: http://localhost:8002/api/v2/objects/c2212239-74d3-4a7f-8388-ac1eee514e1a + response: + body: + string: '{"url":"http://objects-web:8000/api/v2/objects/c2212239-74d3-4a7f-8388-ac1eee514e1a","uuid":"c2212239-74d3-4a7f-8388-ac1eee514e1a","type":"http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e","record":{"index":1,"typeVersion":1,"data":{"bsn":"111222333","foo":"bar"},"geometry":null,"startAt":"2024-10-01","endAt":null,"registrationAt":"2024-10-01","correctionFor":null,"correctedBy":null}}' + headers: + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Connection: + - keep-alive + Content-Crs: + - EPSG:4326 + Content-Length: + - '422' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Date: + - Tue, 01 Oct 2024 13:20:17 GMT + Referrer-Policy: + - same-origin + Server: + - nginx/1.27.0 + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openforms/submissions/tests/test_start_submission.py b/src/openforms/submissions/tests/test_start_submission.py index 4ed3579abb..e8bd367055 100644 --- a/src/openforms/submissions/tests/test_start_submission.py +++ b/src/openforms/submissions/tests/test_start_submission.py @@ -19,6 +19,7 @@ from django.test import override_settings, tag +from requests.exceptions import RequestException from rest_framework import status from rest_framework.reverse import reverse, reverse_lazy from rest_framework.test import APITestCase @@ -241,22 +242,90 @@ def test_start_submission_with_prefill(self, mock_logevent): SubmissionValueVariableSources.prefill, prefilled_variable.source ) - def test_start_submission_with_initial_data_reference(self): + @tag("gh-4398") + def test_start_submission_with_initial_data_reference_user_is_owner_of_object( + self, + ): + objects_api_group_used = ObjectsAPIGroupConfigFactory.create( + for_test_docker_compose=True + ) + with get_objects_client(objects_api_group_used) as client: + object = client.create_object( + record_data=prepare_data_for_registration( + data={"bsn": "111222333", "foo": "bar"}, + objecttype_version=1, + ), + objecttype_url="http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e", + ) + + object_ref = object["uuid"] + + # An objects API backend with a different API group + FormRegistrationBackendFactory.create( + form=self.form, + backend="objects_api", + options={ + "version": 2, + "objecttype": "3edfdaf7-f469-470b-a391-bb7ea015bd6f", + "objects_api_group": 5, + "objecttype_version": 1, + }, + ) + # Another backend that should be ignored + FormRegistrationBackendFactory.create(form=self.form, backend="email") + # The backend that should be used to perform the check + FormRegistrationBackendFactory.create( + form=self.form, + backend="objects_api", + options={ + "version": 2, + "objecttype": "3edfdaf7-f469-470b-a391-bb7ea015bd6f", + "objects_api_group": objects_api_group_used.pk, + "objecttype_version": 1, + }, + ) + + session = self.client.session + session[FORM_AUTH_SESSION_KEY] = { + "plugin": "digid", + "attribute": AuthAttribute.bsn, + "value": "111222333", + } + session.save() + body = { "form": f"http://testserver.com{self.form_url}", "formUrl": "http://testserver.com/my-form", - "initialDataReference": "of-or-3452fre3", + "initialDataReference": object_ref, } response = self.client.post(self.endpoint, body) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + submission = Submission.objects.get() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(submission.initial_data_reference, object_ref) + + @tag("gh-4398") + def test_start_submission_with_initial_data_reference_without_auth_info_raises_error( + self, + ): + body = { + "form": f"http://testserver.com{self.form_url}", + "formUrl": "http://testserver.com/my-form", + "initialDataReference": "of-or-3452fre3", + } + + response = self.client.post(self.endpoint, body) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual( - submission.initial_data_reference, body["initialDataReference"] + response.json()["detail"], "Cannot pass data reference as anonymous user" ) + self.assertFalse(Submission.objects.exists()) + @tag("gh-4398") def test_start_submission_with_initial_data_reference_and_anonymous_raises_error( self, ): @@ -275,10 +344,10 @@ def test_start_submission_with_initial_data_reference_and_anonymous_raises_error ) self.assertFalse(Submission.objects.exists()) + @tag("gh-4398") def test_start_submission_with_initial_data_reference_and_not_owner_of_object_raises_error( self, ): - # objects_api_group_unused = ObjectsAPIGroupConfigFactory.create() objects_api_group_used = ObjectsAPIGroupConfigFactory.create( for_test_docker_compose=True ) @@ -293,38 +362,64 @@ def test_start_submission_with_initial_data_reference_and_not_owner_of_object_ra object_ref = object["uuid"] - # unused_objects_backend = FormRegistrationBackendFactory.create( - # form=self.form, - # backend="objects_api", - # options={ - # "version": 2, - # "objecttype": "3edfdaf7-f469-470b-a391-bb7ea015bd6f", - # "iot_attachment": "", - # "objects_api_group": objects_api_group_unused.pk, - # # TODO these are probably not needed? - # # "variables_mapping": [], - # # "iot_submission_csv": "", - # "objecttype_version": 1, - # # "geometry_variable_key": "", - # # "iot_submission_report": "", - # # "upload_submission_csv": False, - # # "update_existing_object": True, - # }, - # ) - objects_backend_incorrect_api_group = FormRegistrationBackendFactory.create( + # The backend that should be used to perform the check + FormRegistrationBackendFactory.create( form=self.form, backend="objects_api", options={ "version": 2, "objecttype": "3edfdaf7-f469-470b-a391-bb7ea015bd6f", - "objects_api_group": 5, + "objects_api_group": objects_api_group_used.pk, "objecttype_version": 1, }, ) - irrelevant_backend = FormRegistrationBackendFactory.create( - form=self.form, backend="email" + + session = self.client.session + session[FORM_AUTH_SESSION_KEY] = { + "plugin": "digid", + "attribute": AuthAttribute.bsn, + "value": "123456782", + } + session.save() + + body = { + "form": f"http://testserver.com{self.form_url}", + "formUrl": "http://testserver.com/my-form", + "initialDataReference": object_ref, + } + + response = self.client.post(self.endpoint, body) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + response.json()["detail"], "User is not the owner of the referenced object" + ) + self.assertFalse(Submission.objects.exists()) + + @tag("gh-4398") + @patch( + "openforms.contrib.objects_api.clients.objects.ObjectsClient.get_object", + side_effect=RequestException, + ) + def test_start_submission_with_initial_data_reference_and_request_exception_raises_error( + self, mock_get_object + ): + objects_api_group_used = ObjectsAPIGroupConfigFactory.create( + for_test_docker_compose=True ) - objects_backend = FormRegistrationBackendFactory.create( + with get_objects_client(objects_api_group_used) as client: + object = client.create_object( + record_data=prepare_data_for_registration( + data={"bsn": "111222333", "foo": "bar"}, + objecttype_version=1, + ), + objecttype_url="http://objecttypes-web:8000/api/v2/objecttypes/8faed0fa-7864-4409-aa6d-533a37616a9e", + ) + + object_ref = object["uuid"] + + # The backend that should be used to perform the check + FormRegistrationBackendFactory.create( form=self.form, backend="objects_api", options={ @@ -353,10 +448,55 @@ def test_start_submission_with_initial_data_reference_and_not_owner_of_object_ra self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual( - response.json()["detail"], "User is not the owner of the referenced object" + response.json()["detail"], + "Could not fetch object from initial data reference", + ) + self.assertFalse(Submission.objects.exists()) + + @tag("gh-4398") + def test_start_submission_with_initial_data_reference_and_no_objects_service_configured_raises_error( + self, + ): + objects_api_group_used = ObjectsAPIGroupConfigFactory.create( + objects_service=None, + ) + + # The backend that should be used to perform the check + FormRegistrationBackendFactory.create( + form=self.form, + backend="objects_api", + options={ + "version": 2, + "objecttype": "3edfdaf7-f469-470b-a391-bb7ea015bd6f", + "objects_api_group": objects_api_group_used.pk, + "objecttype_version": 1, + }, + ) + + session = self.client.session + session[FORM_AUTH_SESSION_KEY] = { + "plugin": "digid", + "attribute": AuthAttribute.bsn, + "value": "123456782", + } + session.save() + + body = { + "form": f"http://testserver.com{self.form_url}", + "formUrl": "http://testserver.com/my-form", + "initialDataReference": "1234", + } + + response = self.client.post(self.endpoint, body) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + response.json()["detail"], + "Could not fetch object from initial data reference", ) self.assertFalse(Submission.objects.exists()) + @tag("gh-4398") def test_start_submission_with_initial_data_reference_and_no_backends_configured_raises_error( self, ): @@ -384,3 +524,35 @@ def test_start_submission_with_initial_data_reference_and_no_backends_configured "Could not fetch object from initial data reference", ) self.assertFalse(Submission.objects.exists()) + + @tag("gh-4398") + def test_start_submission_with_initial_data_reference_and_backend_without_options_raises_error( + self, + ): + ObjectsAPIGroupConfigFactory.create(for_test_docker_compose=True) + FormRegistrationBackendFactory.create( + form=self.form, backend="objects_api", options={} + ) + + session = self.client.session + session[FORM_AUTH_SESSION_KEY] = { + "plugin": "digid", + "attribute": AuthAttribute.bsn, + "value": "123456782", + } + session.save() + + body = { + "form": f"http://testserver.com{self.form_url}", + "formUrl": "http://testserver.com/my-form", + "initialDataReference": "of-or-3452fre3", + } + + response = self.client.post(self.endpoint, body) + + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + response.json()["detail"], + "Could not fetch object from initial data reference", + ) + self.assertFalse(Submission.objects.exists())