~j5-dev/+junk/cherrypy3-3.2.0rc1

« back to all changes in this revision

Viewing changes to cherrypy/lib/auth_basic.py

  • Committer: steveh at sjsoft
  • Date: 2010-07-01 13:07:15 UTC
  • Revision ID: steveh@sjsoft.com-20100701130715-w56oim8346qzqlka
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This file is part of CherryPy <http://www.cherrypy.org/>
 
2
# -*- coding: utf-8 -*-
 
3
# vim:ts=4:sw=4:expandtab:fileencoding=utf-8
 
4
 
 
5
__doc__ = """Module auth_basic.py provides a CherryPy 3.x tool which implements
 
6
the server-side of HTTP Basic Access Authentication, as described in RFC 2617.
 
7
 
 
8
Example usage, using the built-in checkpassword_dict function which uses a dict
 
9
as the credentials store:
 
10
 
 
11
userpassdict = {'bird' : 'bebop', 'ornette' : 'wayout'}
 
12
checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(userpassdict)
 
13
basic_auth = {'tools.auth_basic.on': True,
 
14
              'tools.auth_basic.realm': 'earth',
 
15
              'tools.auth_basic.checkpassword': checkpassword,
 
16
}
 
17
app_config = { '/' : basic_auth }
 
18
"""
 
19
 
 
20
__author__ = 'visteya'
 
21
__date__ = 'April 2009'
 
22
 
 
23
import binascii
 
24
import base64
 
25
import cherrypy
 
26
 
 
27
 
 
28
def checkpassword_dict(user_password_dict):
 
29
    """Returns a checkpassword function which checks credentials
 
30
    against a dictionary of the form: {username : password}.
 
31
 
 
32
    If you want a simple dictionary-based authentication scheme, use
 
33
    checkpassword_dict(my_credentials_dict) as the value for the
 
34
    checkpassword argument to basic_auth().
 
35
    """
 
36
    def checkpassword(realm, user, password):
 
37
        p = user_password_dict.get(user)
 
38
        return p and p == password or False
 
39
 
 
40
    return checkpassword
 
41
 
 
42
 
 
43
def basic_auth(realm, checkpassword, debug=False):
 
44
    """basic_auth is a CherryPy tool which hooks at before_handler to perform
 
45
    HTTP Basic Access Authentication, as specified in RFC 2617.
 
46
 
 
47
    If the request has an 'authorization' header with a 'Basic' scheme, this
 
48
    tool attempts to authenticate the credentials supplied in that header.  If
 
49
    the request has no 'authorization' header, or if it does but the scheme is
 
50
    not 'Basic', or if authentication fails, the tool sends a 401 response with
 
51
    a 'WWW-Authenticate' Basic header.
 
52
 
 
53
    Arguments:
 
54
    realm: a string containing the authentication realm.
 
55
 
 
56
    checkpassword: a callable which checks the authentication credentials.
 
57
        Its signature is checkpassword(realm, username, password). where
 
58
        username and password are the values obtained from the request's
 
59
        'authorization' header.  If authentication succeeds, checkpassword
 
60
        returns True, else it returns False.
 
61
    """
 
62
    
 
63
    if '"' in realm:
 
64
        raise ValueError('Realm cannot contain the " (quote) character.')
 
65
    request = cherrypy.serving.request
 
66
    
 
67
    auth_header = request.headers.get('authorization')
 
68
    if auth_header is not None:
 
69
        try:
 
70
            scheme, params = auth_header.split(' ', 1)
 
71
            if scheme.lower() == 'basic':
 
72
                # since CherryPy claims compability with Python 2.3, we must use
 
73
                # the legacy API of base64
 
74
                username_password = base64.decodestring(params)
 
75
                username, password = username_password.split(':', 1)
 
76
                if checkpassword(realm, username, password):
 
77
                    if debug:
 
78
                        cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC')
 
79
                    request.login = username
 
80
                    return # successful authentication
 
81
        except (ValueError, binascii.Error): # split() error, base64.decodestring() error
 
82
            raise cherrypy.HTTPError(400, 'Bad Request')
 
83
    
 
84
    # Respond with 401 status and a WWW-Authenticate header
 
85
    cherrypy.serving.response.headers['www-authenticate'] = 'Basic realm="%s"' % realm
 
86
    raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
 
87