The new "country access" implementation replaces the old implementation. Middleware and tests have been updated accordingly, but deprecated models are preserved for backwards compatibility.
169 lines
5.9 KiB
Python
169 lines
5.9 KiB
Python
"""
|
|
Tests for EmbargoMiddleware with CountryAccessRules
|
|
"""
|
|
|
|
import unittest
|
|
from mock import patch
|
|
import ddt
|
|
|
|
from django.core.urlresolvers import reverse
|
|
from django.conf import settings
|
|
from django.core.cache import cache as django_cache
|
|
|
|
from util.testing import UrlResetMixin
|
|
from student.tests.factories import UserFactory
|
|
from xmodule.modulestore.tests.factories import CourseFactory
|
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
|
from config_models.models import cache as config_cache
|
|
|
|
from embargo.models import RestrictedCourse, IPFilter
|
|
from embargo.test_utils import restrict_course
|
|
|
|
|
|
@ddt.ddt
|
|
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
|
class EmbargoMiddlewareAccessTests(UrlResetMixin, ModuleStoreTestCase):
|
|
"""Tests of embargo middleware country access rules.
|
|
|
|
There are detailed unit tests for the rule logic in
|
|
`test_api.py`; here, we're mainly testing the integration
|
|
with middleware
|
|
|
|
"""
|
|
USERNAME = 'fred'
|
|
PASSWORD = 'secret'
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
def setUp(self):
|
|
super(EmbargoMiddlewareAccessTests, self).setUp('embargo')
|
|
self.user = UserFactory(username=self.USERNAME, password=self.PASSWORD)
|
|
self.course = CourseFactory.create()
|
|
self.client.login(username=self.USERNAME, password=self.PASSWORD)
|
|
|
|
self.courseware_url = reverse(
|
|
'course_root',
|
|
kwargs={'course_id': unicode(self.course.id)}
|
|
)
|
|
self.non_courseware_url = reverse('dashboard')
|
|
|
|
# Clear the cache to avoid interference between tests
|
|
django_cache.clear()
|
|
config_cache.clear()
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
def test_blocked(self):
|
|
with restrict_course(self.course.id, access_point='courseware') as redirect_url:
|
|
response = self.client.get(self.courseware_url)
|
|
self.assertRedirects(response, redirect_url)
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
def test_allowed(self):
|
|
# Add the course to the list of restricted courses
|
|
# but don't create any access rules
|
|
RestrictedCourse.objects.create(course_key=self.course.id)
|
|
|
|
# Expect that we can access courseware
|
|
response = self.client.get(self.courseware_url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
def test_non_courseware_url(self):
|
|
with restrict_course(self.course.id):
|
|
response = self.client.get(self.non_courseware_url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
@ddt.data(
|
|
# request_ip, blacklist, whitelist, is_enabled, allow_access
|
|
('173.194.123.35', ['173.194.123.35'], [], True, False),
|
|
('173.194.123.35', ['173.194.0.0/16'], [], True, False),
|
|
('173.194.123.35', ['127.0.0.0/32', '173.194.0.0/16'], [], True, False),
|
|
('173.195.10.20', ['173.194.0.0/16'], [], True, True),
|
|
('173.194.123.35', ['173.194.0.0/16'], ['173.194.0.0/16'], True, False),
|
|
('173.194.123.35', [], ['173.194.0.0/16'], True, True),
|
|
('192.178.2.3', [], ['173.194.0.0/16'], True, True),
|
|
('173.194.123.35', ['173.194.123.35'], [], False, True),
|
|
)
|
|
@ddt.unpack
|
|
def test_ip_access_rules(self, request_ip, blacklist, whitelist, is_enabled, allow_access):
|
|
# Ensure that IP blocking works for anonymous users
|
|
self.client.logout()
|
|
|
|
# Set up the IP rules
|
|
IPFilter.objects.create(
|
|
blacklist=", ".join(blacklist),
|
|
whitelist=", ".join(whitelist),
|
|
enabled=is_enabled
|
|
)
|
|
|
|
# Check that access is enforced
|
|
response = self.client.get(
|
|
"/",
|
|
HTTP_X_FORWARDED_FOR=request_ip,
|
|
REMOTE_ADDR=request_ip
|
|
)
|
|
|
|
if allow_access:
|
|
self.assertEqual(response.status_code, 200)
|
|
else:
|
|
redirect_url = reverse(
|
|
'embargo_blocked_message',
|
|
kwargs={
|
|
'access_point': 'courseware',
|
|
'message_key': 'embargo'
|
|
}
|
|
)
|
|
self.assertRedirects(response, redirect_url)
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
@ddt.data(
|
|
('courseware', 'default'),
|
|
('courseware', 'embargo'),
|
|
('enrollment', 'default'),
|
|
('enrollment', 'embargo')
|
|
)
|
|
@ddt.unpack
|
|
def test_always_allow_access_to_embargo_messages(self, access_point, msg_key):
|
|
# Blacklist an IP address
|
|
IPFilter.objects.create(
|
|
blacklist="192.168.10.20",
|
|
enabled=True
|
|
)
|
|
|
|
url = reverse(
|
|
'embargo_blocked_message',
|
|
kwargs={
|
|
'access_point': access_point,
|
|
'message_key': msg_key
|
|
}
|
|
)
|
|
response = self.client.get(
|
|
url,
|
|
HTTP_X_FORWARDED_FOR="192.168.10.20",
|
|
REMOTE_ADDR="192.168.10.20"
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
@patch.dict(settings.FEATURES, {'EMBARGO': True})
|
|
def test_whitelist_ip_skips_country_access_checks(self):
|
|
# Whitelist an IP address
|
|
IPFilter.objects.create(
|
|
whitelist="192.168.10.20",
|
|
enabled=True
|
|
)
|
|
|
|
# Set up country access rules so the user would
|
|
# be restricted from the course.
|
|
with restrict_course(self.course.id):
|
|
# Make a request from the whitelisted IP address
|
|
response = self.client.get(
|
|
self.courseware_url,
|
|
HTTP_X_FORWARDED_FOR="192.168.10.20",
|
|
REMOTE_ADDR="192.168.10.20"
|
|
)
|
|
|
|
# Expect that we were still able to access the page,
|
|
# even though we would have been blocked by country
|
|
# access rules.
|
|
self.assertEqual(response.status_code, 200)
|