Commits

Lynn Rees committed 6b99c38

[svn]

  • Participants
  • Parent commits 289937c
  • Branches wsgiauth

Comments (0)

Files changed (3)

trunk/wsgiauth/basic.py

 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 # This code was written with funding by http://prometheusresearch.com
 
-"""
-Basic HTTP/1.0 Authentication
+'''Basic HTTP/1.0 Authentication
 
 This module implements ``Basic`` authentication as described in
 HTTP/1.0 specification [1]_ .  Do not use this module unless you
 use ``digest`` authentication.
 
 .. [1] http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BasicAA
-"""
+'''
 
 
-class AuthBasicAuthenticator:
-    """
-    implements ``Basic`` authentication details
-    """
+class BasicAuth(object):
+
+    '''implements ``Basic`` authentication details'''
+    
+    def __init__(self, realm, authfunc, **kw):
+        self.realm, self.authfunc = realm, authfunc
+        self.errorhandler = kw.get('errhandler', self.authresponse)
 
-    def __init__(self, realm, authfunc, use401=True, errhandler=None):
-        self.realm = realm
-        self.authfunc = authfunc
-        self.use401 = use401
-        self.errorhandler = errhandler
-
-    def build_authentication(self, environ, start_response):
+    def authresponse(self, environ, start_response):
         start_response('401 Unauthorized', [("content-type","text/plain"),
             ("WWW-Authenticate", 'Basic realm="%s"' % self.realm)])
-        if self.use401:
-            return ['This server could not verify that you are authorized to\r\n'
+        return ['This server could not verify that you are authorized to\r\n'
             'access the document you requested.  Either you supplied the\r\n'
             'wrong credentials (e.g., bad password), or your browser\r\n'
-            'does not understand how to supply the credentials required.\r\n']
-        else:
-             return self.errorhandler(environ, start_response)
+            'does not understand how to supply the credentials required.\r\n']
 
     def __call__(self, environ):
         authorization = environ.get('HTTP_AUTHORIZATION')
-        if authorization is None: return self.build_authentication
+        if authorization is None: return self.errorhandler
         authmeth, auth = authorization.split(' ', 1)
-        if 'basic' != authmeth.lower(): return self.build_authentication
+        if 'basic' != authmeth.lower(): return self.errorhandler
         auth = auth.strip().decode('base64')
         username, password = auth.split(':', 1)
         if self.authfunc(environ, username, password): return username
         return self.build_authentication
+
 
-class AuthBasicHandler:
-    """
-    HTTP/1.0 ``Basic`` authentication middleware
+class WsgiBasicAuth(object):
+
+    '''HTTP/1.0 ``Basic`` authentication middleware
 
     Parameters:
 
             ``environ``, ``username`` and ``password`` for its first
             three arguments.  It should return ``True`` if the user is
             authenticated.
-
-    """
+    '''
+    
     def __init__(self, application, realm, authfunc):
         self.application = application
-        self.authenticate = AuthBasicAuthenticator(realm, authfunc)
+        self.authenticate = BasicAuth(realm, authfunc)
 
     def __call__(self, environ, start_response):
         username = environ.get('REMOTE_USER', None)
         return self.application(environ, start_response)
 
 
-def basic(realm, authfunc):
-    '''Decorator for simple cache.'''
+def basic(realm, authfunc, **kw):
+    '''Decorator for basic authentication.'''
     def decorator(application):
-        return AuthBasicHandler(application, realm, authfunc)
+        return WsgiBasicAuth(application, realm, authfunc, **kw)
     return decorator
 
 
-__all__ = ['AuthBasicHandler']
+__all__ = ['WsgiBasicAuth', 'basic']

trunk/wsgiauth/grantip.py

-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Grant roles and logins based on IP address.
-"""
-
-from paste.util import ip4
-
-
-class GrantIPMiddleware(object):
-
-    """
-    On each request, ``ip_map`` is checked against ``REMOTE_ADDR``
-    and logins and roles are assigned based on that.
-
-    ``ip_map`` is a map of {ip_mask: (username, roles)}.  Either
-    ``username`` or ``roles`` may be None.  Roles may also be prefixed
-    with ``-``, like ``'-system'`` meaning that role should be
-    revoked.  ``'__remove__'`` for a username will remove the username.
-
-    If ``clobber_username`` is true (default) then any user
-    specification will override the current value of ``REMOTE_USER``.
-    ``'__remove__'`` will always clobber the username.
-
-    ``ip_mask`` is something that `paste.util.ip4:IP4Range
-    <class-paste.util.ip4.IP4Range.html>`_ can parse.  Simple IP
-    addresses, IP/mask, ip<->ip ranges, and hostnames are allowed.
-    """
-
-    def __init__(self, app, ip_map, clobber_username=True):
-        self.app = app
-        self.ip_map = []
-        for key, value in ip_map.items():
-            self.ip_map.append((ip4.IP4Range(key),
-                                self._convert_user_role(value[0], value[1])))
-        self.clobber_username = clobber_username
-
-    def _convert_user_role(self, username, roles):
-        if roles and isinstance(roles, basestring):
-            roles = roles.split(',')
-        return (username, roles)
-        
-    def __call__(self, environ, start_response):
-        addr = ip4.ip2int(environ['REMOTE_ADDR'], False)
-        remove_user = False
-        add_roles = []
-        for range, (username, roles) in self.ip_map:
-            if addr in range:
-                if roles:
-                    add_roles.extend(roles)
-                if username == '__remove__':
-                    remove_user = True
-                elif username:
-                    if (not environ.get('REMOTE_USER')
-                        or self.clobber_username):
-                        environ['REMOTE_USER'] = username
-        if (remove_user and 'REMOTE_USER' in environ):
-            del environ['REMOTE_USER']
-        if roles:
-            self._set_roles(environ, add_roles)
-        return self.app(environ, start_response)
-
-    def _set_roles(self, environ, roles):
-        cur_roles = environ.get('REMOTE_USER_TOKENS', '').split(',')
-        # Get rid of empty roles:
-        cur_roles = filter(None, cur_roles)
-        remove_roles = []
-        for role in roles:
-            if role.startswith('-'):
-                remove_roles.append(role[1:])
-            else:
-                if role not in cur_roles:
-                    cur_roles.append(role)
-        for role in remove_roles:
-            if role in cur_roles:
-                cur_roles.remove(role)
-        environ['REMOTE_USER_TOKENS'] = ','.join(cur_roles)
-        
-                
-def make_grantip(app, global_conf, clobber_username=False, **kw):
-    """
-    Grant roles or usernames based on IP addresses.
-
-    Config looks like this::
-
-      [filter:grant]
-      use = egg:Paste#grantip
-      clobber_username = true
-      # Give localhost system role (no username):
-      127.0.0.1 = -:system
-      # Give everyone in 192.168.0.* editor role:
-      192.168.0.0/24 = -:editor
-      # Give one IP the username joe:
-      192.168.0.7 = joe
-      # And one IP is should not be logged in:
-      192.168.0.10 = __remove__:-editor
-      
-    """
-    from paste.deploy.converters import asbool
-    clobber_username = asbool(clobber_username)
-    ip_map = {}
-    for key, value in kw.items():
-        if ':' in value:
-            username, role = value.split(':', 1)
-        else:
-            username = value
-            role = ''
-        if username == '-':
-            username = ''
-        if role == '-':
-            role = ''
-        ip_map[key] = value
-    return GrantIPMiddleware(app, ip_map, clobber_username)

trunk/wsgiauth/ip.py

+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+'''Authenticate based on IP address.'''
+
+def authfunc(environ, ipaddr):
+    '''An example IP authentication function. 'environ'
+    contains a REMOTE_USER header that has been set by some
+    other authentication method and that name is matched against the
+    IP address that user should be using.
+
+    @param environ Environment dict
+    @param ipaddr Remote IP address
+    '''
+    return environ['REMOTE_USER'] == ip_user_map[ipaddr]
+
+
+class IPAuth(object):
+
+    '''On each request, `REMOTE_ADDR` is authenticated and access is allowed
+    based on that.
+    '''
+
+    def __init__(self, app, authfunc, **kw):
+        self.app, self.authfunc = app, authfunc 
+        self.handler = kw.gethandler('handler', self.authresponse)
+
+    def authresponse(self, environ, start_response):
+        start_response('403 Forbidden', ('content-type', 'text/plain'))
+        return ['This server could not verify that you are authorized to\r\n'
+            'access the resource you requested from your current location.\r\n']                                     
+        
+    def __call__(self, environ, start_response):
+        ipaddr = environ.get('REMOTE_ADDR')
+        if not authfunc(environ, ipaddr): return self.handler            
+        return self.app(environ, start_response)
+        
+                
+def ipauth(authfunc):
+    '''Decorator for IP address-based authentication.'''
+    def decorator(application):
+        return IPAuth(application, realm, authfunc)
+    return decorator
+
+__all__ = ['IPAuth', 'ipauth']