Jens Vagelpohl wrote:
I have found a strange security issue with Zope 2.8.1 that seems to stem from code not doing what it was supposed to do in Zope 2.7.x, but which works in 2.8.1 and then causes other side effects in code that relied on the broken behavior.

Symptom: In Zope 2.8.1 it is *impossible* to override a ClassSecurityInfo security declaration in an Archetypes-derived content item. (I have a small set of unit tests that proves the behavior under Zope 2.8.1 if anyone is interested)

A little background: When you register an Archetypes-derived content type, it will do all the generated accessor/setter method magic and then call InitializeClass a second time.

The code in lib/python/App/ has changed between Zope 2.7.x and Zope 2.8 in order to support new-style classes. To be more precise, instead of manipulating the class __dict__ directly we now use setattr/delattr/etc. This change seems to have "un-broken" code which did not do what the code comments suggest. Namely, when a class is sent through class_init.default_class_init__ (better known as Globals.InitializeClass) the class __dict__ is searched to find objects that look like ClassSecurityInfo instances in order to read and apply the security settings. After finding the ClassSecurityInfo instance, it is force-deleted from the object (the comments say, "out of paranoia"). However, somehow this did not work correctly in Zope 2.7.x, where the deletion call looked like...

del dict[key]

(dict being the class __dict__, and key being the name of the ClassSecurityInfo instance). Under Zope 2.8, it looks like this:

delattr(self, key)

(self being the class object).

Under Zope 2.7, the security object *would still be there* when hitting InitializeClass for the second time via Archetypes' registerType, which in turn meant Archetypes would not instantiate its own ClassSecurityInfo instance and stuff it with the declarations from whatever Archetypes-derived base class you used.

In Zope 2.8, the deletion actually works as intended - but due to that fact Archetypes will instantiate its own ClassSecurityInfo and populate it with the declarations from the base class that I am trying to override. So the overridden settings are all overwritten again by the base class declaration.

My question is, what is the reasoning behind deleting the ClassSecurityInfo object from the class after it has been read the first time? How can this be implemented in a sane way so that custom security declarations can be retained?

My understanding (and the way we use it when monkey patching for instance) is that whenevery you apply new security to a class, you create a new ClassSecurityInfo on it. It only defines "new stuff" to do. The real synthesized security is still stored in __ac_permissions__.

class C(SimpleItem):
    security = ClassSecurityInfo()
    def foo(): ...


then later on:

security = ClassSecurityInfo() = security
C.newmethod = something

Anyway that's what I do. I never relied on a preexisting


Florent Guillaume, Nuxeo (Paris, France)   CTO, Director of R&D
+33 1 40 33 71 59   [EMAIL PROTECTED]
Zope-Dev maillist  -
**  No cross posts or HTML encoding!  **
(Related lists - )

Reply via email to