forked from nsb/imagedbproject
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmiddleware.py
133 lines (118 loc) · 5.95 KB
/
middleware.py
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""Django middleware to redirect requests based on originating IP address
Contains the IPAddressMiddleware class used to redirect requests based
on whether the originating IP is in a set of registered addresses or
not. Both IPv4, and IPv6 addresses can be handled.
External dependencies: The netaddr library,
http://code.google.com/p/netaddr/ , is used for handling IP addresses
Currently tested with Django 1.1-beta-1 (SVN checkout on 2009-JUL-02,
and netaddr 0.6.3. Live testing has only been done with IPv4 addresses.
"""
import netaddr
from django.conf import settings
from django.contrib import admin
import django.contrib.auth.views
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
import files.views
class IPAddressMiddleware(object):
"""Middleware to redirect requests based on originating IP address.
IP addresses are classified into two categories:
- Registered addresses defined in settings.py as a list
- Non-registered addresses: Anything that is not listed in the above
set of registered addresses.
Requests from registered IP addresses are handled as follows:
- Allow access without logging in for non-admin. views. Users are
shown a login screen, but can just click the login button to
get in.
- Normal admin. login for admin. views, except for a special
login page.
No special handling of requests from non-registered IP addresses. Log
in, and proceed as normal for all users, showing the standard login
page.
"""
def __init__(self):
"""Initialises the list of registered IP addresses.
"""
self.ip_reg = []
try:
ip_settings = eval( str(getattr(settings, 'SRJ_IP_REG', '[]')) )
for ip in ip_settings:
if hasattr( ip, '__iter__' ):
# Sequence value => range of IP addresses
self.ip_reg.append( netaddr.IPRange( ip[0], ip[1] ) )
else:
# Single value => normal IP, though can also be range
self.ip_reg.append( netaddr.IP( ip ) )
except Exception:
raise
def _call_viewfunc(self, func, request, args, kwargs):
"""Calls a Django view function passed to process_view()
Needs to be done this way as else it apparently exercises a
bug in Django, with an error 'dict objects are unhashable'
"""
if args:
return func( request, *args, **kwargs ) if kwargs else \
func( request, *args )
else:
return func( request, **kwargs ) if kwargs else func( request )
def process_view(self, request, viewfunc, args, kwargs):
view = request.get_full_path()
# The incoming IP address is normally request.META.get('REMOTE_ADDR')
# except for hosting providers like webfactional.com, who use a
# a reverse proxy that sets REMOTE_ADDR to 127.0.0.1. For
# webfactional.com, use the following code, but if not behind a
# reverse proxy, REMOTE_ADDR should be used, as HTTP_X_FORWARDED_FOR
# can be spoofed. See comments in SetRemoteAddrFromForwardedFor()
# in django/middleware/http.py
#
# Uncomment the following line, and comment the next one to use
# REMOTE_ADDR.
# incoming = request.META.get('REMOTE_ADDR')
#incoming = request.META['HTTP_X_FORWARDED_FOR'].split(",")[0].strip()
incoming = getattr( request.META, 'HTTP_X_FORWARDED_FOR',
request.META.get('REMOTE_ADDR') )
# This is really needed only for HTTP_X_FORWARDED_FOR, which can be
# a comma-separated list of IPs. The client's IP will be the first.
if incoming:
incoming = incoming.split( ',' )[0].strip()
is_ip_reg = False
for ip in self.ip_reg:
# Following covers single addresses, and all address ranges
if incoming in ip.iprange():
is_ip_reg = True
break
if view.startswith('/login/') or view == '/':
# For login view setup appropriate templates
if is_ip_reg:
kwargs['template_name'] = getattr( settings,
'SRJ_TMPL_LOGIN_REG',
'login_reg.html' )
else:
kwargs['template_name'] = getattr( settings,
'SRJ_TMPL_LOGIN_UNREG',
'login.html' )
return self._call_viewfunc( django.contrib.auth.views.login,
request, args, kwargs )
elif view.startswith('/logout/') or view.startswith('/password/'):
return self._call_viewfunc( eval( 'django.contrib.auth.views.' + \
viewfunc.__name__ ),
request, (), {} )
elif view.startswith('/login_reg'):
if not is_ip_reg:
return HttpResponseRedirect( '/login/' )
elif view.startswith('/static/') or view.startswith('/media/'):
# Simply serve static media, and Django admin. media
return self._call_viewfunc( viewfunc, request, args, kwargs )
elif view == '/contact/' or view == '/howto/':
# direct_to_template views
return
else:
# For all other views, if non-admin views are required, return
# them for users from registered IPs.
if is_ip_reg:
# FIXME: Change this to non-deprecated mode.
admin_root = reverse( admin.site.root, args=[''] )
if not view.startswith( admin_root ):
return self._call_viewfunc( eval( 'files.views.' + \
viewfunc.__name__ ),
request, args, kwargs )