Home | History | Annotate | Download | only in auth
      1 # (c) 2005 Clark C. Evans
      2 # This module is part of the Python Paste Project and is released under
      3 # the MIT License: http://www.opensource.org/licenses/mit-license.php
      4 # This code was written with funding by http://prometheusresearch.com
      5 """
      6 Basic HTTP/1.0 Authentication
      7 
      8 This module implements ``Basic`` authentication as described in
      9 HTTP/1.0 specification [1]_ .  Do not use this module unless you
     10 are using SSL or need to work with very out-dated clients, instead
     11 use ``digest`` authentication.
     12 
     13 >>> from paste.wsgilib import dump_environ
     14 >>> from paste.httpserver import serve
     15 >>> # from paste.auth.basic import AuthBasicHandler
     16 >>> realm = 'Test Realm'
     17 >>> def authfunc(environ, username, password):
     18 ...     return username == password
     19 >>> serve(AuthBasicHandler(dump_environ, realm, authfunc))
     20 serving on...
     21 
     22 .. [1] http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BasicAA
     23 """
     24 from paste.httpexceptions import HTTPUnauthorized
     25 from paste.httpheaders import *
     26 
     27 class AuthBasicAuthenticator(object):
     28     """
     29     implements ``Basic`` authentication details
     30     """
     31     type = 'basic'
     32     def __init__(self, realm, authfunc):
     33         self.realm = realm
     34         self.authfunc = authfunc
     35 
     36     def build_authentication(self):
     37         head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
     38         return HTTPUnauthorized(headers=head)
     39 
     40     def authenticate(self, environ):
     41         authorization = AUTHORIZATION(environ)
     42         if not authorization:
     43             return self.build_authentication()
     44         (authmeth, auth) = authorization.split(' ', 1)
     45         if 'basic' != authmeth.lower():
     46             return self.build_authentication()
     47         auth = auth.strip().decode('base64')
     48         username, password = auth.split(':', 1)
     49         if self.authfunc(environ, username, password):
     50             return username
     51         return self.build_authentication()
     52 
     53     __call__ = authenticate
     54 
     55 class AuthBasicHandler(object):
     56     """
     57     HTTP/1.0 ``Basic`` authentication middleware
     58 
     59     Parameters:
     60 
     61         ``application``
     62 
     63             The application object is called only upon successful
     64             authentication, and can assume ``environ['REMOTE_USER']``
     65             is set.  If the ``REMOTE_USER`` is already set, this
     66             middleware is simply pass-through.
     67 
     68         ``realm``
     69 
     70             This is a identifier for the authority that is requesting
     71             authorization.  It is shown to the user and should be unique
     72             within the domain it is being used.
     73 
     74         ``authfunc``
     75 
     76             This is a mandatory user-defined function which takes a
     77             ``environ``, ``username`` and ``password`` for its first
     78             three arguments.  It should return ``True`` if the user is
     79             authenticated.
     80 
     81     """
     82     def __init__(self, application, realm, authfunc):
     83         self.application = application
     84         self.authenticate = AuthBasicAuthenticator(realm, authfunc)
     85 
     86     def __call__(self, environ, start_response):
     87         username = REMOTE_USER(environ)
     88         if not username:
     89             result = self.authenticate(environ)
     90             if isinstance(result, str):
     91                 AUTH_TYPE.update(environ, 'basic')
     92                 REMOTE_USER.update(environ, result)
     93             else:
     94                 return result.wsgi_application(environ, start_response)
     95         return self.application(environ, start_response)
     96 
     97 middleware = AuthBasicHandler
     98 
     99 __all__ = ['AuthBasicHandler']
    100 
    101 def make_basic(app, global_conf, realm, authfunc, **kw):
    102     """
    103     Grant access via basic authentication
    104 
    105     Config looks like this::
    106 
    107       [filter:grant]
    108       use = egg:Paste#auth_basic
    109       realm=myrealm
    110       authfunc=somepackage.somemodule:somefunction
    111 
    112     """
    113     from paste.util.import_string import eval_import
    114     import types
    115     authfunc = eval_import(authfunc)
    116     assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
    117     return AuthBasicHandler(app, realm, authfunc)
    118 
    119 
    120 if "__main__" == __name__:
    121     import doctest
    122     doctest.testmod(optionflags=doctest.ELLIPSIS)
    123