def test_repeat_course(self): # Initially course shouldn't be authorized self.assertFalse(EmbargoedCourse.is_embargoed(self.course.id)) # Test authorizing the course, which should totally work form = EmbargoedCourseForm(data=self.true_form_data) # Validation should work self.assertTrue(form.is_valid()) form.save() # Check that this course is authorized self.assertTrue(EmbargoedCourse.is_embargoed(self.course.id)) # Now make a new course authorization with the same course id that tries to turn email off form = EmbargoedCourseForm(data=self.false_form_data) # Validation should not work because course_id field is unique self.assertFalse(form.is_valid()) self.assertEquals( "Embargoed course with this Course id already exists.", form._errors["course_id"][0], # pylint: disable=protected-access ) with self.assertRaisesRegexp( ValueError, "The EmbargoedCourse could not be created because the data didn't validate." ): form.save() # Course should still be authorized (invalid attempt had no effect) self.assertTrue(EmbargoedCourse.is_embargoed(self.course.id))
def test_repeat_course(self): # Initially course shouldn't be authorized self.assertFalse(EmbargoedCourse.is_embargoed(self.course.id)) # Test authorizing the course, which should totally work form = EmbargoedCourseForm(data=self.true_form_data) # Validation should work self.assertTrue(form.is_valid()) form.save() # Check that this course is authorized self.assertTrue(EmbargoedCourse.is_embargoed(self.course.id)) # Now make a new course authorization with the same course id that tries to turn email off form = EmbargoedCourseForm(data=self.false_form_data) # Validation should not work because course_id field is unique self.assertFalse(form.is_valid()) self.assertEquals( "Embargoed course with this Course id already exists.", form._errors['course_id'][0] # pylint: disable=protected-access ) with self.assertRaisesRegexp( ValueError, "The EmbargoedCourse could not be created because the data didn't validate." ): form.save() # Course should still be authorized (invalid attempt had no effect) self.assertTrue(EmbargoedCourse.is_embargoed(self.course.id))
def test_embargo_course(self): self.assertFalse(EmbargoedCourse.is_embargoed(self.course.id)) # Test adding embargo to this course form = EmbargoedCourseForm(data=self.true_form_data) # Validation should work self.assertTrue(form.is_valid()) form.save() # Check that this course is embargoed self.assertTrue(EmbargoedCourse.is_embargoed(self.course.id))
def test_course_embargo(self): course_id = CourseLocator('abc', '123', 'doremi') # Test that course is not authorized by default self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) # Authorize cauth = EmbargoedCourse(course_id=course_id, embargoed=True) cauth.save() # Now, course should be embargoed self.assertTrue(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals( unicode(cauth), u"Course '{course_id}' is Embargoed".format(course_id=course_id) ) # Unauthorize by explicitly setting email_enabled to False cauth.embargoed = False cauth.save() # Test that course is now unauthorized self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals( unicode(cauth), u"Course '{course_id}' is Not Embargoed".format(course_id=course_id) )
def process_request(self, request): """ Processes embargo requests """ url = request.path course_id = course_id_from_url(url) # If they're trying to access a course that cares about embargoes if EmbargoedCourse.is_embargoed(course_id): # If we're having performance issues, add caching here ip_addr = get_ip(request) # if blacklisted, immediately fail if ip_addr in IPFilter.current().blacklist_ips: log.info( "Embargo: Restricting IP address %s to course %s because IP is blacklisted.", ip_addr, course_id) return redirect('embargo') 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 if is_embargoed and ip_addr not in IPFilter.current( ).whitelist_ips: log.info( "Embargo: Restricting IP address %s to course %s because IP is from country %s.", ip_addr, course_id, country_code_from_ip) return redirect('embargo')
def process_request(self, request): """ Processes embargo requests. """ url = request.path course_id = course_id_from_url(url) course_is_embargoed = EmbargoedCourse.is_embargoed(course_id) # If they're trying to access a course that cares about embargoes if self.site_enabled or course_is_embargoed: # Construct the list of functions that check whether the user is embargoed. # We wrap each of these functions in a decorator that logs the reason the user # was blocked. # Each function should return `True` iff the user is blocked by an embargo. check_functions = [ self._log_embargo_reason(check_func, course_id, course_is_embargoed) for check_func in [ partial(self._is_embargoed_by_ip, get_ip(request)), partial(self._is_embargoed_by_profile_country, request.user) ] ] # Perform each of the checks # If the user fails any of the checks, immediately redirect them # and skip later checks. for check_func in check_functions: if check_func(): return self._embargo_redirect_response
def process_request(self, request): """ Processes embargo requests """ url = request.path course_id = course_id_from_url(url) # If they're trying to access a course that cares about embargoes if EmbargoedCourse.is_embargoed(course_id): # If we're having performance issues, add caching here ip_addr = get_ip(request) # if blacklisted, immediately fail if ip_addr in IPFilter.current().blacklist_ips: log.info("Embargo: Restricting IP address %s to course %s because IP is blacklisted.", ip_addr, course_id) return redirect('embargo') 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 if is_embargoed and ip_addr not in IPFilter.current().whitelist_ips: log.info( "Embargo: Restricting IP address %s to course %s because IP is from country %s.", ip_addr, course_id, country_code_from_ip ) return redirect('embargo')
def setUp(self): super(EmbargoMiddlewareTests, self).setUp() self.user = UserFactory(username='******', password='******') self.client.login(username='******', password='******') 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 course." self.patcher = mock.patch.object(pygeoip.GeoIP, 'country_code_by_addr', self.mock_country_code_by_addr) self.patcher.start()
def process_request(self, request): """ Processes embargo requests """ url = request.path course_id = course_id_from_url(url) course_is_embargoed = EmbargoedCourse.is_embargoed(course_id) # If they're trying to access a course that cares about embargoes if self.site_enabled or course_is_embargoed: response = redirect('embargo') # Set the proper response if site is enabled if self.site_enabled: redirect_url = getattr(settings, 'EMBARGO_SITE_REDIRECT_URL', None) response = HttpResponseRedirect(redirect_url) if redirect_url \ else HttpResponseForbidden('Access Denied') # If we're having performance issues, add caching here ip_addr = get_ip(request) # if blacklisted, immediately fail if ip_addr in IPFilter.current().blacklist_ips: if course_is_embargoed: msg = "Embargo: Restricting IP address %s to course %s because IP is blacklisted." % \ (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) 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 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." % \ (ip_addr, course_id, country_code_from_ip) else: msg = "Embargo: Restricting IP address %s because IP is from country %s." % \ (ip_addr, country_code_from_ip) log.info(msg) return response
def process_request(self, request): """ Processes embargo requests """ url = request.path course_id = course_id_from_url(url) course_is_embargoed = EmbargoedCourse.is_embargoed(course_id) # If they're trying to access a course that cares about embargoes if self.site_enabled or course_is_embargoed: response = redirect("embargo") # Set the proper response if site is enabled if self.site_enabled: redirect_url = getattr(settings, "EMBARGO_SITE_REDIRECT_URL", None) response = ( HttpResponseRedirect(redirect_url) if redirect_url else HttpResponseForbidden("Access Denied") ) # If we're having performance issues, add caching here ip_addr = get_ip(request) # if blacklisted, immediately fail if ip_addr in IPFilter.current().blacklist_ips: if course_is_embargoed: msg = "Embargo: Restricting IP address %s to course %s because IP is blacklisted." % ( ip_addr, course_id, ) else: msg = "Embargo: Restricting IP address %s because IP is blacklisted." % ip_addr log.info(msg) return response 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 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." % ( ip_addr, course_id, country_code_from_ip, ) else: msg = "Embargo: Restricting IP address %s because IP is from country %s." % ( ip_addr, country_code_from_ip, ) log.info(msg) return response
def test_course_embargo(self): course_id = CourseLocator('abc', '123', 'doremi') # Test that course is not authorized by default self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) # Authorize cauth = EmbargoedCourse(course_id=course_id, embargoed=True) cauth.save() # Now, course should be embargoed self.assertTrue(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals( unicode(cauth), u"Course '{course_id}' is Embargoed".format(course_id=course_id)) # Unauthorize by explicitly setting email_enabled to False cauth.embargoed = False cauth.save() # Test that course is now unauthorized self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals( unicode(cauth), u"Course '{course_id}' is Not Embargoed".format( course_id=course_id))
def process_request(self, request): """Block requests based on embargo rules. In the new ENABLE_COUNTRY_ACCESS implmentation, this will perform the following checks: 1) If the user's IP address is blacklisted, block. 2) If the user's IP address is whitelisted, allow. 3) If the user's country (inferred from their IP address) is blocked for a courseware page, block. 4) If the user's country (retrieved from the user's profile) is blocked for a courseware page, block. 5) Allow access. """ # If the feature flag is set, use the new "country access" implementation. # This is a more flexible implementation of the embargo feature that allows # per-course country access rules. if self.enable_country_access: # Never block certain patterns by IP address for pattern in self.ALLOW_URL_PATTERNS: if pattern.match(request.path) is not None: return None ip_address = get_ip(request) ip_filter = IPFilter.current() if ip_filter.enabled and ip_address in ip_filter.blacklist_ips: log.info( ( u"User %s was blocked from accessing %s " u"because IP address %s is blacklisted." ), request.user.id, request.path, ip_address ) # If the IP is blacklisted, reject. # This applies to any request, not just courseware URLs. ip_blacklist_url = reverse( 'embargo_blocked_message', kwargs={ 'access_point': 'courseware', 'message_key': 'embargo' } ) return redirect(ip_blacklist_url) elif ip_filter.enabled and ip_address in ip_filter.whitelist_ips: log.info( ( u"User %s was allowed access to %s because " u"IP address %s is whitelisted." ), request.user.id, request.path, ip_address ) # If the IP is whitelisted, then allow access, # skipping later checks. return None else: # Otherwise, perform the country access checks. # This applies only to courseware URLs. return self.country_access_rules(request.user, ip_address, request.path) url = request.path course_id = course_id_from_url(url) course_is_embargoed = EmbargoedCourse.is_embargoed(course_id) # If they're trying to access a course that cares about embargoes if self.site_enabled or course_is_embargoed: # Construct the list of functions that check whether the user is embargoed. # We wrap each of these functions in a decorator that logs the reason the user # was blocked. # Each function should return `True` iff the user is blocked by an embargo. check_functions = [ self._log_embargo_reason(check_func, course_id, course_is_embargoed) for check_func in [ partial(self._is_embargoed_by_ip, get_ip(request)), partial(self._is_embargoed_by_profile_country, request.user) ] ] # Perform each of the checks # If the user fails any of the checks, immediately redirect them # and skip later checks. for check_func in check_functions: if check_func(): return self._embargo_redirect_response
def test_course_embargo(self): course_id = SlashSeparatedCourseKey('abc', '123', 'doremi') # Test that course is not authorized by default self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) # Authorize cauth = EmbargoedCourse(course_id=course_id, embargoed=True) cauth.save() # Now, course should be embargoed self.assertTrue(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals(cauth.__unicode__(), "Course 'abc/123/doremi' is Embargoed") # Unauthorize by explicitly setting email_enabled to False cauth.embargoed = False cauth.save() # Test that course is now unauthorized self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals(cauth.__unicode__(), "Course 'abc/123/doremi' is Not Embargoed")
def process_request(self, request): """Block requests based on embargo rules. In the new ENABLE_COUNTRY_ACCESS implmentation, this will perform the following checks: 1) If the user's IP address is blacklisted, block. 2) If the user's IP address is whitelisted, allow. 3) If the user's country (inferred from their IP address) is blocked for a courseware page, block. 4) If the user's country (retrieved from the user's profile) is blocked for a courseware page, block. 5) Allow access. """ # If the feature flag is set, use the new "country access" implementation. # This is a more flexible implementation of the embargo feature that allows # per-course country access rules. if self.enable_country_access: # Never block certain patterns by IP address for pattern in self.ALLOW_URL_PATTERNS: if pattern.match(request.path) is not None: return None ip_address = get_ip(request) ip_filter = IPFilter.current() if ip_filter.enabled and ip_address in ip_filter.blacklist_ips: log.info((u"User %s was blocked from accessing %s " u"because IP address %s is blacklisted."), request.user.id, request.path, ip_address) # If the IP is blacklisted, reject. # This applies to any request, not just courseware URLs. ip_blacklist_url = reverse('embargo_blocked_message', kwargs={ 'access_point': 'courseware', 'message_key': 'embargo' }) return redirect(ip_blacklist_url) elif ip_filter.enabled and ip_address in ip_filter.whitelist_ips: log.info((u"User %s was allowed access to %s because " u"IP address %s is whitelisted."), request.user.id, request.path, ip_address) # If the IP is whitelisted, then allow access, # skipping later checks. return None else: # Otherwise, perform the country access checks. # This applies only to courseware URLs. return self.country_access_rules(request.user, ip_address, request.path) url = request.path course_id = course_id_from_url(url) course_is_embargoed = EmbargoedCourse.is_embargoed(course_id) # If they're trying to access a course that cares about embargoes if self.site_enabled or course_is_embargoed: # Construct the list of functions that check whether the user is embargoed. # We wrap each of these functions in a decorator that logs the reason the user # was blocked. # Each function should return `True` iff the user is blocked by an embargo. check_functions = [ self._log_embargo_reason(check_func, course_id, course_is_embargoed) for check_func in [ partial(self._is_embargoed_by_ip, get_ip(request)), partial(self._is_embargoed_by_profile_country, request.user) ] ] # Perform each of the checks # If the user fails any of the checks, immediately redirect them # and skip later checks. for check_func in check_functions: if check_func(): return self._embargo_redirect_response
def test_course_embargo(self): course_id = 'abc/123/doremi' # Test that course is not authorized by default self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) # Authorize cauth = EmbargoedCourse(course_id=course_id, embargoed=True) cauth.save() # Now, course should be embargoed self.assertTrue(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals( cauth.__unicode__(), "Course 'abc/123/doremi' is Embargoed" ) # Unauthorize by explicitly setting email_enabled to False cauth.embargoed = False cauth.save() # Test that course is now unauthorized self.assertFalse(EmbargoedCourse.is_embargoed(course_id)) self.assertEquals( cauth.__unicode__(), "Course 'abc/123/doremi' is Not Embargoed" )