| | |
| | | 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) --' |
| | |
| | | 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 |
| | |
| | | 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 |
| | |
| | | |
| | | 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): |
| | | """\ |
| | |
| | | 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 |
| | |
| | | # 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): |
| | |
| | | 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] |
| | |
| | | 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) |
| | |
| | | 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 |
| | |
| | | log_level = logging.DEBUG |
| | | ) |
| | | return middleware |
| | | |
| | | |