Tres Seaver
2016-05-31 455778d138ea623d224c9206e5001fd2a1fd7e1c
repoze/who/middleware.py
@@ -1,10 +1,9 @@
import logging
from StringIO import StringIO
import sys
from repoze.who.api import APIFactory
from repoze.who.interfaces import IIdentifier
from repoze.who.interfaces import IChallenger
from repoze.who._compat import StringIO
_STARTED = '-- repoze.who request started (%s) --'
_ENDED = '-- repoze.who request ended (%s) --'
@@ -31,7 +30,7 @@
        if request_classifier is None:
            if classifier is None:
                raise ValueError(
                        'Either request_classifier and classifier is required')
                        'Either request_classifier or classifier is required')
            request_classifier = classifier
        self.app = app
        logger = self.logger = None
@@ -73,13 +72,7 @@
        logger = self.logger
        path_info = environ.get('PATH_INFO', None)
        logger and logger.info(_STARTED % path_info)
        userid = None
        identity = None
        identifier = None
        identity = api.authenticate()
        if identity:
            identifier = identity.get('identifier')
        api.authenticate()  # identity saved in environ
        # allow identifier plugins to replace the downstream
        # application (to do redirection and unauthorized themselves
@@ -102,24 +95,32 @@
        if api.challenge_decider(environ, wrapper.status, wrapper.headers):
            logger and logger.info('challenge required')
            close = getattr(app_iter, 'close', _no_op)
            challenge_app = api.challenge(wrapper.status, wrapper.headers)
            if challenge_app is not None:
                logger and logger.info('executing challenge app')
                if app_iter:
                    list(app_iter) # unwind the original app iterator
                # PEP 333 requires that we call the original iterator's
                # 'close' method, if it exists, before releasing it.
                close()
                # replace the downstream app with the challenge app
                app_iter = challenge_app(environ, start_response)
            else:
                logger and logger.info('configuration error: no challengers')
                close()
                raise RuntimeError('no challengers found')
        else:
            logger and logger.info('no challenge required')
            remember_headers = api.remember(identity)
            remember_headers = api.remember()
            wrapper.finish_response(remember_headers)
        logger and logger.info(_ENDED % path_info)
        return app_iter
def _no_op():
    pass
def wrap_generator(result):
    """\
@@ -128,8 +129,12 @@
    caches it to trigger any immediate side effects (in a WSGI world, this
    ensures start_response is called).
    """
    # PEP 333 requires that we call the original iterator's
    # 'close' method, if it exists, before releasing it.
    close = getattr(result, 'close', lambda: None)
    # Neat trick to pull the first iteration only. We need to do this outside
    # of the generator function to ensure it is called.
    first = marker = []
    for iter in result:
        first = iter
        break
@@ -137,10 +142,12 @@
    # Wrapper yields the first iteration, then passes result's iterations
    # directly up.
    def wrapper():
        yield first
        if first is not marker:
            yield first
        for iter in result:
            # We'll let result's StopIteration bubble up directly.
            yield iter
        close()
    return wrapper()
class StartResponseWrapper(object):
@@ -179,13 +186,13 @@
def make_test_middleware(app, global_conf):
    """ Functionally equivalent to
    [plugin:form]
    use = repoze.who.plugins.form.FormPlugin
    rememberer_name = cookie
    login_form_qs=__do_login
    [plugin:redirector]
    use = repoze.who.plugins.redirector.RedirectorPlugin
    login_url = /login.html
    [plugin:cookie]
    use = repoze.who.plugins.cookie:InsecureCookiePlugin
    [plugin:auth_tkt]
    use = repoze.who.plugins.auth_tkt:AuthTktCookiePlugin
    secret = SEEKRIT
    cookie_name = oatmeal
    [plugin:basicauth]
@@ -202,22 +209,20 @@
    challenge_decider = repoze.who.classifiers:default_challenge_decider
    [identifiers]
    plugins = form:browser cookie basicauth
    plugins = authtkt basicauth
    [authenticators]
    plugins = htpasswd
    plugins = authtkt htpasswd
    [challengers]
    plugins = form:browser basicauth
    plugins = redirector:browser basicauth
    """
    # be able to test without a config file
    from repoze.who.plugins.basicauth import BasicAuthPlugin
    from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
    from repoze.who.plugins.cookie import InsecureCookiePlugin
    from repoze.who.plugins.form import FormPlugin
    from repoze.who.plugins.redirector import RedirectorPlugin
    from repoze.who.plugins.htpasswd import HTPasswdPlugin
    io = StringIO()
    salt = 'aa'
    for name, password in [ ('admin', 'admin'), ('chris', 'chris') ]:
        io.write('%s:%s\n' % (name, password))
    io.seek(0)
@@ -226,13 +231,14 @@
    htpasswd = HTPasswdPlugin(io, cleartext_check)
    basicauth = BasicAuthPlugin('repoze.who')
    auth_tkt = AuthTktCookiePlugin('secret', 'auth_tkt')
    cookie = InsecureCookiePlugin('oatmeal')
    form = FormPlugin('__do_login', rememberer_name='auth_tkt')
    form.classifications = { IIdentifier:['browser'],
                             IChallenger:['browser'] } # only for browser
    identifiers = [('form', form),('auth_tkt',auth_tkt),('basicauth',basicauth)]
    redirector = RedirectorPlugin('/login.html')
    redirector.classifications = {IChallenger: ['browser']} # only for browser
    identifiers = [('auth_tkt', auth_tkt),
                   ('basicauth', basicauth),
                  ]
    authenticators = [('htpasswd', htpasswd)]
    challengers = [('form',form), ('basicauth',basicauth)]
    challengers = [('redirector', redirector),
                   ('basicauth', basicauth)]
    mdproviders = []
    from repoze.who.classifiers import default_request_classifier
    from repoze.who.classifiers import default_challenge_decider
@@ -252,5 +258,3 @@
        log_level = logging.DEBUG
        )
    return middleware