diff --git a/open_city_profile/graphene.py b/open_city_profile/graphene.py index 999091c4..36718b37 100644 --- a/open_city_profile/graphene.py +++ b/open_city_profile/graphene.py @@ -1,3 +1,4 @@ +import logging import uuid from functools import partial @@ -194,9 +195,22 @@ def resolve(self, next, root, info, **kwargs): field_name = to_snake_case(getattr(info, "field_name", "")) if not getattr(info.context, "service", False): - raise ServiceNotIdentifiedError("Service not identified") + if settings.ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION: + raise ServiceNotIdentifiedError("Service not identified") + + logging.warning( + "Allowed data field exception would occur: Service not identified. Field name: %s", + field_name, + ) if not root.is_field_allowed_for_service(field_name, info.context.service): - raise FieldNotAllowedError("Field is not allowed for service.") + if settings.ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION: + raise FieldNotAllowedError("Field is not allowed for service.") + + logging.warning( + "Allowed data field exception would occur. Field (%s) is not allowed for service %s.", + field_name, + info.context.service, + ) return next(root, info, **kwargs) diff --git a/open_city_profile/settings.py b/open_city_profile/settings.py index 620af35d..af7057ac 100644 --- a/open_city_profile/settings.py +++ b/open_city_profile/settings.py @@ -50,6 +50,7 @@ AUDIT_LOG_LOGGER_FILENAME=(str, ""), AUDIT_LOG_TO_DB_ENABLED=(bool, False), OPEN_CITY_PROFILE_LOG_LEVEL=(str, None), + ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION=(bool, False), ENABLE_GRAPHIQL=(bool, False), ENABLE_GRAPHQL_INTROSPECTION=(bool, False), GRAPHQL_QUERY_DEPTH_LIMIT=(int, 12), @@ -169,6 +170,8 @@ ENABLE_GRAPHQL_INTROSPECTION = env("ENABLE_GRAPHQL_INTROSPECTION") GRAPHQL_QUERY_DEPTH_LIMIT = env("GRAPHQL_QUERY_DEPTH_LIMIT") +ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION = env("ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION") + INSTALLED_APPS = [ "helusers.apps.HelusersConfig", "open_city_profile.apps.OpenCityProfileAdminConfig", diff --git a/open_city_profile/tests/conftest.py b/open_city_profile/tests/conftest.py index 44b45793..8a8d8e27 100644 --- a/open_city_profile/tests/conftest.py +++ b/open_city_profile/tests/conftest.py @@ -215,3 +215,8 @@ def unix_timestamp_now(): @pytest.fixture(params=[None, ""]) def empty_string_value(request): return request.param + + +@pytest.fixture(autouse=True) +def enable_allowed_data_fields_restriction(settings): + settings.ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION = True diff --git a/profiles/tests/test_allowed_data_field_restriction_flag.py b/profiles/tests/test_allowed_data_field_restriction_flag.py new file mode 100644 index 00000000..4cc1fe5d --- /dev/null +++ b/profiles/tests/test_allowed_data_field_restriction_flag.py @@ -0,0 +1,59 @@ +from unittest import mock + +from profiles.tests.factories import ProfileFactory, SensitiveDataFactory +from services.tests.factories import AllowedDataFieldFactory, ServiceConnectionFactory + + +def test_enable_allowed_data_fields_restriction_flag_false_shows_data( + user_gql_client, service, settings +): + settings.ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION = False + profile = ProfileFactory(user=user_gql_client.user) + ServiceConnectionFactory(profile=profile, service=service) + service.allowed_data_fields.add(AllowedDataFieldFactory(field_name="name")) + SensitiveDataFactory(profile=profile) + + query = """ + { + myProfile { + firstName + sensitivedata { + ssn + } + } + } + """ + + executed = user_gql_client.execute(query, service=service) + + assert executed["data"]["myProfile"]["firstName"] == profile.first_name + assert ( + executed["data"]["myProfile"]["sensitivedata"]["ssn"] + == profile.sensitivedata.ssn + ) + + +@mock.patch("logging.warning") +def test_enable_allowed_data_fields_restriction_flag_logs_warning_if_access_to_restricted_field( + mock_log, user_gql_client, service, settings +): + settings.ENABLE_ALLOWED_DATA_FIELDS_RESTRICTION = False + profile = ProfileFactory(user=user_gql_client.user) + ServiceConnectionFactory(profile=profile, service=service) + service.allowed_data_fields.add(AllowedDataFieldFactory(field_name="name")) + SensitiveDataFactory(profile=profile) + + query = """ + { + myProfile { + firstName + sensitivedata { + ssn + } + } + } + """ + + user_gql_client.execute(query, service=service) + + assert mock_log.call_count == 1