106 lines
4.1 KiB
Python
106 lines
4.1 KiB
Python
"""Middleware for embargoing site and courses.
|
|
|
|
IMPORTANT NOTE: This code WILL NOT WORK if you have a misconfigured proxy
|
|
server. If you are configuring embargo functionality, or if you are
|
|
experiencing mysterious problems with embargoing, please check that your
|
|
reverse proxy is setting any of the well known client IP address headers (ex.,
|
|
HTTP_X_FORWARDED_FOR).
|
|
|
|
This middleware allows you to:
|
|
|
|
* Embargoing courses (access restriction by courses)
|
|
* Embargoing site (access restriction of the main site)
|
|
|
|
Embargo can restrict by states and whitelist/blacklist (IP Addresses
|
|
(ie. 10.0.0.0) or Networks (ie. 10.0.0.0/24)).
|
|
|
|
Usage:
|
|
|
|
# Enable the middleware in your settings
|
|
|
|
# To enable Embargo for particular courses, set:
|
|
FEATURES['EMBARGO'] = True # blocked ip will be redirected to /embargo
|
|
|
|
# To enable the Embargo feature for the whole site, set:
|
|
FEATURES['SITE_EMBARGOED'] = True
|
|
|
|
# With SITE_EMBARGOED, you can define an external url to redirect with:
|
|
EMBARGO_SITE_REDIRECT_URL = 'https://www.edx.org/'
|
|
|
|
# if EMBARGO_SITE_REDIRECT_URL is missing, a HttpResponseForbidden is returned.
|
|
|
|
"""
|
|
import logging
|
|
import pygeoip
|
|
|
|
from django.core.exceptions import MiddlewareNotUsed
|
|
from django.conf import settings
|
|
from django.shortcuts import redirect
|
|
from django.http import HttpResponseRedirect, HttpResponseForbidden
|
|
from ipware.ip import get_ip
|
|
from util.request import course_id_from_url
|
|
|
|
from embargo.models import EmbargoedCourse, EmbargoedState, IPFilter
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class EmbargoMiddleware(object):
|
|
"""
|
|
Middleware for embargoing site and courses
|
|
|
|
This is configured by creating ``EmbargoedCourse``, ``EmbargoedState``, and
|
|
optionally ``IPFilter`` rows in the database, using the django admin site.
|
|
"""
|
|
def __init__(self):
|
|
self.site_enabled = settings.FEATURES.get('SITE_EMBARGOED', False)
|
|
# If embargoing is turned off, make this middleware do nothing
|
|
if not settings.FEATURES.get('EMBARGO', False) and \
|
|
not self.site_enabled:
|
|
raise MiddlewareNotUsed()
|
|
|
|
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
|