Restrict Middleware

  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

  1. Restrict staff access to admin pages by slink 3 years, 6 months ago
  2. KMZMiddleware by giovabal 6 years ago
  3. Row-Level, URL-based permissions for FlatPages by bradmontgomery 4 years, 10 months ago
  4. Restrict Flatpage To Group by nikolaj 6 years ago
  5. feedburner middleware by V 5 years, 7 months ago

Comments

wam (on August 22, 2012):

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 assign g=False in the if statement with a break. You could also tighten up the code significantly if you added the rarely used else clause onto the for loop itself:

### In our particular use case, the get code trumps all
gc = getattr(settings, 'RESTRICT_GET_CODE', self.GET_CODE)
if gc:
    for parameter in gc.keys():
        v = request.GET.get(parameter, None)
        if not v or v != gc[parameter]:
            break
    else:
        return True

#

(Forgotten your password?)