防止匿名访问CKAN网站的方法

Approach for preveting annomyous access to CKAN site

我有一个 CKAN 站点 运行 配置了 ckanext-ldap 扩展,但我只希望经过身份验证的用户无法访问该站点。

这是我目前的解决方案,但我并不完全满意:

import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit

def site_read(context, data_dict):
    # List of allowed paths, when not logged in
    allowed_anon_paths = ['/user/login', '/ldap_login_handler']

    # Prevent "site read" if the user is not logged in and the
    # request path is not in the list of allowed anonymous paths
    if not context.get('user') and toolkit.request.path not in allowed_anon_paths:
        return {'success': False}

    return {'success': True}

class Disable_Anon_AccessPlugin(plugins.SingletonPlugin):
    plugins.implements(plugins.IAuthFunctions)

    def get_auth_functions(self):
        return {'site_read': site_read}

它阻止匿名用户访问任何页面(与登录相关的除外),但它在所有页面上提供 403 禁止错误,直到登录。

(另外 API 请求失败并出现 500 错误,除非已登录或提供 API 密钥,但我可以接受)

如果未登录,我想不出重定向到登录页面的方法 and/or 使 "remember me" 功能正常工作。

添加如下内容:toolkit.redirect_to('/user/login') 而不是 return {'success': False} 没有效果。

我也查看了 IRoutes 接口,但我不知道如何获取当前登录的用户(或检查用户是否登录)

我认为有几种方法可以实现这一点。

可能是最简单的。您可以尝试这样的操作 suggestion to 检查用户是否在每个页面上登录,如果没有则重定向。但这让人们知道网站在那里并尝试登录。

您可以打破一些身份验证并将其放在应用程序前面的 gateway/load balancer/reverse 代理上并在那里进行身份验证(我看到类似的是 azure 与应用程序网关 运行 nginx 与 azure AD).

如果您使用的是 LDAP,我猜您可能有本地网络(可能是 Intranet?)。你也可以把它放在后面。或者创建一个阻止访问的防火墙,除非特定的网络或 IP 阻止。

Another suggestion

我在 CKAN 中看到了以下方法来防止未登录访问该站点。

它使用IMiddleware插件接口:

class AuthMiddleware(object):
    def __init__(self, app, app_conf):
        self.app = app
    def __call__(self, environ, start_response):
        # if logged in via browser cookies or API key, all pages accessible
        if 'repoze.who.identity' in environ or self._get_user_for_apikey(environ) or not is_iar():
            return self.app(environ,start_response)
        else:
            # otherwise only login/reset and front pages are accessible
            if (environ['PATH_INFO'] == '/' or environ['PATH_INFO'] == '/user/login' or environ['PATH_INFO'] == '/user/_logout'
                                or '/user/reset' in environ['PATH_INFO'] or environ['PATH_INFO'] == '/user/logged_out'
                                or environ['PATH_INFO'] == '/user/logged_in' or environ['PATH_INFO'] == '/user/logged_out_redirect'):
                return self.app(environ,start_response)
            else:
                # http://rufuspollock.org/2006/09/28/wsgi-middleware/
                environ['wsgiorg.routing_args'] = '',{'action': 'login', 'controller': 'user'}
                return self.app(environ,start_response)

    def _get_user_for_apikey(self, environ):
        # Adapted from https://github.com/ckan/ckan/blob/625b51cdb0f1697add59c7e3faf723a48c8e04fd/ckan/lib/base.py#L396
        apikey_header_name = config.get(base.APIKEY_HEADER_NAME_KEY,
                                        base.APIKEY_HEADER_NAME_DEFAULT)
        apikey = environ.get(apikey_header_name, '')
        if not apikey:
            # For misunderstanding old documentation (now fixed).
            apikey = environ.get('HTTP_AUTHORIZATION', '')
        if not apikey:
            apikey = environ.get('Authorization', '')
            # Forget HTTP Auth credentials (they have spaces).
            if ' ' in apikey:
                apikey = ''
        if not apikey:
            return None
        apikey = unicode(apikey)
        # check if API key is valid by comparing against keys of registered users
        query = model.Session.query(model.User)
        user = query.filter_by(apikey=apikey).first()
        return user

然后将其添加到您的插件中 class,例如

class Disable_Anon_AccessPlugin(plugins.SingletonPlugin):
    plugins.implements(plugins.IMiddleware, inherit=True)

    def make_middleware(self, app, config):
        return AuthMiddleware(app, config)