Ejemplo n.º 1
0
 def __init__(
     self,
     app,
     identifiers,
     authenticators,
     challengers,
     mdproviders,
     classifier,
     challenge_decider,
     log_stream=None,
     log_level=logging.INFO,
     remote_user_key="REMOTE_USER",
 ):
     PluggableAuthenticationMiddleware.__init__(
         self,
         app,
         identifiers,
         authenticators,
         challengers,
         mdproviders,
         classifier,
         challenge_decider,
         log_stream,
         log_level,
         remote_user_key,
     )
Ejemplo n.º 2
0
    def make_auth_app(global_conf, **app_conf):
        """example authenticated app with an htpasswd file"""

        assert 'auth.htpasswd' in app_conf
        assert os.path.exists(app_conf['auth.htpasswd'])

        app_conf['traclegos.auth'] = True

        # make the app
        app = make_app(global_conf, **app_conf)

        # wrap in repoze.who authentication middleware
        htpasswd_auth = HTPasswdPlugin(app_conf['auth.htpasswd'], check)
        auth_tkt = AuthTktCookiePlugin('secret', 'auth_tkt')
        form = RedirectingFormPlugin('/', '/login', '/logout', 'auth_tkt')
        identifiers = [('form', form), ('auth_tkt', auth_tkt)]
        authenticators = [('htpasswd_auth', htpasswd_auth)]
        challengers = [('form', form)]

        from repoze.who.classifiers import default_request_classifier
        from repoze.who.classifiers import default_challenge_decider
        log_stream = None

        return PluggableAuthenticationMiddleware(app,
                                                 identifiers,
                                                 authenticators,
                                                 challengers, [],
                                                 default_request_classifier,
                                                 default_challenge_decider,
                                                 log_stream=None,
                                                 log_level=logging.DEBUG)
Ejemplo n.º 3
0
def main():
    import zope.app.wsgi
    zope_conf = os.path.join(here, 'zope.conf')
    zope = zope.app.wsgi.getWSGIApplication(zope_conf)

    from repoze.who.middleware import PluggableAuthenticationMiddleware
    from repoze.who.config import WhoConfig
    parser = WhoConfig(here)
    parser.parse(open(os.path.join(here, 'who.ini')))
    log_stream = sys.stdout
    log_level = logging.DEBUG

    app = PluggableAuthenticationMiddleware(
        zope,
        parser.identifiers,
        parser.authenticators,
        parser.challengers,
        parser.mdproviders,
        parser.request_classifier,
        parser.challenge_decider,
        log_stream,
        log_level,
    )
    from paste import httpserver
    httpserver.serve(app, host='0.0.0.0', port='9876')
 def setUp(self):
     self.plugin = MACAuthPlugin()
     application = PluggableAuthenticationMiddleware(
         stub_application, [["mac", self.plugin]], [["mac", self.plugin]],
         [["mac", self.plugin]], [], stub_request_classifier,
         stub_challenge_decider)
     self.app = TestApp(application)
Ejemplo n.º 5
0
def fas_make_who_middleware(app, log_stream):
    faswho = FASWhoPlugin(fasurl)
    csrf_mdprovider = CSRFMetadataProvider(login_handler=tg.config.get(
        'moksha.csrf.login_handler', '/login_handler'))

    form = RedirectingFormPlugin('/community/login',
                                 '/login_handler',
                                 '/logout',
                                 rememberer_name='fasident',
                                 reason_param='ec')
    # only for browser
    form.classifications = {IIdentifier: ['browser'], IChallenger: ['browser']}

    identifiers = [('form', form), ('fasident', faswho)]
    authenticators = [('fasauth', faswho)]
    challengers = [('form', form)]
    mdproviders = [('fasmd', faswho), ('csrfmd', csrf_mdprovider)]

    if os.environ.get('FAS_WHO_LOG'):
        log_stream = sys.stdout

    app = PluggableAuthenticationMiddleware(app,
                                            identifiers,
                                            authenticators,
                                            challengers,
                                            mdproviders,
                                            default_request_classifier,
                                            default_challenge_decider,
                                            log_stream=log_stream)

    return app
Ejemplo n.º 6
0
def make_middleware_with_config(app, global_conf, config_file,
                                log_file=None, log_level=None):
    parser = WhoConfig(global_conf['here'])
    with open(config_file) as f:
        parser.parse(f)
    log_stream = None

    if log_level is None:
        log_level = logging.INFO
    elif not isinstance(log_level, int):
        log_level = _LEVELS[log_level.lower()]

    if log_file is not None:
        if log_file.lower() == 'stdout':
            log_stream = sys.stdout
        else:
            log_stream = open(log_file, 'wb')
    else:
        log_stream = logging.getLogger('repoze.who')
        log_stream.addHandler(NullHandler())
        log_stream.setLevel(log_level or 0)

    return PluggableAuthenticationMiddleware(
                app,
                parser.identifiers,
                parser.authenticators,
                parser.challengers,
                parser.mdproviders,
                parser.request_classifier,
                parser.challenge_decider,
                log_stream,
                log_level,
                parser.remote_user_key,
           )
Ejemplo n.º 7
0
def make_middleware_with_config(app,
                                global_conf,
                                config_file,
                                log_file=None,
                                log_level=None):
    parser = WhoConfig(global_conf['here'])
    parser.parse(open(config_file))
    log_stream = None

    if log_file is not None:
        if log_file.lower() == 'stdout':
            log_stream = sys.stdout
        else:
            log_stream = open(log_file, 'wb')

    if log_level is None:
        log_level = logging.INFO
    else:
        log_level = _LEVELS[log_level.lower()]

    return PluggableAuthenticationMiddleware(
        app,
        parser.identifiers,
        parser.authenticators,
        parser.challengers,
        parser.mdproviders,
        parser.request_classifier,
        parser.challenge_decider,
        log_stream,
        log_level,
        parser.remote_user_key,
    )
Ejemplo n.º 8
0
 def __init__(
     self,
     app,
     identifiers,
     authenticators,
     challengers,
     mdproviders,
     classifier,
     challenge_decider,
     log_stream=None,
     log_level=logging.INFO,
     remote_user_key='REMOTE_USER',
 ):
     PluggableAuthenticationMiddleware.__init__(self, app, identifiers,
                                                authenticators, challengers,
                                                mdproviders, classifier,
                                                challenge_decider,
                                                log_stream, log_level,
                                                remote_user_key)
 def setUp(self):
     self.plugin = VEPAuthPlugin(audiences=["localhost"],
                                 verifier=vep.DummyVerifier(),
                                 token_manager=StubTokenManager())
     application = PluggableAuthenticationMiddleware(stub_application,
                              [["vep", self.plugin]],
                              [["vep", self.plugin]],
                              [["vep", self.plugin]],
                              [],
                              stub_request_classifier,
                              stub_challenge_decider)
     self.app = TestApp(application)
Ejemplo n.º 10
0
    def _wsgi_app(self):
        parser = WhoConfig("")
        parser.parse(WHO_CONFIG)

        def application(environ, start_response):
            start_response("401 Unauthorized", [])
            return [""]

        return PluggableAuthenticationMiddleware(
            application, parser.identifiers, parser.authenticators,
            parser.challengers, parser.mdproviders, parser.request_classifier,
            parser.challenge_decider)
Ejemplo n.º 11
0
    def make_ldap_auth_app(global_conf, **app_conf):
        """example authenticated app with ldap"""

        assert 'auth.base_dn' in app_conf, "No base_dn specified"
        assert 'auth.ldap_host' in app_conf, "No ldap_host specified"

        app_conf['traclegos.auth'] = True

        # make the app
        app = make_app(global_conf, **app_conf)

        # XXX bad touch
        # this should really be passed to the make_app factory and used there
        # but there's no current way of doing this intelligently
        app.application.remote_user_name = ldap_remote_user

        # get the ldap connection
        conn = ldap.open(app_conf['auth.ldap_host'])
        if app_conf.get('auth.use_tls', 'False').lower() == 'true':
            conn.start_tls_s()

        # wrap in repoze.who authentication middleware
        ldap_auth = LDAPAuthenticatorPlugin(conn, app_conf['auth.base_dn'])
        auth_tkt = AuthTktCookiePlugin('secret', 'auth_tkt')
        form = RedirectingFormPlugin('/', '/login', '/logout', 'auth_tkt')
        identifiers = [('form', form), ('auth_tkt', auth_tkt)]
        authenticators = [('ldap_auth', ldap_auth)]
        challengers = [('form', form)]

        from repoze.who.classifiers import default_request_classifier
        from repoze.who.classifiers import default_challenge_decider
        log_stream = None

        #import logging
        #logger = logging.getLogger('something')
        #logger.setLevel(logging.DEBUG)
        return PluggableAuthenticationMiddleware(app,
                                                 identifiers,
                                                 authenticators,
                                                 challengers, [],
                                                 default_request_classifier,
                                                 default_challenge_decider,
                                                 log_stream=None,
                                                 log_level=logging.DEBUG)
Ejemplo n.º 12
0
def make_middleware(skip_authentication=False, *args, **kwargs):
    """
    Return the requested authentication middleware.
    
    :param skip_authentication: If ``True``, an instance of
        :class:`AuthenticationForgerMiddleware` will be returned instead of
        :class:`repoze.who.middleware.PluggableAuthenticationMiddleware`
    :type skip_authentication: bool
    
    ``args`` and ``kwargs`` are the positional and named arguments, 
    respectively, to be passed to the relevant authentication middleware.
    
    """

    if asbool(skip_authentication):
        # We must replace the middleware:
        return AuthenticationForgerMiddleware(*args, **kwargs)
    else:
        return PluggableAuthenticationMiddleware(*args, **kwargs)
Ejemplo n.º 13
0
def AuthenticationMiddleware(app):
    import isitopen.model as model
    import isitopen.lib.helpers as h
    modelpassword = ModelPasswordPlugin(model)
    basicauth = BasicAuthPlugin('repoze.who')
    auth_tkt = AuthTktCookiePlugin('secret', 'auth_tkt')
    form = RedirectingFormPlugin(
        login_form_url=h.url_for(controller='account', action='login'),
        login_handler_path=h.url_for('login-handler'),
        logout_handler_path=h.url_for('logout-handler'),
        rememberer_name='auth_tkt',
    )

    form.classifications = { IIdentifier:['browser'],
                             IChallenger:['browser'] } # only for browser
    identifiers = [('form', form),('auth_tkt',auth_tkt),('basicauth',basicauth)]
    authenticators = [('modelpassword', modelpassword)]
    challengers = [('form',form), ('basicauth',basicauth)]
    mdproviders = []

    from repoze.who.classifiers import default_request_classifier
    from repoze.who.classifiers import default_challenge_decider
    log_stream = None
    import os
    if os.environ.get('WHO_LOG'):
        log_stream = sys.stdout

    return PluggableAuthenticationMiddleware(
        app,
        identifiers,
        authenticators,
        challengers,
        mdproviders,
        default_request_classifier,
        default_challenge_decider,
        log_stream = log_stream,
        log_level = logging.DEBUG
    )
Ejemplo n.º 14
0
def authentication_middleware(app, config):
    return PluggableAuthenticationMiddleware(app, **who_args(config))
Ejemplo n.º 15
0
def make_faswho_middleware(app,
                           log_stream=None,
                           login_handler='/login_handler',
                           login_form_url='/login',
                           logout_handler='/logout_handler',
                           post_login_url='/post_login',
                           post_logout_url=None,
                           fas_url=FAS_URL,
                           insecure=False,
                           ssl_cookie=True,
                           httponly=True):
    '''
    :arg app: WSGI app that is being wrapped
    :kwarg log_stream: :class:`logging.Logger` to log auth messages
    :kwarg login_handler: URL where the login form is submitted
    :kwarg login_form_url: URL where the login form is displayed
    :kwarg logout_handler: URL where the logout form is submitted
    :kwarg post_login_url: URL to redirect the user to after login
    :kwarg post_logout_url: URL to redirect the user to after logout
    :kwarg fas_url: Base URL to the FAS server
    :kwarg insecure: Allow connecting to a fas server without checking the
        server's SSL certificate.  Opens you up to MITM attacks but can be
        useful when testing.  *Do not enable this in production*
    :kwarg ssl_cookie: If :data:`True` (default), tell the browser to only
        send the session cookie back over https.
    :kwarg httponly: If :data:`True` (default), tell the browser that the
        session cookie should only be read for sending to a server, not for
        access by JavaScript or other clientside technology.  This prevents
        using the session cookie to pass information to JavaScript clients but
        also prevents XSS attacks from stealing the session cookie
        information.
    '''

    # Because of the way we override values (via a dict in AppConfig), we
    # need to make this a keyword arg and then check it here to make it act
    # like a positional arg.
    if not log_stream:
        raise TypeError(
            'log_stream must be set when calling make_fasauth_middleware()')

    faswho = FASWhoPlugin(fas_url,
                          insecure=insecure,
                          ssl_cookie=ssl_cookie,
                          httponly=httponly)
    csrf_mdprovider = CSRFMetadataProvider()

    form = FriendlyFormPlugin(login_form_url,
                              login_handler,
                              post_login_url,
                              logout_handler,
                              post_logout_url,
                              rememberer_name='fasident',
                              charset='utf-8')

    form.classifications = {
        IIdentifier: ['browser'],
        IChallenger: ['browser']
    }  # only for browser

    basicauth = BasicAuthPlugin('repoze.who')

    identifiers = [('form', form), ('fasident', faswho),
                   ('basicauth', basicauth)]
    authenticators = [('fasauth', faswho)]
    challengers = [('form', form), ('basicauth', basicauth)]
    mdproviders = [('fasmd', faswho), ('csrfmd', csrf_mdprovider)]

    if os.environ.get('FAS_WHO_LOG'):
        log_stream = sys.stdout

    app = CSRFProtectionMiddleware(app)
    app = PluggableAuthenticationMiddleware(
        app,
        identifiers,
        authenticators,
        challengers,
        mdproviders,
        fas_request_classifier,
        default_challenge_decider,
        log_stream=log_stream,
    )

    return app
Ejemplo n.º 16
0
def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
    """Create a Pylons WSGI application and return it

    ``global_conf``
        The inherited configuration for this application. Normally from
        the [DEFAULT] section of the Paste ini file.

    ``full_stack``
        Whether this application provides a full WSGI stack (by default,
        meaning it handles its own exceptions and errors). Disable
        full_stack when this application is "managed" by another WSGI
        middleware.

    ``static_files``
        Whether this application serves its own static files; disable
        when another web server is responsible for serving them.

    ``app_conf``
        The application's local configuration. Normally specified in
        the [app:<name>] section of the Paste ini file (where <name>
        defaults to main).

    """
    # Configure the Pylons environment
    load_environment(global_conf, app_conf)

    # The Pylons WSGI app
    app = PylonsApp()

    for plugin in PluginImplementations(IMiddleware):
        app = plugin.make_middleware(app, config)

    # Routing/Session/Cache Middleware
    app = RoutesMiddleware(app, config['routes.map'])
    app = SessionMiddleware(app, config)
    app = CacheMiddleware(app, config)

    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
    #app = QueueLogMiddleware(app)

    if asbool(full_stack):
        # Handle Python exceptions
        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])

        # Display error documents for 401, 403, 404 status codes (and
        # 500 when debug is disabled)
        if asbool(config['debug']):
            app = StatusCodeRedirect(app, [400, 404])
        else:
            app = StatusCodeRedirect(app, [400, 404, 500])

    # Initialize repoze.who
    who_parser = WhoConfig(global_conf['here'])
    who_parser.parse(open(app_conf['who.config_file']))

    if asbool(config.get('openid_enabled', 'true')):
        from repoze.who.plugins.openid.identification import OpenIdIdentificationPlugin
        who_parser.identifiers = [i for i in who_parser.identifiers if \
                not isinstance(i, OpenIdIdentificationPlugin)]
        who_parser.challengers = [i for i in who_parser.challengers if \
                not isinstance(i, OpenIdIdentificationPlugin)]

    app = PluggableAuthenticationMiddleware(
        app,
        who_parser.identifiers,
        who_parser.authenticators,
        who_parser.challengers,
        who_parser.mdproviders,
        who_parser.request_classifier,
        who_parser.challenge_decider,
        logging.getLogger('repoze.who'),
        logging.WARN,  # ignored
        who_parser.remote_user_key,
    )

    # Establish the Registry for this application
    app = RegistryManager(app)

    if asbool(static_files):
        # Serve static files
        static_max_age = None if not asbool(config.get('ckan.cache_enabled')) \
            else int(config.get('ckan.static_max_age', 3600))

        static_app = StaticURLParser(config['pylons.paths']['static_files'],
                                     cache_max_age=static_max_age)
        static_parsers = [static_app, app]

        # Configurable extra static file paths
        extra_static_parsers = []
        for public_path in config.get('extra_public_paths', '').split(','):
            if public_path.strip():
                extra_static_parsers.append(
                    StaticURLParser(public_path.strip(),
                                    cache_max_age=static_max_age))
        app = Cascade(extra_static_parsers + static_parsers)

    return app
Ejemplo n.º 17
0
def make_flask_stack(conf, **app_conf):
    """ This has to pass the flask app through all the same middleware that
    Pylons used """

    root = os.path.dirname(
        os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

    debug = asbool(conf.get('debug', conf.get('DEBUG', False)))
    testing = asbool(app_conf.get('testing', app_conf.get('TESTING', False)))
    app = flask_app = CKANFlask(__name__)
    app.debug = debug
    app.testing = testing
    app.template_folder = os.path.join(root, 'templates')
    app.app_ctx_globals_class = CKAN_AppCtxGlobals
    app.url_rule_class = CKAN_Rule

    app.jinja_options = jinja_extensions.get_jinja_env_options()
    # Update Flask config with the CKAN values. We use the common config
    # object as values might have been modified on `load_environment`
    if config:
        app.config.update(config)
    else:
        app.config.update(conf)
        app.config.update(app_conf)

    # Do all the Flask-specific stuff before adding other middlewares

    # Secret key needed for flask-debug-toolbar and sessions
    if not app.config.get('SECRET_KEY'):
        app.config['SECRET_KEY'] = config.get('beaker.session.secret')
    if not app.config.get('SECRET_KEY'):
        raise RuntimeError(u'You must provide a value for the secret key'
                           ' with the SECRET_KEY config option')

    if debug:
        from flask_debugtoolbar import DebugToolbarExtension
        app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
        DebugToolbarExtension(app)

    # Use Beaker as the Flask session interface
    class BeakerSessionInterface(SessionInterface):
        def open_session(self, app, request):
            if 'beaker.session' in request.environ:
                return request.environ['beaker.session']

        def save_session(self, app, session, response):
            session.save()

    namespace = 'beaker.session.'
    session_opts = dict([(k.replace('beaker.', ''), v)
                         for k, v in config.iteritems()
                         if k.startswith(namespace)])
    if (not session_opts.get('session.data_dir')
            and session_opts.get('session.type', 'file') == 'file'):
        cache_dir = app_conf.get('cache_dir') or app_conf.get('cache.dir')
        session_opts['session.data_dir'] = '{data_dir}/sessions'.format(
            data_dir=cache_dir)

    app.wsgi_app = SessionMiddleware(app.wsgi_app, session_opts)
    app.session_interface = BeakerSessionInterface()

    # Add Jinja2 extensions and filters
    app.jinja_env.filters['empty_and_escape'] = \
        jinja_extensions.empty_and_escape

    # Common handlers for all requests
    app.before_request(ckan_before_request)
    app.after_request(ckan_after_request)

    # Template context processors
    app.context_processor(helper_functions)
    app.context_processor(c_object)

    @app.context_processor
    def ungettext_alias():
        u'''
        Provide `ungettext` as an alias of `ngettext` for backwards
        compatibility
        '''
        return dict(ungettext=ungettext)

    # Babel
    pairs = [(os.path.join(root, u'i18n'), 'ckan')
             ] + [(p.i18n_directory(), p.i18n_domain())
                  for p in PluginImplementations(ITranslation)]

    i18n_dirs, i18n_domains = zip(*pairs)

    app.config[u'BABEL_TRANSLATION_DIRECTORIES'] = ';'.join(i18n_dirs)
    app.config[u'BABEL_DOMAIN'] = 'ckan'
    app.config[u'BABEL_MULTIPLE_DOMAINS'] = ';'.join(i18n_domains)

    babel = CKANBabel(app)

    babel.localeselector(get_locale)

    @app.route('/hello', methods=['GET'])
    def hello_world():
        return 'Hello World, this is served by Flask'

    @app.route('/hello', methods=['POST'])
    def hello_world_post():
        return 'Hello World, this was posted to Flask'

    # Auto-register all blueprints defined in the `views` folder
    _register_core_blueprints(app)
    _register_error_handler(app)

    # Set up each IBlueprint extension as a Flask Blueprint
    for plugin in PluginImplementations(IBlueprint):
        if hasattr(plugin, 'get_blueprint'):
            app.register_extension_blueprint(plugin.get_blueprint())

    lib_plugins.register_group_plugins(app)
    lib_plugins.register_package_plugins(app)

    # Set flask routes in named_routes
    for rule in app.url_map.iter_rules():
        if '.' not in rule.endpoint:
            continue
        controller, action = rule.endpoint.split('.')
        needed = list(rule.arguments - set(rule.defaults or {}))
        route = {
            rule.endpoint: {
                'action': action,
                'controller': controller,
                'highlight_actions': action,
                'needed': needed
            }
        }
        config['routes.named_routes'].update(route)

    # Start other middleware
    for plugin in PluginImplementations(IMiddleware):
        app = plugin.make_middleware(app, config)

    # Fanstatic
    if debug:
        fanstatic_config = {
            'versioning': True,
            'recompute_hashes': True,
            'minified': False,
            'bottom': True,
            'bundle': False,
        }
    else:
        fanstatic_config = {
            'versioning': True,
            'recompute_hashes': False,
            'minified': True,
            'bottom': True,
            'bundle': True,
        }
    root_path = config.get('ckan.root_path', None)
    if root_path:
        root_path = re.sub('/{{LANG}}', '', root_path)
        fanstatic_config['base_url'] = root_path
    app = Fanstatic(app, **fanstatic_config)

    for plugin in PluginImplementations(IMiddleware):
        try:
            app = plugin.make_error_log_middleware(app, config)
        except AttributeError:
            log.critical('Middleware class {0} is missing the method'
                         'make_error_log_middleware.'.format(
                             plugin.__class__.__name__))

    # Initialize repoze.who
    who_parser = WhoConfig(conf['here'])
    who_parser.parse(open(app_conf['who.config_file']))

    app = PluggableAuthenticationMiddleware(
        app,
        who_parser.identifiers,
        who_parser.authenticators,
        who_parser.challengers,
        who_parser.mdproviders,
        who_parser.request_classifier,
        who_parser.challenge_decider,
        logging.getLogger('repoze.who'),
        logging.WARN,  # ignored
        who_parser.remote_user_key)

    # Update the main CKAN config object with the Flask specific keys
    # that were set here or autogenerated
    flask_config_keys = set(flask_app.config.keys()) - set(config.keys())
    for key in flask_config_keys:
        config[key] = flask_app.config[key]

    # Add a reference to the actual Flask app so it's easier to access
    app._wsgi_app = flask_app

    return app
Ejemplo n.º 18
0
def make_flask_stack(conf):
    """ This has to pass the flask app through all the same middleware that
    Pylons used """

    root = os.path.dirname(
        os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

    debug = asbool(conf.get('debug', conf.get('DEBUG', False)))
    testing = asbool(conf.get('testing', conf.get('TESTING', False)))
    app = flask_app = CKANFlask(__name__, static_url_path='')

    # Register storage for accessing group images, site logo, etc.
    storage_folder = []
    storage = uploader.get_storage_path()
    if storage:
        storage_folder = [os.path.join(storage, 'storage')]

    # Static files folders (core and extensions)
    public_folder = config.get(u'ckan.base_public_folder')
    app.static_folder = config.get(
        'extra_public_paths', ''
    ).split(',') + [os.path.join(root, public_folder)] + storage_folder

    app.jinja_options = jinja_extensions.get_jinja_env_options()
    app.jinja_env.policies['ext.i18n.trimmed'] = True

    app.debug = debug
    app.testing = testing
    app.template_folder = os.path.join(root, 'templates')
    app.app_ctx_globals_class = CKAN_AppCtxGlobals
    app.url_rule_class = CKAN_Rule

    # Update Flask config with the CKAN values. We use the common config
    # object as values might have been modified on `load_environment`
    if config:
        app.config.update(config)
    else:
        app.config.update(conf)

    # Do all the Flask-specific stuff before adding other middlewares

    # Secret key needed for flask-debug-toolbar and sessions
    if not app.config.get('SECRET_KEY'):
        app.config['SECRET_KEY'] = config.get('beaker.session.secret')
    if not app.config.get('SECRET_KEY'):
        raise RuntimeError(u'You must provide a value for the secret key'
                           ' with the SECRET_KEY config option')

    root_path = config.get('ckan.root_path', None)
    if debug:
        from flask_debugtoolbar import DebugToolbarExtension
        app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
        debug_ext = DebugToolbarExtension()

        # register path that includes `ckan.site_root` before
        # initializing debug app. In such a way, our route receives
        # higher precedence.

        # TODO: After removal of Pylons code, switch to
        # `APPLICATION_ROOT` config value for flask application. Right
        # now it's a bad option because we are handling both pylons
        # and flask urls inside helpers and splitting this logic will
        # bring us tons of headache.
        if root_path:
            app.add_url_rule(
                root_path.replace('{{LANG}}', '').rstrip('/') +
                '/_debug_toolbar/static/<path:filename>',
                '_debug_toolbar.static', debug_ext.send_static_file
            )
        debug_ext.init_app(app)

        from werkzeug.debug import DebuggedApplication
        app.wsgi_app = DebuggedApplication(app.wsgi_app, True)

    # Use Beaker as the Flask session interface
    class BeakerSessionInterface(SessionInterface):
        def open_session(self, app, request):
            if 'beaker.session' in request.environ:
                return request.environ['beaker.session']

        def save_session(self, app, session, response):
            session.save()

    namespace = 'beaker.session.'
    session_opts = {k.replace('beaker.', ''): v
                    for k, v in six.iteritems(config)
                    if k.startswith(namespace)}
    if (not session_opts.get('session.data_dir') and
            session_opts.get('session.type', 'file') == 'file'):
        cache_dir = conf.get('cache_dir') or conf.get('cache.dir')
        session_opts['session.data_dir'] = '{data_dir}/sessions'.format(
            data_dir=cache_dir)

    app.wsgi_app = SessionMiddleware(app.wsgi_app, session_opts)
    app.session_interface = BeakerSessionInterface()

    # Add Jinja2 extensions and filters
    app.jinja_env.filters['empty_and_escape'] = \
        jinja_extensions.empty_and_escape

    # Common handlers for all requests
    app.before_request(ckan_before_request)
    app.after_request(ckan_after_request)

    # Template context processors
    app.context_processor(helper_functions)
    app.context_processor(c_object)

    @app.context_processor
    def ungettext_alias():
        u'''
        Provide `ungettext` as an alias of `ngettext` for backwards
        compatibility
        '''
        return dict(ungettext=ungettext)

    # Babel
    _ckan_i18n_dir = i18n.get_ckan_i18n_dir()

    pairs = [
        (_ckan_i18n_dir, u'ckan')
    ] + [
        (p.i18n_directory(), p.i18n_domain())
        for p in PluginImplementations(ITranslation)
    ]

    i18n_dirs, i18n_domains = zip(*pairs)

    app.config[u'BABEL_TRANSLATION_DIRECTORIES'] = ';'.join(i18n_dirs)
    app.config[u'BABEL_DOMAIN'] = 'ckan'
    app.config[u'BABEL_MULTIPLE_DOMAINS'] = ';'.join(i18n_domains)

    babel = CKANBabel(app)

    babel.localeselector(get_locale)

    # WebAssets
    _setup_webassets(app)

    # Auto-register all blueprints defined in the `views` folder
    _register_core_blueprints(app)
    _register_error_handler(app)

    # Set up each IBlueprint extension as a Flask Blueprint
    for plugin in PluginImplementations(IBlueprint):
        if hasattr(plugin, 'get_blueprint'):
            plugin_blueprints = plugin.get_blueprint()
            if not isinstance(plugin_blueprints, list):
                plugin_blueprints = [plugin_blueprints]
            for blueprint in plugin_blueprints:
                app.register_extension_blueprint(blueprint)

    lib_plugins.register_package_blueprints(app)
    lib_plugins.register_group_blueprints(app)

    # Set flask routes in named_routes
    # TODO: refactor whatever helper is using this to not do it
    if 'routes.named_routes' not in config:
        config['routes.named_routes'] = {}
    for rule in app.url_map.iter_rules():
        if '.' not in rule.endpoint:
            continue
        controller, action = rule.endpoint.split('.')
        needed = list(rule.arguments - set(rule.defaults or {}))
        route = {
            rule.endpoint: {
                'action': action,
                'controller': controller,
                'highlight_actions': action,
                'needed': needed
            }
        }
        config['routes.named_routes'].update(route)

    # Start other middleware
    for plugin in PluginImplementations(IMiddleware):
        app = plugin.make_middleware(app, config)

    for plugin in PluginImplementations(IMiddleware):
        try:
            app = plugin.make_error_log_middleware(app, config)
        except AttributeError:
            log.critical('Middleware class {0} is missing the method'
                         'make_error_log_middleware.'
                         .format(plugin.__class__.__name__))

    # Initialize repoze.who
    who_parser = WhoConfig(conf['here'])
    who_parser.parse(open(conf['who.config_file']))

    app = PluggableAuthenticationMiddleware(
        RepozeAdapterMiddleware(app),
        who_parser.identifiers,
        who_parser.authenticators,
        who_parser.challengers,
        who_parser.mdproviders,
        who_parser.request_classifier,
        who_parser.challenge_decider,
        logging.getLogger('repoze.who'),
        logging.WARN,  # ignored
        who_parser.remote_user_key
    )

    # Update the main CKAN config object with the Flask specific keys
    # that were set here or autogenerated
    flask_config_keys = set(flask_app.config.keys()) - set(config.keys())
    for key in flask_config_keys:
        config[key] = flask_app.config[key]

    # Prevent the host from request to be added to the new header location.
    app = HostHeaderMiddleware(app)
    if six.PY3:
        app = I18nMiddleware(app)

        if asbool(config.get('ckan.tracking_enabled', 'false')):
            app = TrackingMiddleware(app, config)

    # Add a reference to the actual Flask app so it's easier to access
    app._wsgi_app = flask_app

    return app
Ejemplo n.º 19
0
def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
    """Create a Pylons WSGI application and return it

    ``global_conf``
        The inherited configuration for this application. Normally from
        the [DEFAULT] section of the Paste ini file.

    ``full_stack``
        Whether this application provides a full WSGI stack (by default,
        meaning it handles its own exceptions and errors). Disable
        full_stack when this application is "managed" by another WSGI
        middleware.

    ``static_files``
        Whether this application serves its own static files; disable
        when another web server is responsible for serving them.

    ``app_conf``
        The application's local configuration. Normally specified in
        the [app:<name>] section of the Paste ini file (where <name>
        defaults to main).

    """
    # Configure the Pylons environment
    load_environment(global_conf, app_conf)

    # The Pylons WSGI app
    app = PylonsApp()

    # Routing/Session/Cache Middleware
    app = RoutesMiddleware(app, config['routes.map'])
    app = SessionMiddleware(app, config)
    app = CacheMiddleware(app, config)

    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
    basicauth = BasicAuthPlugin('OpenSpending')
    auth_tkt = AuthTktCookiePlugin(
        'RANDOM_KEY_THAT_ONLY_LOOKS_LIKE_A_PLACEHOLDER',
        cookie_name='openspending_login',
        timeout=86400 * 90,
        reissue_time=3600)
    form = FriendlyFormPlugin('/login',
                              '/perform_login',
                              '/after_login',
                              '/logout',
                              '/after_logout',
                              rememberer_name='auth_tkt')
    identifiers = [('auth_tkt', auth_tkt), ('basicauth', basicauth),
                   ('form', form)]
    authenticators = [('auth_tkt', auth_tkt),
                      ('username', UsernamePasswordAuthenticator()),
                      ('apikey', ApiKeyAuthenticator())]
    challengers = [('form', form), ('basicauth', basicauth)]
    log_stream = sys.stdout
    app = PluggableAuthenticationMiddleware(app,
                                            identifiers,
                                            authenticators,
                                            challengers, [],
                                            default_request_classifier,
                                            default_challenge_decider,
                                            log_stream=log_stream,
                                            log_level=logging.WARN)

    if asbool(full_stack):
        # Handle Python exceptions
        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])

        # Display error documents for 401, 403, 404 status codes (and
        # 500 when debug is disabled)
        if asbool(config['debug']):
            app = StatusCodeRedirect(app)
        else:
            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])

    # Establish the Registry for this application
    app = RegistryManager(app)

    if asbool(static_files):
        max_age = None if asbool(config['debug']) else 3600

        # Serve static files
        static_app = StaticURLParser(config['pylons.paths']['static_files'],
                                     cache_max_age=max_age)
        static_parsers = [static_app, app]
        app = Cascade(static_parsers)

    return app
Ejemplo n.º 20
0
def make_app(conf, full_stack=True, static_files=True, **app_conf):
    """Create a Pylons WSGI application and return it

    ``conf``
        The inherited configuration for this application. Normally from
        the [DEFAULT] section of the Paste ini file.

    ``full_stack``
        Whether this application provides a full WSGI stack (by default,
        meaning it handles its own exceptions and errors). Disable
        full_stack when this application is "managed" by another WSGI
        middleware.

    ``static_files``
        Whether this application serves its own static files; disable
        when another web server is responsible for serving them.

    ``app_conf``
        The application's local configuration. Normally specified in
        the [app:<name>] section of the Paste ini file (where <name>
        defaults to main).

    """
    # Configure the Pylons environment
    load_environment(conf, app_conf)

    # The Pylons WSGI app
    app = PylonsApp()
    # set pylons globals
    app_globals.reset()

    for plugin in PluginImplementations(IMiddleware):
        app = plugin.make_middleware(app, config)

    # Routing/Session/Cache Middleware
    app = RoutesMiddleware(app, config['routes.map'])
    # we want to be able to retrieve the routes middleware to be able to update
    # the mapper.  We store it in the pylons config to allow this.
    config['routes.middleware'] = app
    app = SessionMiddleware(app, config)
    app = CacheMiddleware(app, config)

    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
    #app = QueueLogMiddleware(app)

    # Fanstatic
    if asbool(config.get('debug', False)):
        fanstatic_config = {
            'versioning': True,
            'recompute_hashes': True,
            'minified': False,
            'bottom': True,
            'bundle': False,
        }
    else:
        fanstatic_config = {
            'versioning': True,
            'recompute_hashes': False,
            'minified': True,
            'bottom': True,
            'bundle': True,
        }
    app = Fanstatic(app, **fanstatic_config)

    if asbool(full_stack):
        # Handle Python exceptions
        app = ErrorHandler(app, conf, **config['pylons.errorware'])

        # Display error documents for 401, 403, 404 status codes (and
        # 500 when debug is disabled)
        if asbool(config['debug']):
            app = StatusCodeRedirect(app, [400, 404])
        else:
            app = StatusCodeRedirect(app, [400, 404, 500])

    # Initialize repoze.who
    who_parser = WhoConfig(conf['here'])
    who_parser.parse(open(app_conf['who.config_file']))

    if asbool(config.get('openid_enabled', 'true')):
        from repoze.who.plugins.openid.identification import OpenIdIdentificationPlugin
        # Monkey patches for repoze.who.openid
        # Fixes #1659 - enable log-out when CKAN mounted at non-root URL
        from ckan.lib import repoze_patch
        OpenIdIdentificationPlugin.identify = repoze_patch.identify
        OpenIdIdentificationPlugin.redirect_to_logged_in = repoze_patch.redirect_to_logged_in
        OpenIdIdentificationPlugin._redirect_to_loginform = repoze_patch._redirect_to_loginform
        OpenIdIdentificationPlugin.challenge = repoze_patch.challenge

        who_parser.identifiers = [i for i in who_parser.identifiers if \
                not isinstance(i, OpenIdIdentificationPlugin)]
        who_parser.challengers = [i for i in who_parser.challengers if \
                not isinstance(i, OpenIdIdentificationPlugin)]

    app = PluggableAuthenticationMiddleware(app,
                who_parser.identifiers,
                who_parser.authenticators,
                who_parser.challengers,
                who_parser.mdproviders,
                who_parser.request_classifier,
                who_parser.challenge_decider,
                logging.getLogger('repoze.who'),
                logging.WARN,  # ignored
                who_parser.remote_user_key,
           )

    # Establish the Registry for this application
    app = RegistryManager(app)

    app = I18nMiddleware(app, config)

    if asbool(static_files):
        # Serve static files
        static_max_age = None if not asbool(config.get('ckan.cache_enabled')) \
            else int(config.get('ckan.static_max_age', 3600))

        static_app = StaticURLParser(config['pylons.paths']['static_files'],
                cache_max_age=static_max_age)
        static_parsers = [static_app, app]

        # Configurable extra static file paths
        extra_static_parsers = []
        for public_path in config.get('extra_public_paths', '').split(','):
            if public_path.strip():
                extra_static_parsers.append(
                    StaticURLParser(public_path.strip(),
                        cache_max_age=static_max_age)
                )
        app = Cascade(extra_static_parsers + static_parsers)

    # Page cache
    if asbool(config.get('ckan.page_cache_enabled')):
        app = PageCacheMiddleware(app, config)

    # Tracking
    if asbool(config.get('ckan.tracking_enabled', 'false')):
        app = TrackingMiddleware(app, config)

    return app
Ejemplo n.º 21
0
    def add_auth_middleware(self, app, skip_authentication):
        """
        """
        log_stream = config.get('who.log_stream', 'stdout')
        log_stream = LOG_STREAMS.get(log_stream, log_stream)
        if isinstance(log_stream, basestring):
            log_stream = logging.getLogger(log_stream)
        log_level = LOG_LEVELS.get(config['who.log_level'], logging.ERROR)
        log.debug("LOG_STREAM %s LOG_LEVEL %s", str(log_stream),
                  str(log_level))

        if 'who.config_file' in config and asbool(
                config.get('bisque.has_database')):
            parser = WhoConfig(config['here'])
            parser.parse(open(config['who.config_file']))

            if not asbool(skip_authentication):
                app = PluggableAuthenticationMiddleware(
                    app,
                    parser.identifiers,
                    parser.authenticators,
                    parser.challengers,
                    parser.mdproviders,
                    parser.request_classifier,
                    parser.challenge_decider,
                    log_stream=log_stream,
                    log_level=log_level,
                    remote_user_key=parser.remote_user_key,
                )
            else:
                app = AuthenticationForgerMiddleware(
                    app,
                    parser.identifiers,
                    parser.authenticators,
                    parser.challengers,
                    parser.mdproviders,
                    parser.request_classifier,
                    parser.challenge_decider,
                    log_stream=log_stream,
                    log_level=log_level,
                    remote_user_key=parser.remote_user_key,
                )
        else:
            log.info("MEX auth only")
            # Add mex only authentication
            from repoze.who.plugins.basicauth import BasicAuthPlugin
            from bq.core.lib.mex_auth import make_plugin
            from repoze.who.classifiers import default_request_classifier
            from repoze.who.classifiers import default_challenge_decider
            basicauth = BasicAuthPlugin('repoze.who')
            mexauth = make_plugin()

            identifiers = [('mexauth', mexauth)]
            authenticators = [('mexauth', mexauth)]
            challengers = []
            mdproviders = []
            app = PluggableAuthenticationMiddleware(
                app,
                identifiers,
                authenticators,
                challengers,
                mdproviders,
                default_request_classifier,
                default_challenge_decider,
                log_stream=log_stream,
                log_level=log_level,
            )
        return app
Ejemplo n.º 22
0
def setup_auth(app,
               authmetadata,
               form_plugin=None,
               form_identifies=True,
               cookie_secret='secret',
               cookie_name='authtkt',
               login_url='/login',
               login_handler='/login_handler',
               post_login_url=None,
               logout_handler='/logout_handler',
               post_logout_url=None,
               login_counter_name=None,
               cookie_timeout=None,
               cookie_reissue_time=None,
               **who_args):
    """
    Sets :mod:`repoze.who` up with the provided authenticators and
    options to create FriendlyFormPlugin/FastFormPlugin.

    It returns a middleware that provides identification,
    authentication and authorization in a way that is compatible
    with repoze.who and repoze.what.
    """
    if 'charset' in who_args:  #pragma: no cover
        log.warn('charset argument in authentication setup is ignored')
        who_args.pop('charset')

    # If no identifiers are provided in repoze setup arguments
    # then create a default one using AuthTktCookiePlugin.
    if 'identifiers' not in who_args:
        from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
        cookie = AuthTktCookiePlugin(cookie_secret,
                                     cookie_name,
                                     timeout=cookie_timeout,
                                     reissue_time=cookie_reissue_time)
        who_args['identifiers'] = [('cookie', cookie)]
        who_args['authenticators'].insert(0, ('cookie', cookie))

    # If no form plugin is provided then create a default
    # one using the provided options.
    if form_plugin is None:
        from tg.configuration.auth.fastform import FastFormPlugin
        form = FastFormPlugin(login_url,
                              login_handler,
                              post_login_url,
                              logout_handler,
                              post_logout_url,
                              rememberer_name='cookie',
                              login_counter_name=login_counter_name)
    else:
        form = form_plugin

    if form_identifies:
        who_args['identifiers'].insert(0, ('main_identifier', form))

    # Setting the repoze.who challengers:
    if 'challengers' not in who_args:
        who_args['challengers'] = []
    who_args['challengers'].append(('form', form))

    # Including logging
    log_file = who_args.pop('log_file', None)
    if log_file is not None:
        if log_file.lower() == 'stdout':
            log_stream = sys.stdout
        elif log_file.lower() == 'stderr':
            log_stream = sys.stderr
        else:
            log_stream = open(log_file, 'wb')
        who_args['log_stream'] = log_stream

    log_level = who_args.get('log_level', None)
    if log_level is None:
        log_level = logging.INFO
    else:
        log_level = _LEVELS[log_level.lower()]
    who_args['log_level'] = log_level

    # Setting up the metadata provider for the user informations
    if 'mdproviders' not in who_args:
        who_args['mdproviders'] = []

    if authmetadata:
        authmd = _AuthMetadataProvider(authmetadata)
        who_args['mdproviders'].append(('authmd', authmd))

    # Set up default classifier
    if 'classifier' not in who_args:
        who_args['classifier'] = default_request_classifier

    # Set up default challenger decider
    if 'challenge_decider' not in who_args:
        who_args['challenge_decider'] = turbogears_challenge_decider

    skip_authn = who_args.pop('skip_authentication', False)
    if asbool(skip_authn):
        return _AuthenticationForgerMiddleware(app, **who_args)
    else:
        return PluggableAuthenticationMiddleware(app, **who_args)
Ejemplo n.º 23
0
def make_pylons_stack(conf, full_stack=True, static_files=True, **app_conf):
    """Create a Pylons WSGI application and return it

    ``conf``
        The inherited configuration for this application. Normally from
        the [DEFAULT] section of the Paste ini file.

    ``full_stack``
        Whether this application provides a full WSGI stack (by default,
        meaning it handles its own exceptions and errors). Disable
        full_stack when this application is "managed" by another WSGI
        middleware.

    ``static_files``
        Whether this application serves its own static files; disable
        when another web server is responsible for serving them.

    ``app_conf``
        The application's local configuration. Normally specified in
        the [app:<name>] section of the Paste ini file (where <name>
        defaults to main).

    """
    # The Pylons WSGI app
    app = pylons_app = CKANPylonsApp()

    for plugin in PluginImplementations(IMiddleware):
        app = plugin.make_middleware(app, config)

    # Routing/Session/Cache Middleware
    app = RoutesMiddleware(app, config['routes.map'])
    # we want to be able to retrieve the routes middleware to be able to update
    # the mapper.  We store it in the pylons config to allow this.
    config['routes.middleware'] = app
    app = SessionMiddleware(app, config)
    app = CacheMiddleware(app, config)

    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
    # app = QueueLogMiddleware(app)
    if asbool(config.get('ckan.use_pylons_response_cleanup_middleware', True)):
        app = execute_on_completion(app, config,
                                    cleanup_pylons_response_string)

    # Fanstatic
    if asbool(config.get('debug', False)):
        fanstatic_config = {
            'versioning': True,
            'recompute_hashes': True,
            'minified': False,
            'bottom': True,
            'bundle': False,
        }
    else:
        fanstatic_config = {
            'versioning': True,
            'recompute_hashes': False,
            'minified': True,
            'bottom': True,
            'bundle': True,
        }
    app = Fanstatic(app, **fanstatic_config)

    for plugin in PluginImplementations(IMiddleware):
        try:
            app = plugin.make_error_log_middleware(app, config)
        except AttributeError:
            log.critical('Middleware class {0} is missing the method'
                         'make_error_log_middleware.'.format(
                             plugin.__class__.__name__))

    if asbool(full_stack):
        # Handle Python exceptions
        app = ErrorHandler(app, conf, **config['pylons.errorware'])

        # Display error documents for 400, 403, 404 status codes (and
        # 500 when debug is disabled)
        if asbool(config['debug']):
            app = StatusCodeRedirect(app, [400, 403, 404])
        else:
            app = StatusCodeRedirect(app, [400, 403, 404, 500])

    # Initialize repoze.who
    who_parser = WhoConfig(conf['here'])
    who_parser.parse(open(app_conf['who.config_file']))

    app = PluggableAuthenticationMiddleware(
        app,
        who_parser.identifiers,
        who_parser.authenticators,
        who_parser.challengers,
        who_parser.mdproviders,
        who_parser.request_classifier,
        who_parser.challenge_decider,
        logging.getLogger('repoze.who'),
        logging.WARN,  # ignored
        who_parser.remote_user_key)

    # Establish the Registry for this application
    app = RegistryManager(app)

    app = common_middleware.I18nMiddleware(app, config)

    if asbool(static_files):
        # Serve static files
        static_max_age = None if not asbool(
            config.get('ckan.cache_enabled')) \
            else int(config.get('ckan.static_max_age', 3600))

        static_app = StaticURLParser(config['pylons.paths']['static_files'],
                                     cache_max_age=static_max_age)
        static_parsers = [static_app, app]

        storage_directory = uploader.get_storage_path()
        if storage_directory:
            path = os.path.join(storage_directory, 'storage')
            try:
                os.makedirs(path)
            except OSError, e:
                # errno 17 is file already exists
                if e.errno != 17:
                    raise

            storage_app = StaticURLParser(path, cache_max_age=static_max_age)
            static_parsers.insert(0, storage_app)

        # Configurable extra static file paths
        extra_static_parsers = []
        for public_path in config.get('extra_public_paths', '').split(','):
            if public_path.strip():
                extra_static_parsers.append(
                    StaticURLParser(public_path.strip(),
                                    cache_max_age=static_max_age))
        app = Cascade(extra_static_parsers + static_parsers)