2014-03-10 01:18:05 -04:00
|
|
|
# This file is part of CherryPy <http://www.cherrypy.org/>
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# vim:ts=4:sw=4:expandtab:fileencoding=utf-8
|
|
|
|
|
2014-06-04 21:28:59 -04:00
|
|
|
__doc__ = """This module provides a CherryPy 3.x tool which implements
|
|
|
|
the server-side of HTTP Basic Access Authentication, as described in
|
|
|
|
:rfc:`2617`.
|
2014-03-10 01:18:05 -04:00
|
|
|
|
|
|
|
Example usage, using the built-in checkpassword_dict function which uses a dict
|
2014-06-04 21:28:59 -04:00
|
|
|
as the credentials store::
|
|
|
|
|
|
|
|
userpassdict = {'bird' : 'bebop', 'ornette' : 'wayout'}
|
|
|
|
checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(userpassdict)
|
|
|
|
basic_auth = {'tools.auth_basic.on': True,
|
|
|
|
'tools.auth_basic.realm': 'earth',
|
|
|
|
'tools.auth_basic.checkpassword': checkpassword,
|
|
|
|
}
|
|
|
|
app_config = { '/' : basic_auth }
|
|
|
|
|
2014-03-10 01:18:05 -04:00
|
|
|
"""
|
|
|
|
|
|
|
|
__author__ = 'visteya'
|
|
|
|
__date__ = 'April 2009'
|
|
|
|
|
|
|
|
import binascii
|
2014-06-04 21:28:59 -04:00
|
|
|
from cherrypy._cpcompat import base64_decode
|
2014-03-10 01:18:05 -04:00
|
|
|
import cherrypy
|
|
|
|
|
|
|
|
|
|
|
|
def checkpassword_dict(user_password_dict):
|
|
|
|
"""Returns a checkpassword function which checks credentials
|
|
|
|
against a dictionary of the form: {username : password}.
|
|
|
|
|
|
|
|
If you want a simple dictionary-based authentication scheme, use
|
|
|
|
checkpassword_dict(my_credentials_dict) as the value for the
|
|
|
|
checkpassword argument to basic_auth().
|
|
|
|
"""
|
|
|
|
def checkpassword(realm, user, password):
|
|
|
|
p = user_password_dict.get(user)
|
|
|
|
return p and p == password or False
|
|
|
|
|
|
|
|
return checkpassword
|
|
|
|
|
|
|
|
|
|
|
|
def basic_auth(realm, checkpassword, debug=False):
|
2014-06-04 21:28:59 -04:00
|
|
|
"""A CherryPy tool which hooks at before_handler to perform
|
|
|
|
HTTP Basic Access Authentication, as specified in :rfc:`2617`.
|
2014-03-10 01:18:05 -04:00
|
|
|
|
|
|
|
If the request has an 'authorization' header with a 'Basic' scheme, this
|
|
|
|
tool attempts to authenticate the credentials supplied in that header. If
|
|
|
|
the request has no 'authorization' header, or if it does but the scheme is
|
|
|
|
not 'Basic', or if authentication fails, the tool sends a 401 response with
|
|
|
|
a 'WWW-Authenticate' Basic header.
|
|
|
|
|
2014-06-04 21:28:59 -04:00
|
|
|
realm
|
|
|
|
A string containing the authentication realm.
|
2014-03-10 01:18:05 -04:00
|
|
|
|
2014-06-04 21:28:59 -04:00
|
|
|
checkpassword
|
|
|
|
A callable which checks the authentication credentials.
|
2014-03-10 01:18:05 -04:00
|
|
|
Its signature is checkpassword(realm, username, password). where
|
|
|
|
username and password are the values obtained from the request's
|
|
|
|
'authorization' header. If authentication succeeds, checkpassword
|
|
|
|
returns True, else it returns False.
|
2014-06-04 21:28:59 -04:00
|
|
|
|
2014-03-10 01:18:05 -04:00
|
|
|
"""
|
2014-06-04 21:28:59 -04:00
|
|
|
|
2014-03-10 01:18:05 -04:00
|
|
|
if '"' in realm:
|
|
|
|
raise ValueError('Realm cannot contain the " (quote) character.')
|
|
|
|
request = cherrypy.serving.request
|
2014-06-04 21:28:59 -04:00
|
|
|
|
2014-03-10 01:18:05 -04:00
|
|
|
auth_header = request.headers.get('authorization')
|
|
|
|
if auth_header is not None:
|
|
|
|
try:
|
|
|
|
scheme, params = auth_header.split(' ', 1)
|
|
|
|
if scheme.lower() == 'basic':
|
2014-06-04 21:28:59 -04:00
|
|
|
username, password = base64_decode(params).split(':', 1)
|
2014-03-10 01:18:05 -04:00
|
|
|
if checkpassword(realm, username, password):
|
|
|
|
if debug:
|
|
|
|
cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC')
|
|
|
|
request.login = username
|
2014-06-04 21:28:59 -04:00
|
|
|
return # successful authentication
|
|
|
|
# split() error, base64.decodestring() error
|
|
|
|
except (ValueError, binascii.Error):
|
2014-03-10 01:18:05 -04:00
|
|
|
raise cherrypy.HTTPError(400, 'Bad Request')
|
|
|
|
|
2014-06-04 21:28:59 -04:00
|
|
|
# Respond with 401 status and a WWW-Authenticate header
|
|
|
|
cherrypy.serving.response.headers[
|
|
|
|
'www-authenticate'] = 'Basic realm="%s"' % realm
|
|
|
|
raise cherrypy.HTTPError(
|
|
|
|
401, "You are not authorized to access that resource")
|