zopefoundation / zope.component

Other
32 stars 15 forks source link

Register protected utility (Register protected vocabulary) #65

Open ksuess opened 2 years ago

ksuess commented 2 years ago

BUG/PROBLEM REPORT (OR OTHER COMMON ISSUE)

Maybe I am wrong, but queryUtility seems to return a utility without a permission check. Background is the need to protect vocabularies:

  <utility
      provides="zope.schema.interfaces.IVocabularyFactory"
      name="plone.restapi.testing.protected_vocabulary"
      component=".tests.test_services_vocabularies.test_vocabulary_factory"
      permission="cmf.ManagePortal"
      />

What I did:

zope.component is kind of complex. I got so far that I think there is a permission checker missing in zope.component.zcml.utility

        if component:
            # checker = Checker({
            #     '__call__': permission
            # })
            checker = _checker(component, permission, None, None)
            component = proxify(
                component,
                checker,
                provides,
                permission
            )

https://github.com/zopefoundation/zope.component/blob/5bd246ed532d8ace5034bb09777b9f5b8eb87150/src/zope/component/zcml.py#L398-L401

Even with the checker its not obvious for me why the permission is not regarded.

What I expect to happen:

queryUtility does check the permission of the utility registration.

What actually happened:

permission is ignored.

What version of Python and Zope/Addons I am using:

Before we implement a security check in plone.app.vocabulary and maybe also in plone.restapi, I would like to know more about queryUtility and protected utilities. As any implementation (for example https://github.com/plone/plone.restapi/pull/1287) in Plone does keep the door open for quering a utility without permission check.

d-maurer commented 2 years ago

Katja Süss wrote at 2021-12-1 06:22 -0800:

Maybe I am wrong, but queryUtility seems to return a utility without a permission check.

It is very difficult to check permissions for utilities in the Zope world.

The problem: Users do not (directly) have permissions but roles. The map from roles to permissions is determined by location dependent permission to role maps. This means that in order to check permissions for an object (and the current user), this object must get a location (relative to which the permission to role map is determined).

For global utilities, there is no natural location. For local utilities, the site at which the utility is registered might be taken as the location. But, likely it is not implemented (like permission checking for utilities in general).

Another important aspect: in the Zope world, trusted code (like queryUtility, queryAdapter) is not restricted by permissions. For adapters, and especially views, the returned objects have security assertions which can be explicitly checked by trusted code and are implicitly checked in untrusted code.

In the wider zope toolkit world (in contrast to Zope), the zope.component functions return security proxies. Again you get the same objects independent of the permissions/roles the current user has. The check is only made when the object is actually used.

You should no expect that queryUtility performs internal security checks.

ksuess commented 2 years ago

Thanks for the explanation! I'm on the way getting a better understanding.

Just as a comment to our use case "protected vocabulary" in Plone: Maybe an abstraction layer like https://github.com/zopefoundation/zope.vocabularyregistry would come in handy to