Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce XForm meta permissions on the attachment viewset #2178

Merged
merged 3 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions onadata/apps/api/tests/viewsets/test_attachment_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from onadata.apps.logger.import_tools import django_file
from onadata.apps.logger.models.attachment import Attachment
from onadata.apps.logger.models.instance import get_attachment_url
from onadata.apps.main.models.meta_data import MetaData
from onadata.libs.permissions import EditorRole
from onadata.libs.models.share_xform import ShareXForm


def attachment_url(attachment, suffix=None):
Expand Down Expand Up @@ -382,3 +385,34 @@ def test_total_count(self):
'/count', data={"xform": xform_id}, **self.extra)
response = self.count_view(request)
self.assertEqual(response.data['count'], 1)

def test_returned_attachments_is_based_on_form_permissions(self):
# Create a form and make submissions with attachments
self._submit_transport_instance_w_attachment()

formid = self.xform.pk
request = self.factory.get(
'/', data={"xform": formid}, **self.extra)
response = self.list_view(request)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)

user_dave = self._create_user_profile({"username": "dave"}).user
# Enable meta perms
data_value = "editor-minor|dataentry-minor"
MetaData.xform_meta_permission(self.xform, data_value=data_value)

ShareXForm(self.xform, user_dave.username, EditorRole.name)
auth_extra = {
'HTTP_AUTHORIZATION': f'Token {user_dave.auth_token.key}'
}

# Dave user should not be able to view attachments for
# submissions which they did not submit
request = self.factory.get('/', data={"xform": formid}, **auth_extra)
response = self.list_view(request)
self.assertEqual(response.status_code, 200)
# Ensure no submissions are returned for the User
# daves' request as they have not submitted any data
# and meta permissions have been applied to the form
self.assertEqual(len(response.data), 0)
11 changes: 11 additions & 0 deletions onadata/libs/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from onadata.apps.viewer.models import Export
from onadata.libs.utils.numeric import int_or_parse_error
from onadata.libs.utils.common_tags import MEDIA_FILE_TYPES
from onadata.libs.permissions import \
exclude_items_from_queryset_using_xform_meta_perms


class AnonDjangoObjectPermissionFilter(ObjectPermissionsFilter):
Expand Down Expand Up @@ -412,6 +414,15 @@ def filter_queryset(self, request, queryset, view):

queryset = self._xform_filter_queryset(request, queryset, view,
'instance__xform')
# Ensure queryset is filtered by XForm meta permissions
xform_ids = set(
queryset.values_list("instance__xform", flat=True))
for xform_id in xform_ids:
xform = XForm.objects.get(id=xform_id)
user = request.user
queryset = exclude_items_from_queryset_using_xform_meta_perms(
xform, user, queryset)

instance_id = request.query_params.get('instance')
if instance_id:
int_or_parse_error(instance_id,
Expand Down
21 changes: 20 additions & 1 deletion onadata/libs/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

import six
from django.db.models.base import ModelBase
from django.db.models import Q
from guardian.shortcuts import (assign_perm, get_perms, get_users_with_perms,
remove_perm)

from onadata.apps.api.models import OrganizationProfile
from onadata.apps.logger.models import MergedXForm, Project, XForm
from onadata.apps.logger.models import MergedXForm, Project, XForm,\
Attachment
from onadata.apps.logger.models.project import (ProjectGroupObjectPermission,
ProjectUserObjectPermission)
from onadata.apps.logger.models.xform import (XFormGroupObjectPermission,
Expand Down Expand Up @@ -496,6 +498,23 @@ def _check_meta_perms_enabled(xform):
return xform.metadata_set.filter(data_type=XFORM_META_PERMS).count() > 0


def exclude_items_from_queryset_using_xform_meta_perms(
xform, user, queryset):
"""
Exclude instances from the queryset if meta-perms have been enabled
"""
if user.has_perm(CAN_VIEW_XFORM_ALL, xform) or xform.shared_data \
or not _check_meta_perms_enabled(xform):
return queryset
elif user.has_perm(CAN_VIEW_XFORM_DATA, xform):
if queryset.model is Attachment:
return queryset.exclude(
~Q(instance__user=user), instance__xform=xform)
else:
return queryset.exclude(
~Q(user=user), xform=xform)


def filter_queryset_xform_meta_perms(xform, user, instance_queryset):
"""
Check for the specific perms if meta-perms have been enabled
Expand Down