cherrypy update

fixes #3348
This commit is contained in:
AdeHub
2024-12-07 19:56:21 +13:00
parent 94d62430a0
commit a09e91ff8a
28 changed files with 512 additions and 108 deletions
+27 -11
View File
@@ -34,6 +34,7 @@ __date__ = 'April 2009'
def md5_hex(s):
"""Return hexdigest of md5sum."""
return md5(ntob(s, 'utf-8')).hexdigest()
@@ -48,6 +49,7 @@ DEFAULT_CHARSET = 'UTF-8'
def TRACE(msg):
"""Log message in TOOLS.AUTH_DIGEST context."""
cherrypy.log(msg, context='TOOLS.AUTH_DIGEST')
# Three helper functions for users of the tool, providing three variants
@@ -55,8 +57,9 @@ def TRACE(msg):
def get_ha1_dict_plain(user_password_dict):
"""Return a get_ha1 function which obtains a plaintext password from a
dictionary of the form: {username : password}.
"""Return a get_ha1 function which obtains a plaintext password.
user_password_dict is a dictionary of the form: {username : password}.
If you want a simple dictionary-based authentication scheme, with plaintext
passwords, use get_ha1_dict_plain(my_userpass_dict) as the value for the
@@ -72,8 +75,9 @@ def get_ha1_dict_plain(user_password_dict):
def get_ha1_dict(user_ha1_dict):
"""Return a get_ha1 function which obtains a HA1 password hash from a
dictionary of the form: {username : HA1}.
"""Return a get_ha1 function which obtains a HA1 password hash.
user_ha1_dict is a dictionary of the form: {username : HA1}.
If you want a dictionary-based authentication scheme, but with
pre-computed HA1 hashes instead of plain-text passwords, use
@@ -87,7 +91,9 @@ def get_ha1_dict(user_ha1_dict):
def get_ha1_file_htdigest(filename):
"""Return a get_ha1 function which obtains a HA1 password hash from a
"""Return a get_ha1 function.
The returned function obtains a HA1 password hash from a
flat file with lines of the same format as that produced by the Apache
htdigest utility. For example, for realm 'wonderland', username 'alice',
and password '4x5istwelve', the htdigest line would be::
@@ -113,7 +119,9 @@ def get_ha1_file_htdigest(filename):
def synthesize_nonce(s, key, timestamp=None):
"""Synthesize a nonce value which resists spoofing and can be checked
"""Synthesize a nonce value.
A nonce value resists spoofing and can be checked
for staleness. Returns a string suitable as the value for 'nonce' in
the www-authenticate header.
@@ -135,7 +143,7 @@ def synthesize_nonce(s, key, timestamp=None):
def H(s):
"""The hash function H."""
"""Return an ``md5`` HEX hash."""
return md5_hex(s)
@@ -152,7 +160,8 @@ def _try_decode_header(header, charset):
class HttpDigestAuthorization(object):
"""
"""Digest Authorization implementation.
Parses a Digest Authorization header and performs
re-calculation of the digest.
"""
@@ -160,10 +169,12 @@ class HttpDigestAuthorization(object):
scheme = 'digest'
def errmsg(self, s):
"""Make an error message for HTTP Digest Authorization."""
return 'Digest Authorization header: %s' % s
@classmethod
def matches(cls, header):
"""Check if header scheme matches auth implementation."""
scheme, _, _ = header.partition(' ')
return scheme.lower() == cls.scheme
@@ -171,6 +182,7 @@ class HttpDigestAuthorization(object):
self, auth_header, http_method,
debug=False, accept_charset=DEFAULT_CHARSET[:],
):
"""Initialize an HTTP Digest Authorization parser."""
self.http_method = http_method
self.debug = debug
@@ -229,10 +241,12 @@ class HttpDigestAuthorization(object):
'neither cnonce nor nc can be present'))
def __str__(self):
"""Render an HTTP Digest Auth header as a string."""
return 'authorization : %s' % self.auth_header
def validate_nonce(self, s, key):
"""Validate the nonce.
Returns True if nonce was generated by synthesize_nonce() and the
timestamp is not spoofed, else returns False.
@@ -298,7 +312,7 @@ class HttpDigestAuthorization(object):
return H(a2)
def request_digest(self, ha1, entity_body=''):
"""Calculates the Request-Digest. See :rfc:`2617` section 3.2.2.1.
"""Calculate the Request-Digest. See :rfc:`2617` section 3.2.2.1.
ha1
The HA1 string obtained from the credentials store.
@@ -351,7 +365,7 @@ def www_authenticate(
realm, key, algorithm='MD5', nonce=None, qop=qop_auth,
stale=False, accept_charset=DEFAULT_CHARSET[:],
):
"""Constructs a WWW-Authenticate header for Digest authentication."""
"""Construct a WWW-Authenticate header for Digest authentication."""
if qop not in valid_qops:
raise ValueError("Unsupported value for qop: '%s'" % qop)
if algorithm not in valid_algorithms:
@@ -374,7 +388,9 @@ def www_authenticate(
def digest_auth(realm, get_ha1, key, debug=False, accept_charset='utf-8'):
"""A CherryPy tool that hooks at before_handler to perform
"""Perform HTTP Digest Access Authentication.
A CherryPy tool that hooks at ``before_handler`` to perform
HTTP Digest Access Authentication, as specified in :rfc:`2617`.
If the request has an 'authorization' header with a 'Digest' scheme,