- Author:
- pakal
- Posted:
- June 26, 2019
- Language:
- Python
- Version:
- Not specified
- Score:
- 0 (after 0 ratings)
This middleware uses Django's Geoip support (https://docs.djangoproject.com/fr/2.2/ref/contrib/gis/geoip2/), as well as axes's package helper to retrieve IP address (since Django's REMOTE_ADDR might be wrong when behind a reverse proxy).
Ensure your geolite DB files are up to date (eg. with https://djangosnippets.org/snippets/10674/).
The checker is optional, but ensures that security is not broken due to a misspelled/missing GEOIP_COUNTRY_WHITELIST.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | import ipaddress
import geoip2.errors
from axes.helpers import get_client_ip_address
from django.conf import settings
from django.contrib.gis.geoip2 import GeoIP2
from django.http import HttpResponseForbidden
from django.utils.deprecation import MiddlewareMixin
class CountryRestrictionMiddleware(MiddlewareMixin):
"""
Restrict access to users that are not in an allowed country.
If GEOIP_COUNTRY_WHITELIST is empty, access blocking is disabled.
"""
def __init__(self, *args, **kwargs):
if MiddlewareMixin != object:
super(CountryRestrictionMiddleware, self).__init__(*args, **kwargs)
whitelist = settings.GEOIP_COUNTRY_WHITELIST or []
whitelist = [country.strip().upper() for country in whitelist]
self.whitelist = whitelist
self.geoip = GeoIP2()
def process_request(self, request):
ip_address = get_client_ip_address(request)
assert ip_address, ip_address
request.country_code = None # Default
ip_address = "200.200.100.100"
if ipaddress.ip_address(ip_address).is_private:
return # Dev mode, or misconfiguration of portal
try:
country = self.geoip.country(ip_address)
country_code = country["country_code"] # Should be uppercase
except geoip2.errors.GeoIP2Error:
country_code = None
if self.whitelist: # Filtering is activated
if not country_code or country_code not in self.whitelist:
return HttpResponseForbidden("Forbidden country '%s'" % country_code)
request.country_code = country_code
return None
############# CHECKER FOR YOUR APP.PY #############
from django.conf import settings
from django.core.checks import Warning, register, Tags
@register(Tags.security)
def check_country_whitelist(app_configs, **kwargs):
errors = []
from django.conf import settings
whitelist = getattr(settings, "GEOIP_COUNTRY_WHITELIST", None)
success = False
if isinstance(whitelist, (list, tuple)):
if all(isinstance(country, str) for country in whitelist):
success = True
if not success:
errors.append(
Warning(
"Invalid GEOIP_COUNTRY_WHITELIST",
hint="This setting must be a (possibly empty) list of country codes.",
obj=None,
id="accounts.E100",
)
)
return errors
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Please login first before commenting.