From df741b7b7c0e4cd666bdd633b1342b2788107b42 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Mon, 6 May 2024 11:39:49 +0200 Subject: [PATCH 1/3] patch security leak in settings view --- backend/users/serializers.py | 3 +-- backend/users/tests/test_user_serializer.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/backend/users/serializers.py b/backend/users/serializers.py index 28b04e199..d94505dd7 100644 --- a/backend/users/serializers.py +++ b/backend/users/serializers.py @@ -12,14 +12,13 @@ class Meta: class CustomUserDetailsSerializer(UserDetailsSerializer): - is_admin = serializers.BooleanField(source='is_staff') + is_admin = serializers.BooleanField(source='is_staff', read_only=True) profile = UserProfileSerializer() class Meta(UserDetailsSerializer.Meta): fields = ('id', 'username', 'email', 'saml', 'download_limit', 'is_admin', 'profile') - def update(self, instance, validated_data): profile_data = validated_data.pop('profile', None) diff --git a/backend/users/tests/test_user_serializer.py b/backend/users/tests/test_user_serializer.py index 2e072f6c9..7b0e3949d 100644 --- a/backend/users/tests/test_user_serializer.py +++ b/backend/users/tests/test_user_serializer.py @@ -44,3 +44,16 @@ def test_user_updates(auth_client): assert response.status_code == 200 assert not search_history_enabled() + +def test_readonly_fields(auth_client): + ''' + Test that is_admin is readonly + ''' + + route = '/users/user/' + details = lambda: auth_client.get(route) + is_admin = lambda: details().data.get('is_admin') + + assert not is_admin() + response = auth_client.patch(route, {'is_admin': True}, content_type='application/json') + assert not is_admin() From c482100126b4942ea6d1f0a2d8d986882c8e639b Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Mon, 6 May 2024 12:00:47 +0200 Subject: [PATCH 2/3] remove option to PUT search history --- backend/api/tests/test_api_views.py | 42 +++++++++-------------------- backend/api/views.py | 4 +-- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/backend/api/tests/test_api_views.py b/backend/api/tests/test_api_views.py index e207dedf5..c4a6aef18 100644 --- a/backend/api/tests/test_api_views.py +++ b/backend/api/tests/test_api_views.py @@ -1,47 +1,29 @@ from datetime import datetime from addcorpus.models import Corpus from rest_framework.status import is_success - -def mock_query_data(user, corpus_name): - return { - 'aborted': False, - 'corpus': corpus_name, - 'user': user.id, - 'started': datetime.now().isoformat(), - 'completed': datetime.now().isoformat(), - 'query_json': { - "queryText": "example", - "filters": [], - "sortAscending": False - }, - 'total_results': 10, - 'transferred': 0, - } +from api.models import Query +from visualization.query import MATCH_ALL def test_search_history_view(admin_user, admin_client): - corpus = Corpus.objects.create(name = 'mock-corpus') - # get search history response = admin_client.get('/api/search_history/') assert is_success(response.status_code) assert len(response.data) == 0 - # add a query to search history - data = mock_query_data(admin_user, 'mock-corpus') - response = admin_client.post('/api/search_history/', data, content_type='application/json') - assert is_success(response.status_code) - - # get search history again - response = admin_client.get('/api/search_history/') - assert is_success(response.status_code) - assert len(response.data) == 1 - def test_delete_search_history(auth_client, auth_user, db): mock_corpus = 'mock-corpus' corpus = Corpus.objects.create(name = mock_corpus) - query = mock_query_data(auth_user, mock_corpus) - auth_client.post('/api/search_history/', query, content_type='application/json') + Query.objects.create( + user=auth_user, + corpus=corpus, + query_json = {'es_query': MATCH_ALL}, + started=datetime.now(), + completed=datetime.now(), + total_results=10, + transferred=10, + aborted=False, + ) assert len(auth_user.queries.all()) == 1 diff --git a/backend/api/views.py b/backend/api/views.py index b35a86bee..d2cec0541 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -12,7 +12,7 @@ logger = logging.getLogger() -class QueryViewset(viewsets.ModelViewSet): +class QueryViewset(viewsets.ReadOnlyModelViewSet): ''' Access search history ''' @@ -45,7 +45,7 @@ def post(self, request, *args, **kwargs): results = [celery_app.AsyncResult(id=task_id) for task_id in task_ids] if not all(results): raise APIException(detail='Could not get task data') - + if any(result.state == 'FAILURE' for result in results): raise APIException(detail='Task failed') From 8dee2aa2127cfe78bbff2f05ef05355dd891b020 Mon Sep 17 00:00:00 2001 From: Luka van der Plas Date: Mon, 6 May 2024 12:01:24 +0200 Subject: [PATCH 3/3] update version number --- CITATION.cff | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 9001acf69..fe027f61d 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -35,5 +35,5 @@ keywords: - elasticsearch - natural language processing license: MIT -version: 5.6.1 -date-released: '2024-05-03' +version: 5.6.2 +date-released: '2024-05-06' diff --git a/package.json b/package.json index c98faf984..1cbb86ade 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "i-analyzer", - "version": "5.6.1", + "version": "5.6.2", "license": "MIT", "scripts": { "postinstall": "yarn install-back && yarn install-front",