def setup_server(): class Root: def index(self): return "This is public." index.exposed = True class BasicProtected: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True class BasicProtected2: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True userpassdict = {'xuser' : 'xpassword'} userhashdict = {'xuser' : md5(ntob('xpassword')).hexdigest()} def checkpasshash(realm, user, password): p = userhashdict.get(user) return p and p == md5(ntob(password)).hexdigest() or False conf = {'/basic': {'tools.auth_basic.on': True, 'tools.auth_basic.realm': 'wonderland', 'tools.auth_basic.checkpassword': auth_basic.checkpassword_dict(userpassdict)}, '/basic2': {'tools.auth_basic.on': True, 'tools.auth_basic.realm': 'wonderland', 'tools.auth_basic.checkpassword': checkpasshash}, } root = Root() root.basic = BasicProtected() root.basic2 = BasicProtected2() cherrypy.tree.mount(root, config=conf)
def setup_server(): class Root: def index(self): return "This is public." index.exposed = True class DigestProtected: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True class BasicProtected: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True class BasicProtected2: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True def fetch_users(): return {'test': 'test'} def sha_password_encrypter(password): return sha(ntob(password)).hexdigest() def fetch_password(username): return sha(ntob('test')).hexdigest() conf = { '/digest': { 'tools.digest_auth.on': True, 'tools.digest_auth.realm': 'localhost', 'tools.digest_auth.users': fetch_users }, '/basic': { 'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'localhost', 'tools.basic_auth.users': { 'test': md5(ntob('test')).hexdigest() } }, '/basic2': { 'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'localhost', 'tools.basic_auth.users': fetch_password, 'tools.basic_auth.encrypt': sha_password_encrypter } } root = Root() root.digest = DigestProtected() root.basic = BasicProtected() root.basic2 = BasicProtected2() cherrypy.tree.mount(root, config=conf)
def setup_server(): class Root: def index(self): return 'This is public.' index.exposed = True class DigestProtected: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True class BasicProtected: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True class BasicProtected2: def index(self): return "Hello %s, you've been authorized." % cherrypy.request.login index.exposed = True def fetch_users(): return {'test': 'test'} def sha_password_encrypter(password): return sha(ntob(password)).hexdigest() def fetch_password(username): return sha(ntob('test')).hexdigest() conf = {'/digest': {'tools.digest_auth.on': True, 'tools.digest_auth.realm': 'localhost', 'tools.digest_auth.users': fetch_users}, '/basic': {'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'localhost', 'tools.basic_auth.users': {'test': md5(ntob('test')).hexdigest()}}, '/basic2': {'tools.basic_auth.on': True, 'tools.basic_auth.realm': 'localhost', 'tools.basic_auth.users': fetch_password, 'tools.basic_auth.encrypt': sha_password_encrypter}} root = Root() root.digest = DigestProtected() root.basic = BasicProtected() root.basic2 = BasicProtected2() cherrypy.tree.mount(root, config=conf)
def validate_etags(autotags=False, debug=False): response = cherrypy.serving.response if hasattr(response, 'ETag'): return status, reason, msg = _httputil.valid_status(response.status) etag = response.headers.get('ETag') if etag: if debug: cherrypy.log('ETag already set: %s' % etag, 'TOOLS.ETAGS') elif not autotags: if debug: cherrypy.log('Autotags off', 'TOOLS.ETAGS') elif status != 200: if debug: cherrypy.log('Status not 200', 'TOOLS.ETAGS') else: etag = response.collapse_body() etag = '"%s"' % md5(etag).hexdigest() if debug: cherrypy.log('Setting ETag: %s' % etag, 'TOOLS.ETAGS') response.headers['ETag'] = etag response.ETag = etag if debug: cherrypy.log('Status: %s' % status, 'TOOLS.ETAGS') if status >= 200 and status <= 299: request = cherrypy.serving.request conditions = request.headers.elements('If-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions and not (conditions == ['*'] or etag in conditions): raise cherrypy.HTTPError( 412, 'If-Match failed: ETag %r did not match %r' % (etag, conditions)) conditions = request.headers.elements('If-None-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-None-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions == ['*'] or etag in conditions: if debug: cherrypy.log('request.method: %s' % request.method, 'TOOLS.ETAGS') if request.method in ('GET', 'HEAD'): raise cherrypy.HTTPRedirect([], 304) else: raise cherrypy.HTTPError( 412, 'If-None-Match failed: ETag %r matched %r' % (etag, conditions))
def setup_server(): class Root: def index(self): return "This is public." index.exposed = True class BasicProtected: def index(self): return "Hello %s, you've been authorized." % (cherrypy.request.login) index.exposed = True class BasicProtected2: def index(self): return "Hello %s, you've been authorized." % (cherrypy.request.login) index.exposed = True userpassdict = {"xuser": "******"} userhashdict = {"xuser": md5(ntob("xpassword")).hexdigest()} def checkpasshash(realm, user, password): p = userhashdict.get(user) return p and p == md5(ntob(password)).hexdigest() or False basic_checkpassword_dict = auth_basic.checkpassword_dict(userpassdict) conf = { "/basic": { "tools.auth_basic.on": True, "tools.auth_basic.realm": "wonderland", "tools.auth_basic.checkpassword": basic_checkpassword_dict, }, "/basic2": { "tools.auth_basic.on": True, "tools.auth_basic.realm": "wonderland", "tools.auth_basic.checkpassword": checkpasshash, }, } root = Root() root.basic = BasicProtected() root.basic2 = BasicProtected2() cherrypy.tree.mount(root, config=conf)
def validate_etags(autotags = False, debug = False): response = cherrypy.serving.response if hasattr(response, 'ETag'): return status, reason, msg = _httputil.valid_status(response.status) etag = response.headers.get('ETag') if etag: if debug: cherrypy.log('ETag already set: %s' % etag, 'TOOLS.ETAGS') elif not autotags: if debug: cherrypy.log('Autotags off', 'TOOLS.ETAGS') elif status != 200: if debug: cherrypy.log('Status not 200', 'TOOLS.ETAGS') else: etag = response.collapse_body() etag = '"%s"' % md5(etag).hexdigest() if debug: cherrypy.log('Setting ETag: %s' % etag, 'TOOLS.ETAGS') response.headers['ETag'] = etag response.ETag = etag if debug: cherrypy.log('Status: %s' % status, 'TOOLS.ETAGS') if status >= 200 and status <= 299: request = cherrypy.serving.request conditions = request.headers.elements('If-Match') or [] conditions = [ str(x) for x in conditions ] if debug: cherrypy.log('If-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions and not (conditions == ['*'] or etag in conditions): raise cherrypy.HTTPError(412, 'If-Match failed: ETag %r did not match %r' % (etag, conditions)) conditions = request.headers.elements('If-None-Match') or [] conditions = [ str(x) for x in conditions ] if debug: cherrypy.log('If-None-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions == ['*'] or etag in conditions: if debug: cherrypy.log('request.method: %s' % request.method, 'TOOLS.ETAGS') if request.method in ('GET', 'HEAD'): raise cherrypy.HTTPRedirect([], 304) else: raise cherrypy.HTTPError(412, 'If-None-Match failed: ETag %r matched %r' % (etag, conditions))
def validate_etags(autotags=False, debug=False): """Validate the current ETag against If-Match, If-None-Match headers. If autotags is True, an ETag response-header value will be provided from an MD5 hash of the response body (unless some other code has already provided an ETag header). If False (the default), the ETag will not be automatic. WARNING: the autotags feature is not designed for URL's which allow methods other than GET. For example, if a POST to the same URL returns no content, the automatic ETag will be incorrect, breaking a fundamental use for entity tags in a possibly destructive fashion. Likewise, if you raise 304 Not Modified, the response body will be empty, the ETag hash will be incorrect, and your application will break. See :rfc:`2616` Section 14.24. """ response = cherrypy.serving.response # Guard against being run twice. if hasattr(response, "ETag"): return status, reason, msg = _httputil.valid_status(response.status) etag = response.headers.get('ETag') # Automatic ETag generation. See warning in docstring. if etag: if debug: cherrypy.log('ETag already set: %s' % etag, 'TOOLS.ETAGS') elif not autotags: if debug: cherrypy.log('Autotags off', 'TOOLS.ETAGS') elif status != 200: if debug: cherrypy.log('Status not 200', 'TOOLS.ETAGS') else: etag = response.collapse_body() etag = '"%s"' % md5(etag).hexdigest() if debug: cherrypy.log('Setting ETag: %s' % etag, 'TOOLS.ETAGS') response.headers['ETag'] = etag response.ETag = etag # "If the request would, without the If-Match header field, result in # anything other than a 2xx or 412 status, then the If-Match header # MUST be ignored." if debug: cherrypy.log('Status: %s' % status, 'TOOLS.ETAGS') if status >= 200 and status <= 299: request = cherrypy.serving.request conditions = request.headers.elements('If-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions and not (conditions == ["*"] or etag in conditions): raise cherrypy.HTTPError( 412, "If-Match failed: ETag %r did " "not match %r" % (etag, conditions)) conditions = request.headers.elements('If-None-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-None-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions == ["*"] or etag in conditions: if debug: cherrypy.log('request.method: %s' % request.method, 'TOOLS.ETAGS') if request.method in ("GET", "HEAD"): raise cherrypy.HTTPRedirect([], 304) else: raise cherrypy.HTTPError( 412, "If-None-Match failed: ETag %r " "matched %r" % (etag, conditions))
__credits__ = '\n Peter van Kampen for its recipe which implement most of Digest authentication:\n http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302378\n' __license__ = '\nCopyright (c) 2005, Tiago Cogumbreiro <*****@*****.**>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, \nare permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, \n this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, \n this list of conditions and the following disclaimer in the documentation \n and/or other materials provided with the distribution.\n * Neither the name of Sylvain Hellegouarch nor the names of his contributors \n may be used to endorse or promote products derived from this software \n without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND \nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED \nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE \nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR \nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER \nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, \nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n' __all__ = ('digestAuth', 'basicAuth', 'doAuth', 'checkResponse', 'parseAuthorization', 'SUPPORTED_ALGORITHM', 'md5SessionKey', 'calculateNonce', 'SUPPORTED_QOP') import time from cherrypy._cpcompat import base64_decode, ntob, md5 from cherrypy._cpcompat import parse_http_list, parse_keqv_list MD5 = 'MD5' MD5_SESS = 'MD5-sess' AUTH = 'auth' AUTH_INT = 'auth-int' SUPPORTED_ALGORITHM = (MD5, MD5_SESS) SUPPORTED_QOP = (AUTH, AUTH_INT) DIGEST_AUTH_ENCODERS = { MD5: lambda val: md5(ntob(val)).hexdigest(), MD5_SESS: lambda val: md5(ntob(val)).hexdigest() } def calculateNonce(realm, algorithm=MD5): global DIGEST_AUTH_ENCODERS try: encoder = DIGEST_AUTH_ENCODERS[algorithm] except KeyError: raise NotImplementedError( 'The chosen algorithm (%s) does not have an implementation yet' % algorithm) return encoder('%d:%s' % (time.time(), realm))
'tools.auth_digest.realm': 'wonderland', 'tools.auth_digest.get_ha1': get_ha1, 'tools.auth_digest.key': 'a565c27146791cfb', } app_config = { '/' : digest_auth } """ __author__ = 'visteya' __date__ = 'April 2009' import time from cherrypy._cpcompat import parse_http_list, parse_keqv_list import cherrypy from cherrypy._cpcompat import md5, ntob md5_hex = lambda s: md5(ntob(s)).hexdigest() qop_auth = 'auth' qop_auth_int = 'auth-int' valid_qops = (qop_auth, qop_auth_int) valid_algorithms = ('MD5', 'MD5-sess') def TRACE(msg): cherrypy.log(msg, context='TOOLS.AUTH_DIGEST') # Three helper functions for users of the tool, providing three variants # of get_ha1() functions for three different kinds of credential stores.
def checkpasshash(realm, user, password): p = userhashdict.get(user) return p and p == md5(ntob(password)).hexdigest() or False
userpassdict = {'alice' : '4x5istwelve'} get_ha1 = cherrypy.lib.auth_digest.get_ha1_dict_plain(userpassdict) digest_auth = {'tools.auth_digest.on': True, 'tools.auth_digest.realm': 'wonderland', 'tools.auth_digest.get_ha1': get_ha1, 'tools.auth_digest.key': 'a565c27146791cfb', } app_config = { '/' : digest_auth } """ __author__ = 'visteya' __date__ = 'April 2009' import time from cherrypy._cpcompat import parse_http_list, parse_keqv_list import cherrypy from cherrypy._cpcompat import md5, ntob md5_hex = lambda s: md5(ntob(s)).hexdigest() qop_auth = 'auth' qop_auth_int = 'auth-int' valid_qops = (qop_auth, qop_auth_int) valid_algorithms = ('MD5', 'MD5-sess') def TRACE(msg): cherrypy.log(msg, context='TOOLS.AUTH_DIGEST') def get_ha1_dict_plain(user_password_dict): def get_ha1(realm, username): password = user_password_dict.get(username) if password: return md5_hex('%s:%s:%s' % (username, realm, password))
from cherrypy._cpcompat import base64_decode, ntob, md5 from cherrypy._cpcompat import parse_http_list, parse_keqv_list MD5 = "MD5" MD5_SESS = "MD5-sess" AUTH = "auth" AUTH_INT = "auth-int" SUPPORTED_ALGORITHM = ('md5', MD5, MD5_SESS) # Changed by Kovid SUPPORTED_QOP = (AUTH, AUTH_INT) ################################################################################ # doAuth # DIGEST_AUTH_ENCODERS = { MD5: lambda val: md5(ntob(val)).hexdigest(), 'md5': lambda val:md5(val).hexdigest(), # Added by Kovid MD5_SESS: lambda val: md5(ntob(val)).hexdigest(), # SHA: lambda val: sha.new(ntob(val)).hexdigest (), } def calculateNonce (realm, algorithm = MD5): """This is an auxaliary function that calculates 'nonce' value. It is used to handle sessions.""" global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS assert algorithm in SUPPORTED_ALGORITHM try: encoder = DIGEST_AUTH_ENCODERS[algorithm] except KeyError:
from cherrypy._cpcompat import base64_decode, ntob, md5 from cherrypy._cpcompat import parse_http_list, parse_keqv_list MD5 = "MD5" MD5_SESS = "MD5-sess" AUTH = "auth" AUTH_INT = "auth-int" SUPPORTED_ALGORITHM = ('md5', MD5, MD5_SESS) # Changed by Kovid SUPPORTED_QOP = (AUTH, AUTH_INT) ################################################################################ # doAuth # DIGEST_AUTH_ENCODERS = { MD5: lambda val: md5(ntob(val)).hexdigest(), 'md5': lambda val: md5(val).hexdigest(), # Added by Kovid MD5_SESS: lambda val: md5(ntob(val)).hexdigest(), # SHA: lambda val: sha.new(ntob(val)).hexdigest (), } def calculateNonce(realm, algorithm=MD5): """This is an auxaliary function that calculates 'nonce' value. It is used to handle sessions.""" global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS assert algorithm in SUPPORTED_ALGORITHM try: encoder = DIGEST_AUTH_ENCODERS[algorithm]
from cherrypy._cpcompat import base64_decode, ntob, md5 from cherrypy._cpcompat import parse_http_list, parse_keqv_list MD5 = "MD5" MD5_SESS = "MD5-sess" AUTH = "auth" AUTH_INT = "auth-int" SUPPORTED_ALGORITHM = (MD5, MD5_SESS) SUPPORTED_QOP = (AUTH, AUTH_INT) ########################################################################## # doAuth # DIGEST_AUTH_ENCODERS = { MD5: lambda val: md5(ntob(val)).hexdigest(), MD5_SESS: lambda val: md5(ntob(val)).hexdigest(), # SHA: lambda val: sha.new(ntob(val)).hexdigest (), } def calculateNonce(realm, algorithm=MD5): """This is an auxaliary function that calculates 'nonce' value. It is used to handle sessions.""" global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS assert algorithm in SUPPORTED_ALGORITHM try: encoder = DIGEST_AUTH_ENCODERS[algorithm] except KeyError:
#Embedded file name: e:\jenkins\workspace\client_SERENITY\branches\release\SERENITY\carbon\common\lib\cherrypy\lib\httpauth.py __version__ = (1, 0, 1) __author__ = 'Tiago Cogumbreiro <*****@*****.**>' __credits__ = '\n Peter van Kampen for its recipe which implement most of Digest authentication:\n http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302378\n' __license__ = '\nCopyright (c) 2005, Tiago Cogumbreiro <*****@*****.**>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, \nare permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, \n this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, \n this list of conditions and the following disclaimer in the documentation \n and/or other materials provided with the distribution.\n * Neither the name of Sylvain Hellegouarch nor the names of his contributors \n may be used to endorse or promote products derived from this software \n without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND \nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED \nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE \nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR \nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER \nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, \nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n' __all__ = ('digestAuth', 'basicAuth', 'doAuth', 'checkResponse', 'parseAuthorization', 'SUPPORTED_ALGORITHM', 'md5SessionKey', 'calculateNonce', 'SUPPORTED_QOP') import time from cherrypy._cpcompat import base64_decode, ntob, md5 from cherrypy._cpcompat import parse_http_list, parse_keqv_list MD5 = 'MD5' MD5_SESS = 'MD5-sess' AUTH = 'auth' AUTH_INT = 'auth-int' SUPPORTED_ALGORITHM = (MD5, MD5_SESS) SUPPORTED_QOP = (AUTH, AUTH_INT) DIGEST_AUTH_ENCODERS = {MD5: lambda val: md5(ntob(val)).hexdigest(), MD5_SESS: lambda val: md5(ntob(val)).hexdigest()} def calculateNonce(realm, algorithm = MD5): global DIGEST_AUTH_ENCODERS try: encoder = DIGEST_AUTH_ENCODERS[algorithm] except KeyError: raise NotImplementedError('The chosen algorithm (%s) does not have an implementation yet' % algorithm) return encoder('%d:%s' % (time.time(), realm)) def digestAuth(realm, algorithm = MD5, nonce = None, qop = AUTH): if nonce is None: nonce = calculateNonce(realm, algorithm)
def validate_etags(autotags=False, debug=False): """Validate the current ETag against If-Match, If-None-Match headers. If autotags is True, an ETag response-header value will be provided from an MD5 hash of the response body (unless some other code has already provided an ETag header). If False (the default), the ETag will not be automatic. WARNING: the autotags feature is not designed for URL's which allow methods other than GET. For example, if a POST to the same URL returns no content, the automatic ETag will be incorrect, breaking a fundamental use for entity tags in a possibly destructive fashion. Likewise, if you raise 304 Not Modified, the response body will be empty, the ETag hash will be incorrect, and your application will break. See :rfc:`2616` Section 14.24. """ response = cherrypy.serving.response # Guard against being run twice. if hasattr(response, "ETag"): return status, reason, msg = _httputil.valid_status(response.status) etag = response.headers.get('ETag') # Automatic ETag generation. See warning in docstring. if etag: if debug: cherrypy.log('ETag already set: %s' % etag, 'TOOLS.ETAGS') elif not autotags: if debug: cherrypy.log('Autotags off', 'TOOLS.ETAGS') elif status != 200: if debug: cherrypy.log('Status not 200', 'TOOLS.ETAGS') else: etag = response.collapse_body() etag = '"%s"' % md5(etag).hexdigest() if debug: cherrypy.log('Setting ETag: %s' % etag, 'TOOLS.ETAGS') response.headers['ETag'] = etag response.ETag = etag # "If the request would, without the If-Match header field, result in # anything other than a 2xx or 412 status, then the If-Match header # MUST be ignored." if debug: cherrypy.log('Status: %s' % status, 'TOOLS.ETAGS') if status >= 200 and status <= 299: request = cherrypy.serving.request conditions = request.headers.elements('If-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions and not (conditions == ["*"] or etag in conditions): raise cherrypy.HTTPError(412, "If-Match failed: ETag %r did " "not match %r" % (etag, conditions)) conditions = request.headers.elements('If-None-Match') or [] conditions = [str(x) for x in conditions] if debug: cherrypy.log('If-None-Match conditions: %s' % repr(conditions), 'TOOLS.ETAGS') if conditions == ["*"] or etag in conditions: if debug: cherrypy.log('request.method: %s' % request.method, 'TOOLS.ETAGS') if request.method in ("GET", "HEAD"): raise cherrypy.HTTPRedirect([], 304) else: raise cherrypy.HTTPError(412, "If-None-Match failed: ETag %r " "matched %r" % (etag, conditions))
""" __version__ = (1, 0, 1) __author__ = 'Tiago Cogumbreiro <*****@*****.**>' __credits__ = '\n Peter van Kampen for its recipe which implement most of Digest authentication:\n http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302378\n' __license__ = '\nCopyright (c) 2005, Tiago Cogumbreiro <*****@*****.**>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, \nare permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, \n this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, \n this list of conditions and the following disclaimer in the documentation \n and/or other materials provided with the distribution.\n * Neither the name of Sylvain Hellegouarch nor the names of his contributors \n may be used to endorse or promote products derived from this software \n without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND \nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED \nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE \nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE \nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR \nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER \nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, \nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n' __all__ = ('digestAuth', 'basicAuth', 'doAuth', 'checkResponse', 'parseAuthorization', 'SUPPORTED_ALGORITHM', 'md5SessionKey', 'calculateNonce', 'SUPPORTED_QOP') import time from cherrypy._cpcompat import base64_decode, ntob, md5 from cherrypy._cpcompat import parse_http_list, parse_keqv_list MD5 = 'MD5' MD5_SESS = 'MD5-sess' AUTH = 'auth' AUTH_INT = 'auth-int' SUPPORTED_ALGORITHM = (MD5, MD5_SESS) SUPPORTED_QOP = (AUTH, AUTH_INT) DIGEST_AUTH_ENCODERS = {MD5: lambda val: md5(ntob(val)).hexdigest(), MD5_SESS: lambda val: md5(ntob(val)).hexdigest()} def calculateNonce(realm, algorithm = MD5): """This is an auxaliary function that calculates 'nonce' value. It is used to handle sessions.""" global DIGEST_AUTH_ENCODERS try: encoder = DIGEST_AUTH_ENCODERS[algorithm] except KeyError: raise NotImplementedError('The chosen algorithm (%s) does not have an implementation yet' % algorithm) return encoder('%d:%s' % (time.time(), realm)) def digestAuth(realm, algorithm = MD5, nonce = None, qop = AUTH):