Commit 8855f127 by Clinton Blackburn

Merge pull request #12435 from mitocw/gdm_certificates_api_key

Authentication and Authorization for Cert Rest APIs fixed
parents 21ff5f4e 3a6167d6
"""
Tests for the Certificate REST APIs.
"""
from datetime import datetime, timedelta
from django.core.urlresolvers import reverse
from oauth2_provider import models as dot_models
from rest_framework import status
from rest_framework.test import APITestCase
......@@ -12,6 +15,8 @@ from student.tests.factories import UserFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
USER_PASSWORD = 'test'
class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
"""
......@@ -29,9 +34,9 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
def setUp(self):
super(CertificatesRestApiTest, self).setUp()
self.student = UserFactory.create(password='test')
self.student_no_cert = UserFactory.create(password='test')
self.staff_user = UserFactory.create(password='test', is_staff=True)
self.student = UserFactory.create(password=USER_PASSWORD)
self.student_no_cert = UserFactory.create(password=USER_PASSWORD)
self.staff_user = UserFactory.create(password=USER_PASSWORD, is_staff=True)
GeneratedCertificateFactory.create(
user=self.student,
......@@ -44,6 +49,23 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
self.namespaced_url = 'certificates_api:v0:certificates:detail'
# create a configuration for django-oauth-toolkit (DOT)
dot_app_user = UserFactory.create(password=USER_PASSWORD)
dot_app = dot_models.Application.objects.create(
name='test app',
user=dot_app_user,
client_type='confidential',
authorization_grant_type='authorization-code',
redirect_uris='http://localhost:8079/complete/edxorg/'
)
self.dot_access_token = dot_models.AccessToken.objects.create(
user=self.student,
application=dot_app,
expires=datetime.utcnow() + timedelta(weeks=1),
scope='read write',
token='16MGyP3OaQYHmpT1lK7Q6MMNAZsjwF'
)
def get_url(self, username):
"""
Helper function to create the url for certificates
......@@ -56,6 +78,15 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
}
)
def assert_oauth_status(self, access_token, expected_status):
"""
Helper method for requests with OAUTH token
"""
self.client.logout()
auth_header = "Bearer {0}".format(access_token)
response = self.client.get(self.get_url(self.student.username), HTTP_AUTHORIZATION=auth_header)
self.assertEqual(response.status_code, expected_status)
def test_permissions(self):
"""
Test that only the owner of the certificate can access the url
......@@ -65,7 +96,7 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_401_UNAUTHORIZED)
# another student
self.client.login(username=self.student_no_cert.username, password='test')
self.client.login(username=self.student_no_cert.username, password=USER_PASSWORD)
resp = self.client.get(self.get_url(self.student.username))
# gets 404 instead of 403 for security reasons
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
......@@ -73,21 +104,57 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
self.client.logout()
# same student of the certificate
self.client.login(username=self.student.username, password='test')
self.client.login(username=self.student.username, password=USER_PASSWORD)
resp = self.client.get(self.get_url(self.student.username))
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.client.logout()
# staff user
self.client.login(username=self.staff_user.username, password='test')
self.client.login(username=self.staff_user.username, password=USER_PASSWORD)
resp = self.client.get(self.get_url(self.student.username))
self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_inactive_user_access(self):
"""
Verify inactive users - those who have not verified their email addresses -
are allowed to access the endpoint.
"""
self.client.login(username=self.student.username, password=USER_PASSWORD)
self.student.is_active = False
self.student.save()
resp = self.client.get(self.get_url(self.student.username))
self.assertEqual(resp.status_code, status.HTTP_200_OK)
def test_dot_valid_accesstoken(self):
"""
Verify access with a valid Django Oauth Toolkit access token.
"""
self.assert_oauth_status(self.dot_access_token, status.HTTP_200_OK)
def test_dot_invalid_accesstoken(self):
"""
Verify the endpoint is inaccessible for authorization
attempts made with an invalid OAuth access token.
"""
self.assert_oauth_status("fooooooooooToken", status.HTTP_401_UNAUTHORIZED)
def test_dot_expired_accesstoken(self):
"""
Verify the endpoint is inaccessible for authorization
attempts made with an expired OAuth access token.
"""
# set the expiration date in the past
self.dot_access_token.expires = datetime.utcnow() - timedelta(weeks=1)
self.dot_access_token.save()
self.assert_oauth_status(self.dot_access_token, status.HTTP_401_UNAUTHORIZED)
def test_no_certificate_for_user(self):
"""
Test for case with no certificate available
"""
self.client.login(username=self.student_no_cert.username, password='test')
self.client.login(username=self.student_no_cert.username, password=USER_PASSWORD)
resp = self.client.get(self.get_url(self.student_no_cert.username))
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
self.assertIn('error_code', resp.data) # pylint: disable=no-member
......@@ -100,7 +167,7 @@ class CertificatesRestApiTest(SharedModuleStoreTestCase, APITestCase):
"""
Tests case user that pulls her own certificate
"""
self.client.login(username=self.student.username, password='test')
self.client.login(username=self.student.username, password=USER_PASSWORD)
resp = self.client.get(self.get_url(self.student.username))
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(
......
......@@ -3,14 +3,16 @@ import logging
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from rest_framework.authentication import SessionAuthentication
from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework_oauth.authentication import OAuth2Authentication
from lms.djangoapps.certificates.api import get_certificate_for_user
from openedx.core.lib.api import permissions
from openedx.core.lib.api import (
authentication,
permissions,
)
log = logging.getLogger(__name__)
......@@ -64,8 +66,14 @@ class CertificatesDetailView(GenericAPIView):
}
"""
authentication_classes = (OAuth2Authentication, SessionAuthentication,)
permission_classes = (IsAuthenticated, permissions.IsUserInUrlOrStaff)
authentication_classes = (
authentication.OAuth2AuthenticationAllowInactiveUser,
authentication.SessionAuthenticationAllowInactiveUser,
)
permission_classes = (
IsAuthenticated,
permissions.IsUserInUrlOrStaff
)
def get(self, request, username, course_id):
"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment