Example #1
0
    def test_course_id_from_url(self):
        """ Test course_id_from_url(). """

        self.assertIsNone(course_id_from_url('/login'))
        self.assertIsNone(course_id_from_url('/course/edX/maths/2020'))
        self.assertIsNone(course_id_from_url('/courses/edX/maths/'))

        course_id = course_id_from_url('/courses/edX/maths/2020')
        self.assertEqual(course_id.org, 'edX')
        self.assertEqual(course_id.course, 'maths')
        self.assertEqual(course_id.run, '2020')
Example #2
0
    def country_access_rules(self, user, ip_address, url_path):
        """
        Check the country access rules for a given course.
        Applies only to courseware URLs.

        Args:
            user (User): The user making the current request.
            ip_address (str): The IP address from which the request originated.
            url_path (str): The request path.

        Returns:
            HttpResponse or None

        """
        course_id = course_id_from_url(url_path)

        if course_id:
            redirect_url = embargo_api.redirect_if_blocked(
                course_id,
                user=user,
                ip_address=ip_address,
                url=url_path,
                access_point='courseware'
            )

            if redirect_url:
                return redirect(redirect_url)
Example #3
0
    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
Example #4
0
    def country_access_rules(self, user, ip_address, url_path):
        """
        Check the country access rules for a given course.
        Applies only to courseware URLs.

        Args:
            user (User): The user making the current request.
            ip_address (str): The IP address from which the request originated.
            url_path (str): The request path.

        Returns:
            HttpResponse or None

        """
        course_id = course_id_from_url(url_path)

        if course_id:
            redirect_url = embargo_api.redirect_if_blocked(
                course_id,
                user=user,
                ip_address=ip_address,
                url=url_path,
                access_point='courseware')

            if redirect_url:
                return redirect(redirect_url)
Example #5
0
    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')
Example #6
0
    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')
Example #7
0
    def process_view(self, request, view_func, view_args, view_kwargs):  # pylint: disable=unused-argument
        """
        This function handles authentication logic for wiki urls and redirects from
        the "root wiki" to the "course wiki" if the user accesses the wiki from a course url
        """
        # we care only about requests to wiki urls
        if not view_func.__module__.startswith('wiki.'):
            return

        # wiki pages are login required
        if not request.user.is_authenticated():
            return redirect(reverse('signin_user'), next=request.path)

        course_id = course_id_from_url(request.path)
        wiki_path = request.path.partition('/wiki/')[2]

        if course_id:
            # This is a /courses/org/name/run/wiki request
            course_path = "/courses/{}".format(text_type(course_id))
            # HACK: django-wiki monkeypatches the reverse function to enable
            # urls to be rewritten
            reverse._transform_url = lambda url: course_path + url  # pylint: disable=protected-access
            # Authorization Check
            # Let's see if user is enrolled or the course allows for public access
            try:
                course = get_course_with_access(request.user, 'load',
                                                course_id)
            except Http404:
                # course does not exist. redirect to root wiki.
                # clearing the referrer will cause process_response not to redirect
                # back to a non-existent course
                request.META['HTTP_REFERER'] = ''
                return redirect('/wiki/{}'.format(wiki_path))

            if not course.allow_public_wiki_access:
                is_enrolled = CourseEnrollment.is_enrolled(
                    request.user, course.id)
                is_staff = has_access(request.user, 'staff', course)
                if not (is_enrolled or is_staff):
                    # if a user is logged in, but not authorized to see a page,
                    # we'll redirect them to the course about page
                    return redirect('about_course', text_type(course_id))

                # If we need enterprise data sharing consent for this course, then redirect to the form.
                consent_url = get_enterprise_consent_url(
                    request, text_type(course_id))
                if consent_url:
                    return redirect(consent_url)

            # set the course onto here so that the wiki template can show the course navigation
            request.course = course
        else:
            # this is a request for /wiki/...

            # Check to see if we don't allow top-level access to the wiki via the /wiki/xxxx/yyy/zzz URLs
            # this will help prevent people from writing pell-mell to the Wiki in an unstructured way
            if not settings.FEATURES.get('ALLOW_WIKI_ROOT_ACCESS', False):
                raise PermissionDenied()

            return self._redirect_from_referrer(request, wiki_path)
Example #8
0
    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
Example #9
0
    def process_view(self, request, view_func, view_args, view_kwargs):  # pylint: disable=unused-argument
        """
        This function handles authentication logic for wiki urls and redirects from
        the "root wiki" to the "course wiki" if the user accesses the wiki from a course url
        """
        # we care only about requests to wiki urls
        if not view_func.__module__.startswith('wiki.'):
            return

        # wiki pages are login required
        if not request.user.is_authenticated():
            return redirect(reverse('signin_user'), next=request.path)

        course_id = course_id_from_url(request.path)
        wiki_path = request.path.partition('/wiki/')[2]

        if course_id:
            # This is a /courses/org/name/run/wiki request
            course_path = "/courses/{}".format(course_id.to_deprecated_string())
            # HACK: django-wiki monkeypatches the reverse function to enable
            # urls to be rewritten
            reverse._transform_url = lambda url: course_path + url  # pylint: disable=protected-access
            # Authorization Check
            # Let's see if user is enrolled or the course allows for public access
            try:
                course = get_course_with_access(request.user, 'load', course_id)
            except Http404:
                # course does not exist. redirect to root wiki.
                # clearing the referrer will cause process_response not to redirect
                # back to a non-existent course
                request.META['HTTP_REFERER'] = ''
                return redirect('/wiki/{}'.format(wiki_path))

            if not course.allow_public_wiki_access:
                is_enrolled = CourseEnrollment.is_enrolled(request.user, course.id)
                is_staff = has_access(request.user, 'staff', course)
                if not (is_enrolled or is_staff):
                    # if a user is logged in, but not authorized to see a page,
                    # we'll redirect them to the course about page
                    return redirect('about_course', course_id.to_deprecated_string())

                # If we need enterprise data sharing consent for this course, then redirect to the form.
                consent_url = get_enterprise_consent_url(request, unicode(course_id))
                if consent_url:
                    return redirect(consent_url)

            # set the course onto here so that the wiki template can show the course navigation
            request.course = course
        else:
            # this is a request for /wiki/...

            # Check to see if we don't allow top-level access to the wiki via the /wiki/xxxx/yyy/zzz URLs
            # this will help prevent people from writing pell-mell to the Wiki in an unstructured way
            if not settings.FEATURES.get('ALLOW_WIKI_ROOT_ACCESS', False):
                raise PermissionDenied()

            return self._redirect_from_referrer(request, wiki_path)
    def test_course_id_from_url(self):
        """ Test course_id_from_url(). """

        self.assertIsNone(course_id_from_url('/login'))
        self.assertIsNone(course_id_from_url('/course/edX/maths/2020'))
        self.assertIsNone(course_id_from_url('/courses/edX/maths/'))
        self.assertIsNone(
            course_id_from_url('/api/courses/v1/blocks/edX/maths/2020'))
        self.assertIsNone(
            course_id_from_url(
                '/api/courses/v1/blocks/course-v1:incidental+courseid+formatting'
            ))
        self.assertIsNone(
            course_id_from_url(
                '/api/courses/v41/notcourses/course-v1:incidental+courseid+formatting'
            ))

        course_id = course_id_from_url('/courses/course-v1:edX+maths+2020')
        self.assertCourseIdFieldsMatch(course_id=course_id,
                                       org="edX",
                                       course='maths',
                                       run='2020')

        course_id = course_id_from_url('/courses/edX/maths/2020')
        self.assertCourseIdFieldsMatch(course_id=course_id,
                                       org='edX',
                                       course='maths',
                                       run='2020')

        course_id = course_id_from_url(
            '/api/courses/v1/courses/course-v1:edX+maths+2020')
        self.assertCourseIdFieldsMatch(course_id=course_id,
                                       org='edX',
                                       course='maths',
                                       run='2020')

        course_id = course_id_from_url(
            '/api/courses/v1/courses/edX/maths/2020')
        self.assertCourseIdFieldsMatch(course_id=course_id,
                                       org='edX',
                                       course='maths',
                                       run='2020')
Example #11
0
    def test_course_id_from_url(self):
        """ Test course_id_from_url(). """

        self.assertIsNone(course_id_from_url('/login'))
        self.assertIsNone(course_id_from_url('/course/edX/maths/2020'))
        self.assertIsNone(course_id_from_url('/courses/edX/maths/'))
        self.assertIsNone(course_id_from_url('/api/courses/v1/blocks/edX/maths/2020'))
        self.assertIsNone(course_id_from_url('/api/courses/v1/blocks/course-v1:incidental+courseid+formatting'))
        self.assertIsNone(course_id_from_url('/api/courses/v41/notcourses/course-v1:incidental+courseid+formatting'))

        course_id = course_id_from_url('/courses/course-v1:edX+maths+2020')
        self.assertCourseIdFieldsMatch(course_id=course_id, org="edX", course='maths', run='2020')

        course_id = course_id_from_url('/courses/edX/maths/2020')
        self.assertCourseIdFieldsMatch(course_id=course_id, org='edX', course='maths', run='2020')

        course_id = course_id_from_url('/api/courses/v1/courses/course-v1:edX+maths+2020')
        self.assertCourseIdFieldsMatch(course_id=course_id, org='edX', course='maths', run='2020')

        course_id = course_id_from_url('/api/courses/v1/courses/edX/maths/2020')
        self.assertCourseIdFieldsMatch(course_id=course_id, org='edX', course='maths', run='2020')
Example #12
0
    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
Example #13
0
    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
Example #14
0
 def _redirect_from_referrer(self, request, wiki_path):
     """
     redirect to course wiki url if the referrer is from a course page
     """
     course_id = course_id_from_url(request.META.get('HTTP_REFERER'))
     if course_id:
         # See if we are able to view the course. If we are, redirect to it
         try:
             get_course_overview_with_access(request.user, 'load', course_id)
             return redirect("/courses/{course_id}/wiki/{path}".format(course_id=course_id.to_deprecated_string(), path=wiki_path))
         except Http404:
             # Even though we came from the course, we can't see it. So don't worry about it.
             pass
Example #15
0
    def process_request(self, request):
        """
        Only if the following are all true:
          1. request is a GET
          2. request is NOT to a URL in DISALLOW_SNEAKPEEK_URL_NAMES
          3. request.user is AnonymousUser (This middleware must be added after the AuthenticationMiddleware)
          4. request has a course context
          5. request's course allows sneakpeek
          6. request's course's enrollment period is open
        Does the following:
          1. Registers an anonymous user
          2. Login this user in
          3. Enrolls this user in the course
        """
        ### Start by testing the conditions, each of which can fail fast and return,
        ### causing the middleware to do nothing
        if request.method != "GET":
            return None

        try:
            match = resolve(request.path)
            if match.url_name in DISALLOW_SNEAKPEEK_URL_NAMES:
                return None
        except Http404:
            pass

        if request.user.is_authenticated():
            return None

        course_id = course_id_from_url(request.path)
        if not course_id:
            return None

        if not CoursePreference.course_allows_nonregistered_access(course_id):
            return None

        if not modulestore().has_course(course_id):
            message = u"Sneakpeek attempt for non-existent course %s"
            LOG.warning(message, course_id)
            return None

        can_enroll, _ = _check_can_enroll_in_course(
            request.user, course_id, access_type='within_enrollment_period')

        if not can_enroll:
            return None

        ### OK. We should now do the 3 steps to get the users access to follow the deeplink
        _create_and_login_nonregistered_user(request)
        CourseEnrollment.enroll(request.user, course_id)
        return None
Example #16
0
    def process_request(self, request):
        """
        Only if the following are all true:
          1. request is a GET
          2. request is NOT to a URL in DISALLOW_SNEAKPEEK_URL_NAMES
          3. request.user is AnonymousUser (This middleware must be added after the AuthenticationMiddleware)
          4. request has a course context
          5. request's course allows sneakpeek
          6. request's course's enrollment period is open
        Does the following:
          1. Registers an anonymous user
          2. Login this user in
          3. Enrolls this user in the course
        """
        ### Start by testing the conditions, each of which can fail fast and return,
        ### causing the middleware to do nothing
        if request.method != "GET":
            return None

        try:
            match = resolve(request.path)
            if match.url_name in DISALLOW_SNEAKPEEK_URL_NAMES:
                return None
        except Http404:
            pass

        if request.user.is_authenticated():
            return None

        course_id = course_id_from_url(request.path)
        if not course_id:
            return None

        if not CoursePreference.course_allows_nonregistered_access(course_id):
            return None

        can_enroll, _ = _check_can_enroll_in_course(request.user, course_id, access_type="within_enrollment_period")

        if not can_enroll:
            return None

        ### OK. We should now do the 3 steps to get the users access to follow the deeplink
        _create_and_login_nonregistered_user(request)
        CourseEnrollment.enroll(request.user, course_id)
        return None
Example #17
0
    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
Example #18
0
    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