Require login if not in authorized IP range

This commit is contained in:
Alexandre Iooss 2021-09-23 11:41:35 +02:00
parent d59fb154b6
commit 6f67b855ac
4 changed files with 56 additions and 2 deletions

48
photo21/middleware.py Normal file
View file

@ -0,0 +1,48 @@
from django.http import HttpResponseRedirect
from django.conf import settings
import ipaddress
import re
class LoginRequiredMiddleware:
"""
If user is not accessing the site from an authorized IP, force
authentification.
"""
def __init__(self, get_response):
"""Init middleware"""
self.get_response = get_response
self.whitelist_re = re.compile("^/accounts/.*$")
def __call__(self, request):
"""
If user is not authenticated and external, redirect to login view
before calling the view.
"""
if not request.user.is_authenticated and not self.check_ip(request):
if not self.whitelist_re.match(request.path_info):
return HttpResponseRedirect(settings.LOGIN_URL)
response = self.get_response(request)
return response
def check_ip(self, request):
"""
Return true if IP is in authorized range
"""
# Get IP address
if 'HTTP_X_REAL_IP' in request.META:
ip = request.META.get('HTTP_X_REAL_IP')
elif 'HTTP_X_FORWARDED_FOR' in request.META:
ip = request.META.get('HTTP_X_FORWARDED_FOR').split(', ')[0]
else:
ip = request.META.get('REMOTE_ADDR')
ip = ipaddress.ip_address(ip)
# Check against ranges
if hasattr(settings, 'LOGIN_EXEMPT_IP_RANGE'):
for ip_range in settings.LOGIN_EXEMPT_IP_RANGE:
net = ip_network(ip_range)
if ip in net:
return True
return False

View file

@ -57,6 +57,7 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware', 'django.contrib.sites.middleware.CurrentSiteMiddleware',
'photo21.middleware.LoginRequiredMiddleware',
] ]
ROOT_URLCONF = 'photo21.urls' ROOT_URLCONF = 'photo21.urls'
@ -163,3 +164,6 @@ SITE_ID = 1
# Photologue # Photologue
PHOTOLOGUE_GALLERY_SAMPLE_SIZE = 1 PHOTOLOGUE_GALLERY_SAMPLE_SIZE = 1
# IP range whitelist
LOGIN_EXEMPT_IP_RANGE = ["185.230.76.0/22", "2a0c:700::/32"]

View file

@ -17,13 +17,15 @@ from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib.auth.decorators import login_required
from .views import IndexView from .views import IndexView
# photologue_custom overrides some photologue patterns
urlpatterns = [ urlpatterns = [
path('', IndexView.as_view(), name='index'), path('', IndexView.as_view(), name='index'),
path('photologue/', include('photologue_custom.urls')),
path('photologue/', include('photologue.urls', namespace='photologue')), path('photologue/', include('photologue.urls', namespace='photologue')),
path('photologue_custom/', include('photologue_custom.urls')),
path('accounts/', include('django.contrib.auth.urls')), path('accounts/', include('django.contrib.auth.urls')),
path('i18n/', include('django.conf.urls.i18n')), path('i18n/', include('django.conf.urls.i18n')),
path('admin/', admin.site.urls), path('admin/', admin.site.urls),

View file

@ -3,5 +3,5 @@ from django.urls import path
from .views import TagDetail from .views import TagDetail
urlpatterns = [ urlpatterns = [
path('tags/<slug:slug>/', TagDetail.as_view(), name='tag-detail'), path('tag/<slug:slug>/', TagDetail.as_view(), name='tag-detail'),
] ]