Conflicts: cms/djangoapps/contentstore/tests/test_contentstore.py cms/djangoapps/contentstore/views/component.py cms/djangoapps/contentstore/views/item.py cms/djangoapps/contentstore/views/preview.py cms/djangoapps/contentstore/views/tests/test_container.py cms/static/js/spec/views/unit_spec.js cms/static/js/utils/module.js cms/templates/container.html cms/templates/studio_vertical_wrapper.html cms/templates/studio_xblock_wrapper.html common/djangoapps/student/views.py lms/templates/notes.html lms/templates/textannotation.html lms/templates/videoannotation.html
238 lines
11 KiB
Python
238 lines
11 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')
|
|
def test_ip_network_exceptions(self):
|
|
# Explicitly whitelist/blacklist some IP networks
|
|
IPFilter(
|
|
whitelist='1.0.0.1/24',
|
|
blacklist='5.0.0.0/16,1.1.0.0/24',
|
|
changed_by=self.user,
|
|
enabled=True
|
|
).save()
|
|
|
|
# Accessing an embargoed page from a blocked IP that's been whitelisted with a network
|
|
# 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 with a network
|
|
# 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 with a network
|
|
# should cause a redirect
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='5.0.0.100', REMOTE_ADDR='5.0.0.100')
|
|
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.100',
|
|
REMOTE_ADDR='5.0.0.100',
|
|
follow=True
|
|
)
|
|
self.assertIn(self.embargo_text, response.content)
|
|
|
|
# Accessing an embargoed course from non-embargoed IP that's been blaclisted with a network
|
|
# should cause a redirect
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='1.1.0.1', REMOTE_ADDR='1.1.0.1')
|
|
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.1.0.0',
|
|
REMOTE_ADDR='1.1.0.0',
|
|
follow=True
|
|
)
|
|
self.assertIn(self.embargo_text, response.content)
|
|
|
|
# Accessing an embargoed from a blocked IP that's not blacklisted by the network rule.
|
|
# should succeed
|
|
response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='1.1.1.0', REMOTE_ADDR='1.1.1.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)
|
|
|
|
@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)
|
|
|
|
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
|
@mock.patch.dict(settings.FEATURES, {'EMBARGO': False, 'SITE_EMBARGOED': True})
|
|
def test_embargo_off_embargo_site_on(self):
|
|
# When the middleware is turned on with SITE, main site access should be restricted
|
|
# Accessing a regular page from a blocked IP is denied.
|
|
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, 403)
|
|
|
|
# Accessing a regular page from a non blocked 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')
|
|
@mock.patch.dict(settings.FEATURES, {'EMBARGO': False, 'SITE_EMBARGOED': True})
|
|
@override_settings(EMBARGO_SITE_REDIRECT_URL='https://www.edx.org/')
|
|
def test_embargo_off_embargo_site_on_with_redirect_url(self):
|
|
# When the middleware is turned on with SITE_EMBARGOED, main site access
|
|
# should be restricted. Accessing a regular page from a blocked IP is
|
|
# denied, and redirected to EMBARGO_SITE_REDIRECT_URL rather than returning a 403.
|
|
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, 302)
|