This commit updates common/djangoapps. These keys are now objects with a limited interface, and the particular internal representation is managed by the data storage layer (the modulestore). For the LMS, there should be no outward-facing changes to the system. The keys are, for now, a change to internal representation only. For Studio, the new serialized form of the keys is used in urls, to allow for further migration in the future. Co-Author: Andy Armstrong <andya@edx.org> Co-Author: Christina Roberts <christina@edx.org> Co-Author: David Baumgold <db@edx.org> Co-Author: Diana Huang <dkh@edx.org> Co-Author: Don Mitchell <dmitchell@edx.org> Co-Author: Julia Hansbrough <julia@edx.org> Co-Author: Nimisha Asthagiri <nasthagiri@edx.org> Co-Author: Sarina Canelake <sarina@edx.org> [LMS-2370]
160 lines
7.0 KiB
Python
160 lines
7.0 KiB
Python
"""
|
|
Tests for EmbargoMiddleware
|
|
"""
|
|
|
|
import mock
|
|
import pygeoip
|
|
import unittest
|
|
|
|
from django.conf import settings
|
|
from django.test import TestCase, Client
|
|
from django.test.utils import override_settings
|
|
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
|
from student.models import CourseEnrollment
|
|
from student.tests.factories import UserFactory
|
|
from xmodule.modulestore.tests.factories import CourseFactory
|
|
|
|
# Explicitly import the cache from ConfigurationModel so we can reset it after each test
|
|
from config_models.models import cache
|
|
from embargo.models import EmbargoedCourse, EmbargoedState, IPFilter
|
|
|
|
|
|
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
|
|
class EmbargoMiddlewareTests(TestCase):
|
|
"""
|
|
Tests of EmbargoMiddleware
|
|
"""
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.user = UserFactory(username='fred', password='secret')
|
|
self.client.login(username='fred', password='secret')
|
|
self.embargo_course = CourseFactory.create()
|
|
self.embargo_course.save()
|
|
self.regular_course = CourseFactory.create(org="Regular")
|
|
self.regular_course.save()
|
|
self.embargoed_page = '/courses/' + self.embargo_course.id.to_deprecated_string() + '/info'
|
|
self.regular_page = '/courses/' + self.regular_course.id.to_deprecated_string() + '/info'
|
|
EmbargoedCourse(course_id=self.embargo_course.id, embargoed=True).save()
|
|
EmbargoedState(
|
|
embargoed_countries="cu, ir, Sy, SD",
|
|
changed_by=self.user,
|
|
enabled=True
|
|
).save()
|
|
CourseEnrollment.enroll(self.user, self.regular_course.id)
|
|
CourseEnrollment.enroll(self.user, self.embargo_course.id)
|
|
# Text from lms/templates/static_templates/embargo.html
|
|
self.embargo_text = "Unfortunately, at this time edX must comply with export controls, and we cannot allow you to access this particular course."
|
|
|
|
self.patcher = mock.patch.object(pygeoip.GeoIP, 'country_code_by_addr', self.mock_country_code_by_addr)
|
|
self.patcher.start()
|
|
|
|
def tearDown(self):
|
|
# Explicitly clear ConfigurationModel's cache so tests have a clear cache
|
|
# and don't interfere with each other
|
|
cache.clear()
|
|
self.patcher.stop()
|
|
|
|
def mock_country_code_by_addr(self, ip_addr):
|
|
"""
|
|
Gives us a fake set of IPs
|
|
"""
|
|
ip_dict = {
|
|
'1.0.0.0': 'CU',
|
|
'2.0.0.0': 'IR',
|
|
'3.0.0.0': 'SY',
|
|
'4.0.0.0': 'SD',
|
|
'5.0.0.0': 'AQ', # Antartica
|
|
}
|
|
return ip_dict.get(ip_addr, 'US')
|
|
|
|
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
|
def test_countries(self):
|
|
# Accessing an embargoed page from a blocked IP should cause a redirect
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='1.0.0.0', REMOTE_ADDR='1.0.0.0')
|
|
self.assertEqual(response.status_code, 302)
|
|
# Following the redirect should give us the embargo page
|
|
response = self.client.get(
|
|
self.embargoed_page,
|
|
HTTP_X_FORWARDED_FOR='1.0.0.0',
|
|
REMOTE_ADDR='1.0.0.0',
|
|
follow=True
|
|
)
|
|
self.assertIn(self.embargo_text, response.content)
|
|
|
|
# Accessing a regular page from a blocked IP should succeed
|
|
response = self.client.get(self.regular_page, HTTP_X_FORWARDED_FOR='1.0.0.0', REMOTE_ADDR='1.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Accessing an embargoed page from a non-embargoed IP should succeed
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='5.0.0.0', REMOTE_ADDR='5.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Accessing a regular page from a non-embargoed IP should succeed
|
|
response = self.client.get(self.regular_page, HTTP_X_FORWARDED_FOR='5.0.0.0', REMOTE_ADDR='5.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
|
def test_ip_exceptions(self):
|
|
# Explicitly whitelist/blacklist some IPs
|
|
IPFilter(
|
|
whitelist='1.0.0.0',
|
|
blacklist='5.0.0.0',
|
|
changed_by=self.user,
|
|
enabled=True
|
|
).save()
|
|
|
|
# Accessing an embargoed page from a blocked IP that's been whitelisted
|
|
# should succeed
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='1.0.0.0', REMOTE_ADDR='1.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Accessing a regular course from a blocked IP that's been whitelisted should succeed
|
|
response = self.client.get(self.regular_page, HTTP_X_FORWARDED_FOR='1.0.0.0', REMOTE_ADDR='1.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Accessing an embargoed course from non-embargoed IP that's been blacklisted
|
|
# should cause a redirect
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='5.0.0.0', REMOTE_ADDR='5.0.0.0')
|
|
self.assertEqual(response.status_code, 302)
|
|
# Following the redirect should give us the embargo page
|
|
response = self.client.get(
|
|
self.embargoed_page,
|
|
HTTP_X_FORWARDED_FOR='5.0.0.0',
|
|
REMOTE_ADDR='1.0.0.0',
|
|
follow=True
|
|
)
|
|
self.assertIn(self.embargo_text, response.content)
|
|
|
|
# Accessing a regular course from a non-embargoed IP that's been blacklisted should succeed
|
|
response = self.client.get(self.regular_page, HTTP_X_FORWARDED_FOR='5.0.0.0', REMOTE_ADDR='5.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
|
@mock.patch.dict(settings.FEATURES, {'EMBARGO': False})
|
|
def test_countries_embargo_off(self):
|
|
# When the middleware is turned off, all requests should go through
|
|
# Accessing an embargoed page from a blocked IP OK
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='1.0.0.0', REMOTE_ADDR='1.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Accessing a regular page from a blocked IP should succeed
|
|
response = self.client.get(self.regular_page, HTTP_X_FORWARDED_FOR='1.0.0.0', REMOTE_ADDR='1.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Explicitly whitelist/blacklist some IPs
|
|
IPFilter(
|
|
whitelist='1.0.0.0',
|
|
blacklist='5.0.0.0',
|
|
changed_by=self.user,
|
|
enabled=True
|
|
).save()
|
|
|
|
# Accessing an embargoed course from non-embargoed IP that's been blacklisted
|
|
# should be OK
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='5.0.0.0', REMOTE_ADDR='5.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Accessing a regular course from a non-embargoed IP that's been blacklisted should succeed
|
|
response = self.client.get(self.regular_page, HTTP_X_FORWARDED_FOR='5.0.0.0', REMOTE_ADDR='5.0.0.0')
|
|
self.assertEqual(response.status_code, 200)
|