检查当前用户是否有权使用金字塔服务?

时间:2015-06-15 20:57:46

标签: python acl pyramid cornice

我使用Cornice和Pyramid与ACL Auth。这是older question的副本,我在金字塔改变时重新询问。

Current docs表示已将pyramid.security.has_permission替换为request.has_permission,其中context具有可选的has_permission arg。我尝试在所有服务的循环中使用request来查看当前用户(@resource)可以访问哪些服务。

最终目标是动态扫描所有Cornice服务(即使用Cornice' 'view'装饰器查看文件)以查看哪些服务器已获得授权以获得给定权限(即has_permission)当前用户。除了from cornice import service # Get our list of services services = service.get_services() # Assume we have an authenticated user logged in, thus attaching auth info to request for svc in services: context = magic_context_function(svc) if request.has_permission('view', context) == False: # Code will go here to hide endpoint documentation for this endpoint 之外,我还可以使用其他方式执行此操作。

此知识的用例是提供Swagger Spec JSON文档,该文档仅记录当前用户可用的API端点。

我希望代码看起来像这样:

<asp:CustomValidator ID="CustomValidator1" runat="server" SetFocusOnError="true" Display="Dynamic" ValidateEmptyText="true" ControlToValidate="tbFirstName" ClientValidationFunction="CVH.createFunction(notEmpty, 'tbFirstName','tbFirstNameRequired')"></asp:CustomValidator>

1 个答案:

答案 0 :(得分:1)

似乎答案应该是使用view_execution_permitted(context, request, name=''),但我无法使用任意视图名称,因为name arg与cornice.service.name不匹配值。

但是,这是Pyramid issue on Github的半解决方案。您需要一些导入才能使链接的解决方案正常工作(更好)。这是完整的代码

from pyramid.security import _get_registry, Allowed
from pyramid.interfaces import IRouteRequest, IRequest, IViewClassifier, ISecuredView, IView
from zope.interface import providedBy
def route_view_execution_permitted(context, request, route_name, name=''):
    reg = _get_registry(request)
    context_iface = providedBy(context)
    request_iface = reg.queryUtility(
        IRouteRequest,
        name=route_name,
        default=IRequest)
    provides = (IViewClassifier, request_iface, context_iface)

    view = reg.adapters.lookup(provides, ISecuredView, name=name)
    if view is None:
        view = reg.adapters.lookup(provides, IView, name=name)
        if view is None:
            raise TypeError('No registered view satisfies the constraints. '
                            'It would not make sense to claim that this view '
                            '"is" or "is not" permitted.')
        return Allowed(
            'Allowed: view name %r in context %r for route %r (no permission defined)' %
            (name, context, route_name))
    return view.__permitted__(context, request)

可以使用上面的函数来确定当前用户(从request对象确定)是否能够访问服务(按名称),如下所示:

from cornice import service
services = service.get_services()
for svc in services:
  view_permitted = route_view_execution_permitted(request.context, request, svc.name)
  if view_permitted == True:
      # Do something interesting...

我发现上述解决方案有两个不足之处:

  1. 这很慢,因为svc循环的每次迭代都会因某种原因打开与API的新连接。
  2. 它会返回错误的结果(即表示一个人有权获得他没有的服务,反之亦然)
  3. 也许有人可以看到改善上述答案的方法。与此同时,这是一个解决方案,使用附加到每个服务的ACL,然后确定当前request.effective_principals是否匹配。

    # Now see if current user meets ACL requirements for any permission
    is_permitted = None  # set our default.
    for ace in acl:
        for principal in request.effective_principals:
            if ace[1] == principal:
                is_permitted = True if ace[0] == Allow else False
                break
        if is_permitted is not None:
            break
    
    if is_permitted is True:
        # Do something interesting...
    

    这里的弱点是:

    1. 由于与之前的解决方案相同的原因,它很慢
    2. 执行时,它只查看@resource - 装饰的服务类, @view - 装饰的方法,这些方法可能拥有自己的权限或acls。
    3. 这可以通过以下方式解决:

      for method, view, args in service.definitions:
          if 'permission' in args:
              # Now start looking at permission to see if they match what's given by the parent ACL in the resource class
              # Also, the special "__no_permission_required__" value means we should not have a Security Requirement Object
              if args['permission'] == NO_PERMISSION_REQUIRED :
                  # Interesting....