This is a very basic, easily foolable, restriction method implemented in a Django middleware.
However, for low security sites that need a cursory barrier to entry (without the ability to assign/administer user accounts), this does very well.
All of the features are fairly well-documented in the code.
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 132 133 134 | from django.http import HttpResponseForbidden
from django.conf import settings
class RestrictMiddleware(object):
"""
This middleware rejects certain requests depending on
four tests which are detailed in this classes'
`process_request` method.
All parameters for the operation of this middleware should
be defined in your settings.py file.
Adding this middleware to your project without specifying
any parameters will result in a default policy of all
requests being denied.
Valid settings options follow:
RESTRICT_IP_WHITELIST: a list or tuple of strings representing
IP addresses
RESTRICT_REFERRER_WHITELIST: a list or tuple of strings to be
searched as substrings in a request's HTTP_REFERRER
RESTRICT_GET_CODE: a dictionary of key/value pairs which, if
specified, will be checked for complete equality with a
client's GET paramters.
RESTRICT_COOKIE_NAME: a string representing the name of a cookie
that will be checked at the beginning of the process and will be
set if any of the tests pass.
RESTRICT_ACCESS_DENIED_MESSAGE: a string that will be displayed
to the user in the event of no tests being passed.
"""
IP_WHITELIST = []
REFERRER_WHITELIST = []
IP_BLACKLIST = []
GET_CODE = {}
COOKIE_NAME = 'auth'
ACCESS_DENIED_MESSAGE = 'Access Denied'
def process_request(self, request):
"""
Processes the HTTP request against a number of tests to determine
if access should be granted.
First, if the user has a particular cookie set to 'True', they
are passed through without further tests.
Second, the client's IP address is checked against an IP whitelist.
Third, the client's request's GET paramters are checked against
an optional set of key value pairs.
Fourth, the client's HTTP referrer is checked against a referrer
whitelist.
The user is considered valid if any one of the tests are evaluated
to be true.
If none of the tests pass, the user's request is rejected.
"""
cn = getattr(settings, 'RESTRICT_COOKIE_NAME', self.COOKIE_NAME)
if not request.session.get(cn, False):
ip = request.META['REMOTE_ADDR']
referrer = request.META.get('HTTP_REFERER', None)
ipw = getattr(settings, 'RESTRICT_IP_WHITELIST', self.IP_WHITELIST)
if (ip in ipw or self.valid_host(request, referrer)):
request.session[cn] = True
else:
return self.reject_request()
return None
def valid_host(self, request, ref):
"""
Checks the the RESTRICT_GET_CODE. It also checks the
referrer against a whitelist.
Accepts:
* request: this is a Django request object
* ref: the client's referrer string
Returns:
* True if the client is valid
* False if the client is not valid
Validity in this method is defined by passing one of the
following two tests.
There can be anywhere from 0 to n get codes which are key-
value pairs. These are checked against any GET parameters.
If any get codes are specified, all must be present and
both key and value must match. If there is a complete
match, then this function is short circuited and no
other values (such as referrer) are checked.
If there were no get codes specified, or if they did
not match completely, the referrer is checked against
a list of valid referrers. If any of the strings in the
RESTRICT_REFERRER_WHITELIST are found in any substring of
the client's referrer, then they are passed on as valid.
"""
### In our particular use case, the get code trumps all
g = None
gc = getattr(settings, 'RESTRICT_GET_CODE', self.GET_CODE)
if gc:
for parameter in gc.keys():
v = request.GET.get(parameter, None)
if v and v == gc[parameter]:
g = True
else:
g = False
if g != None and g == True:
return True
## If they didn't have all the get codes, we check referrer
rw = getattr(settings, 'RESTRICT_REFERRER_WHITELIST', self.REFERRER_WHITELIST)
if ref:
if rw:
for host in rw:
if (host.lower() in ref.lower()) or (ref.lower() in host.lower()):
return True
return False
def reject_request(self):
"""
Determines which user-facing message to display, and then
returns an HTTP Forbidden response along with that message.
"""
m = getattr(settings, 'RESTRICT_ACCESS_DENIED_MESSAGE', self.ACCESS_DENIED_MESSAGE)
return HttpResponseForbidden(m)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
The code in lines 110-117 (testing for the RESTRICT_GET_CODE cases) has a serious error in it. As it is, each iteration an element of the RESTRICT_GET_CODE dict is compared; however, only the last key checked seems to make any difference since the pass/fail value of prior comparisons is completely overwritten on each iteration. You could fix this most easily by short circuiting out of the
for
loop after you assigng=False
in theif
statement with abreak
. You could also tighten up the code significantly if you added the rarely usedelse
clause onto thefor
loop itself:#
Please login first before commenting.