Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1354

Show
Ignore:
Timestamp:
09/11/06 14:53:21
Author:
lawouach
Message:

Digest and basic auth can now take a callable which must return a dict with user credentials so that it can fetch those from a database for instance.

Basic takes also an encrypt parameter which must be a callable that will encrypt the password sent back the user-agent. So that passwords can be stored encrypted on the server.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/lib/auth.py

    r1353 r1354  
    44 
    55 
    6 def check_auth(users): 
     6def check_auth(users, encrypt=None): 
    77    """If an authorization header contains credentials, return True, else False.""" 
    88    if 'authorization' in cherrypy.request.headers: 
     
    1111        if ah is None: 
    1212            raise cherrypy.HTTPError(400, 'Bad Request') 
    13          
     13 
     14        if not encrypt: 
     15            encrypt = lambda x: x 
     16 
     17        if callable(users): 
     18            users = users() # expect it to return a dictionary 
     19 
     20        if not isinstance(users, dict): 
     21            raise ValueError, "Authentication users must be passed contained in a dictionary" 
     22     
    1423        # fetch the user password 
    1524        password = users.get(ah["username"], None) 
     
    1726        # validate the authorization by re-computing it here 
    1827        # and compare it with what the user-agent provided 
    19         if checkResponse(ah, password, method=cherrypy.request.method): 
     28        if checkResponse(ah, password, method=cherrypy.request.method, encrypt=encrypt): 
    2029            return True 
    2130     
    2231    return False 
    2332 
    24 def basic_auth(realm, users): 
     33def basic_auth(realm, users, encrypt=None): 
    2534    """If auth fails, raise 401 with a basic authentication header. 
    2635     
    2736    realm: a string containing the authentication realm. 
    28     users: a dict of the form: {username: password}. 
     37    users: a dict of the form: {username: password} or a callable returning a dict. 
     38    encrypt: callable used to encrypt the password returned from the user-agent. 
    2939    """ 
    30     if check_auth(users): 
     40    if check_auth(users, encrypt): 
    3141        return 
    3242     
     
    4050     
    4151    realm: a string containing the authentication realm. 
    42     users: a dict of the form: {username: password}
     52    users: a dict of the form: {username: password} or a callable returning a dict
    4353    """ 
    4454    if check_auth(users): 
  • trunk/cherrypy/lib/httpauth.py

    r1352 r1354  
    296296    return KD(H_A1, request) 
    297297 
    298 def _checkDigestResponse(auth_map, password, method = "GET", A1 = None,**kwargs): 
     298def _checkDigestResponse(auth_map, password, method = "GET", A1 = None, **kwargs): 
    299299    """This function is used to verify the response given by the client when 
    300300    he tries to authenticate. 
     
    309309    return response == auth_map["response"] 
    310310 
    311 def _checkBasicResponse (auth_map, password, method='GET', **kwargs): 
    312     return auth_map["password"] == password 
     311def _checkBasicResponse (auth_map, password, method='GET', encrypt=None, **kwargs): 
     312    return encrypt(auth_map["password"]) == password 
    313313 
    314314AUTH_RESPONSES = { 
     
    317317} 
    318318 
    319 def checkResponse (auth_map, password, method = "GET", **kwargs): 
     319def checkResponse (auth_map, password, method = "GET", encrypt=None, **kwargs): 
    320320    """'checkResponse' compares the auth_map with the password and optionally 
    321321    other arguments that each implementation might need. 
     
    336336    global AUTH_RESPONSES 
    337337    checker = AUTH_RESPONSES[auth_map["auth_scheme"]] 
    338     return checker (auth_map, password, method, **kwargs) 
     338    return checker (auth_map, password, method=method, encrypt=encrypt, **kwargs) 
    339339  
    340340 
  • trunk/cherrypy/test/test_httpauth.py

    r1351 r1354  
    11from cherrypy.test import test 
    22test.prefer_parent_path() 
     3 
     4import md5 
    35 
    46import cherrypy 
     
    2123        index.exposed = True 
    2224 
     25    def md5_encrypt(data): 
     26        return md5.new(data).hexdigest() 
     27 
     28    def fetch_users(): 
     29        return {'test': 'test'} 
     30 
    2331    conf = {'/digest': {'tools.digestauth.on': True, 
    2432                        'tools.digestauth.realm': 'localhost', 
    25                         'tools.digestauth.users': {'test': 'test'}}, 
     33                        'tools.digestauth.users': fetch_users}, 
    2634            '/basic': {'tools.basicauth.on': True, 
    2735                       'tools.basicauth.realm': 'localhost', 
    28                        'tools.basicauth.users': {'test': 'test'}}} 
     36                       'tools.basicauth.users': {'test': md5_encrypt('test')}, 
     37                       'tools.basicauth.encrypt': md5_encrypt}} 
    2938    root = Root() 
    3039    root.digest = DigestProtected() 
     
    97106 
    98107            # now let's see if what  
    99             base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"' 
     108        base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"' 
    100109 
    101             auth = base_auth % (nonce, '', '00000001') 
     110        auth = base_auth % (nonce, '', '00000001') 
    102111                 
    103             params = httpauth.parseAuthorization(auth) 
    104             response = httpauth._computeDigestResponse(params, 'test') 
     112        params = httpauth.parseAuthorization(auth) 
     113        response = httpauth._computeDigestResponse(params, 'test') 
     114         
     115        auth = base_auth % (nonce, response, '00000001') 
     116        self.getPage('/digest/', [('Authorization', auth)]) 
     117        self.assertStatus('200 OK') 
     118        self.assertBody('This is protected by Digest auth.') 
    105119             
    106             auth = base_auth % (nonce, response, '00000001') 
    107             self.getPage('/digest/', [('Authorization', auth)]) 
    108             self.assertStatus('200 OK') 
    109             self.assertBody('This is protected by Digest auth.') 
    110  
    111120if __name__ == "__main__": 
    112121    setup_server() 

Hosted by WebFaction

Log in as guest/cpguest to create tickets