Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #4
0
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))
Exemple #5
0
    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))
Exemple #7
0
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))
Exemple #8
0
__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))
Exemple #9
0
                   '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.
Exemple #10
0
 def checkpasshash(realm, user, password):
     p = userhashdict.get(user)
     return p and p == md5(ntob(password)).hexdigest() or False
Exemple #11
0
 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))
Exemple #13
0
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:
Exemple #14
0
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]
Exemple #15
0
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)
Exemple #17
0
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):