From d0f7120198e6ae198a97aa44ebb97ae0218b42d0 Mon Sep 17 00:00:00 2001 From: uzairr Date: Mon, 1 Jun 2020 15:15:43 +0500 Subject: [PATCH] Restrict cert api to staff and self user --- .../certificates/apis/v0/permissions.py | 26 ++++++++++++ .../certificates/apis/v0/tests/test_views.py | 40 +++++++++++++++++++ lms/djangoapps/certificates/apis/v0/views.py | 6 ++- 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 lms/djangoapps/certificates/apis/v0/permissions.py diff --git a/lms/djangoapps/certificates/apis/v0/permissions.py b/lms/djangoapps/certificates/apis/v0/permissions.py new file mode 100644 index 0000000000..a666071904 --- /dev/null +++ b/lms/djangoapps/certificates/apis/v0/permissions.py @@ -0,0 +1,26 @@ +""" +This module provides a custom DRF Permission class for supporting the course certificates +to Admin users and users whom they belongs to. +""" + +from django.contrib.auth.models import User +from rest_framework.permissions import BasePermission + +from openedx.core.djangoapps.user_api.models import UserPreference + + +class IsOwnerOrPublicCertificates(BasePermission): + """ + Method that will ensure whether the requesting user is staff or + the user whom the certificate belongs to + """ + def has_permission(self, request, view): + requested_profile_username = view.kwargs.get('username') + # check whether requesting user is the owner of certs or not + if request.user.username == requested_profile_username: + return True + + user = User.objects.get(username=requested_profile_username) + cert_privacy = UserPreference.get_value(user, 'visibility.course_certificates') + + return cert_privacy == 'all_users' diff --git a/lms/djangoapps/certificates/apis/v0/tests/test_views.py b/lms/djangoapps/certificates/apis/v0/tests/test_views.py index 9cabe83885..b99eebdf15 100644 --- a/lms/djangoapps/certificates/apis/v0/tests/test_views.py +++ b/lms/djangoapps/certificates/apis/v0/tests/test_views.py @@ -229,6 +229,46 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC self.assertEqual(resp.status_code, status.HTTP_200_OK) self.assertEqual(len(resp.data), 1) + def test_owner_can_access_its_certs(self): + """ + Tests the owner of the certs can access the certificate list api + """ + self.student.profile.year_of_birth = 1977 + self.student.profile.save() + UserPreferenceFactory.build( + user=self.student, + key='visibility.course_certificates', + value='private', + ).save() + + resp = self.get_response(AuthType.session, requesting_user=self.student) + self.assertEqual(resp.status_code, status.HTTP_200_OK) + + # verifies that other than owner cert list api is not accessible + resp = self.get_response(AuthType.session, requesting_user=self.other_student) + self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN) + + def test_public_profile_certs_is_accessible(self): + """ + Tests the public profile certs can be accessed by all users + """ + self.student.profile.year_of_birth = 1977 + self.student.profile.save() + UserPreferenceFactory.build( + user=self.student, + key='visibility.course_certificates', + value='all_users', + ).save() + + resp = self.get_response(AuthType.session, requesting_user=self.student) + self.assertEqual(resp.status_code, status.HTTP_200_OK) + + resp = self.get_response(AuthType.session, requesting_user=self.other_student) + self.assertEqual(resp.status_code, status.HTTP_200_OK) + + resp = self.get_response(AuthType.session, requesting_user=self.global_staff) + self.assertEqual(resp.status_code, status.HTTP_200_OK) + @ddt.data(*list(AuthType)) def test_another_user_with_certs_shared_custom(self, auth_type): """ diff --git a/lms/djangoapps/certificates/apis/v0/views.py b/lms/djangoapps/certificates/apis/v0/views.py index 83ee155b10..0f33f18073 100644 --- a/lms/djangoapps/certificates/apis/v0/views.py +++ b/lms/djangoapps/certificates/apis/v0/views.py @@ -12,7 +12,7 @@ from edx_rest_framework_extensions.auth.session.authentication import SessionAut from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from rest_condition import C -from rest_framework.permissions import IsAuthenticated, IsAdminUser +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView @@ -23,6 +23,8 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi from openedx.core.djangoapps.user_api.accounts.api import visible_fields from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser +from .permissions import IsOwnerOrPublicCertificates + log = logging.getLogger(__name__) User = get_user_model() @@ -158,7 +160,7 @@ class CertificatesListView(APIView): permissions.JwtHasUserFilterForRequestedUser ) ), - IsAdminUser, + (C(permissions.IsStaff) | IsOwnerOrPublicCertificates), ) required_scopes = ['certificates:read']