diff --git a/AUTHORS b/AUTHORS index 96bca29d4a2518218c6665b9fd6fa1ae2ec916df..1556e2124915e3f73cf33d712221511986c3af12 100644 --- a/AUTHORS +++ b/AUTHORS @@ -169,3 +169,4 @@ Clinton Blackburn <cblackburn@edx.org> Dennis Jen <djen@edx.org> Filippo Valsorda <hi@filippo.io> Ivica Ceraj <ceraj@mit.edu> +Jason Zhu <fmyzjs@gmail.com> \ No newline at end of file diff --git a/cms/envs/common.py b/cms/envs/common.py index 2f39d754dcd6dec7de33ab6e2537cb1db18438ce..2f187e9f0fd84ae1ad4984b1e540978280d1d7ec 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -129,7 +129,7 @@ sys.path.append(COMMON_ROOT / 'lib') # For geolocation ip database GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoIP.dat" - +GEOIPV6_PATH = REPO_ROOT / "common/static/data/geoip/GeoIPv6.dat" ############################# WEB CONFIGURATION ############################# # This is where we stick our compiled template files. diff --git a/common/djangoapps/embargo/middleware.py b/common/djangoapps/embargo/middleware.py index 052c04bdbce29eb4820b95e66484f86ccf4b1057..de962ec0eeb841472d9c513448364ca162bc258e 100644 --- a/common/djangoapps/embargo/middleware.py +++ b/common/djangoapps/embargo/middleware.py @@ -86,13 +86,17 @@ class EmbargoMiddleware(object): (ip_addr, course_id) else: msg = "Embargo: Restricting IP address %s because IP is blacklisted." % ip_addr - log.info(msg) return response + # ipv6 support + if ip_addr.find(':') >= 0: + country_code_from_ip = pygeoip.GeoIP(settings.GEOIPV6_PATH).country_code_by_addr(ip_addr) + else: + country_code_from_ip = pygeoip.GeoIP(settings.GEOIP_PATH).country_code_by_addr(ip_addr) - country_code_from_ip = pygeoip.GeoIP(settings.GEOIP_PATH).country_code_by_addr(ip_addr) is_embargoed = country_code_from_ip in EmbargoedState.current().embargoed_countries_list - # Fail if country is embargoed and the ip address isn't explicitly whitelisted + # Fail if country is embargoed and the ip address isn't explicitly + # whitelisted if is_embargoed and ip_addr not in IPFilter.current().whitelist_ips: if course_is_embargoed: msg = "Embargo: Restricting IP address %s to course %s because IP is from country %s." % \ diff --git a/common/djangoapps/embargo/tests/test_middleware.py b/common/djangoapps/embargo/tests/test_middleware.py index 2f112ca94f90ee4ec6f59098870b71f8c23d47ac..05fd836c36145ec76ecc73398946ac146238beba 100644 --- a/common/djangoapps/embargo/tests/test_middleware.py +++ b/common/djangoapps/embargo/tests/test_middleware.py @@ -64,6 +64,8 @@ class EmbargoMiddlewareTests(TestCase): '3.0.0.0': 'SY', '4.0.0.0': 'SD', '5.0.0.0': 'AQ', # Antartica + '2001:250::': 'CN', + '2001:1340::': 'CU', } return ip_dict.get(ip_addr, 'US') @@ -93,6 +95,32 @@ class EmbargoMiddlewareTests(TestCase): 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_countries_ipv6(self): + # Accessing an embargoed page from a blocked IP should cause a redirect + response = self.client.get(self.embargoed_page, HTTP_X_FORWARDED_FOR='2001:1340::', REMOTE_ADDR='2001:1340::') + 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='2001:1340::', + REMOTE_ADDR='2001:1340::', + 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='2001:1340::', REMOTE_ADDR='2001:1340::') + 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='2001:250::', REMOTE_ADDR='2001:250::') + 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='2001:250::', REMOTE_ADDR='2001:250::') + 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 diff --git a/common/djangoapps/geoinfo/middleware.py b/common/djangoapps/geoinfo/middleware.py index 4779b2f63a65149a395d63c7009e3a5d24f95d71..1f648d6d2d9dd2697cb44ec15807b7a3df7c29a2 100644 --- a/common/djangoapps/geoinfo/middleware.py +++ b/common/djangoapps/geoinfo/middleware.py @@ -36,7 +36,10 @@ class CountryMiddleware(object): del request.session['ip_address'] del request.session['country_code'] elif new_ip_address != old_ip_address: - country_code = pygeoip.GeoIP(settings.GEOIP_PATH).country_code_by_addr(new_ip_address) + if new_ip_address.find(':') >= 0: + country_code = pygeoip.GeoIP(settings.GEOIPV6_PATH).country_code_by_addr(new_ip_address) + else: + country_code = pygeoip.GeoIP(settings.GEOIP_PATH).country_code_by_addr(new_ip_address) request.session['country_code'] = country_code request.session['ip_address'] = new_ip_address log.debug('Country code for IP: %s is set to %s', new_ip_address, country_code) diff --git a/common/djangoapps/geoinfo/tests/test_middleware.py b/common/djangoapps/geoinfo/tests/test_middleware.py index 05982fb98c4c9f820a4791a898f44fdfdb548663..2ef8e9fc6a31b2d02c77f545f6cda67178709140 100644 --- a/common/djangoapps/geoinfo/tests/test_middleware.py +++ b/common/djangoapps/geoinfo/tests/test_middleware.py @@ -41,6 +41,7 @@ class CountryMiddlewareTests(TestCase): '117.79.83.1': 'CN', '117.79.83.100': 'CN', '4.0.0.0': 'SD', + '2001:da8:20f:1502:edcf:550b:4a9c:207d': 'CN', } return ip_dict.get(ip_addr, 'US') @@ -106,3 +107,19 @@ class CountryMiddlewareTests(TestCase): # No country code exists after request processing. self.assertNotIn('country_code', request.session) self.assertNotIn('ip_address', request.session) + + def test_ip_address_is_ipv6(self): + request = self.request_factory.get( + '/somewhere', + HTTP_X_FORWARDED_FOR='2001:da8:20f:1502:edcf:550b:4a9c:207d' + ) + request.user = self.authenticated_user + self.session_middleware.process_request(request) + # No country code exists before request. + self.assertNotIn('country_code', request.session) + self.assertNotIn('ip_address', request.session) + self.country_middleware.process_request(request) + # Country code added to session. + self.assertEqual('CN', request.session.get('country_code')) + self.assertEqual( + '2001:da8:20f:1502:edcf:550b:4a9c:207d', request.session.get('ip_address')) diff --git a/common/static/data/geoip/GeoIPv6.dat b/common/static/data/geoip/GeoIPv6.dat new file mode 100644 index 0000000000000000000000000000000000000000..c61e48c75b77467764be4c27e044ed84bbaa0df5 Binary files /dev/null and b/common/static/data/geoip/GeoIPv6.dat differ diff --git a/lms/envs/common.py b/lms/envs/common.py index 5ff55fbb801018564c4002fdd5b8577c27710856..82174e44ed4b3827f1c4b3a31720fe2b7ef8f85a 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -307,7 +307,7 @@ NODE_PATH = ':'.join(node_paths) # For geolocation ip database GEOIP_PATH = REPO_ROOT / "common/static/data/geoip/GeoIP.dat" - +GEOIPV6_PATH = REPO_ROOT / "common/static/data/geoip/GeoIPv6.dat" # Where to look for a status message STATUS_MESSAGE_PATH = ENV_ROOT / "status_message.json"