[Zope-dev] Re: Strange security issue with Zope 2.8.1
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__. Yes, your understanding matches what I know now. Part of my earlier diagnosis was wrong, the behavior of class_init has not changed between Zope 2.7 and Zope 2.8, just the behavior of Archetypes. What Archetypes seems to do is to generate a new ClassSecurityInfo during the call to registerType, which does not contain added information, but information about every single method on the class. It does try to look at the already existing __ac_permissions__ to make sure already set permissions don't get stomped, but when a name is declared private or public it will not be part of __ac_permissions__ and Archetypes will gladly stomp all over it. I have applied a patch locally (and submitted it on the Archetypes bug tracker on sf.net) that seems to solve the problem. I honestly don't know if there are other dangerous consequences because the way Archetypes works is just really dark magic which I don't want to get into too far. Basically, at the point where it tries to find already- set permissions, I am also trying to find a name method__roles__ to determine if something has already been declared private or public, and then re-declare it private or public on the ClassSecurityInfo object that Archetypes creates: Index: Archetypes/ClassGen.py === --- Archetypes/ClassGen.py (revision 6167) +++ Archetypes/ClassGen.py (working copy) @@ -103,6 +103,8 @@ perm = _modes[mode]['security'] perm = getattr(field, perm, None) +method__roles__ = getattr(klass, '%s__roles__' % methodName, 0) + # Check copied from SecurityInfo to avoid stomping over # existing permissions. if security.names.get(methodName, perm) != perm: @@ -112,6 +114,10 @@ 'permission declared is the correct one and ' 'has preference over the permission declared ' 'on the field.' % methodName) +elif method__roles__ is None: +security.declarePublic(methodName) +elif method__roles__ == (): +security.declarePrivate(methodName) else: security.declareProtected(perm, methodName) jens ___ Zope-Dev maillist - Zope-Dev@zope.org http://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - http://mail.zope.org/mailman/listinfo/zope-announce http://mail.zope.org/mailman/listinfo/zope )
[Zope-dev] Re: Strange security issue with Zope 2.8.1
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/class_init.py 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() security.declareProtected(...) def foo(): ... InitializeClass(C) then later on: security = ClassSecurityInfo() C.security = security security.declareProtected(...) C.newmethod = something InitializeClass(C) Anyway that's what I do. I never relied on a preexisting C.security. Florent -- Florent Guillaume, Nuxeo (Paris, France) CTO, Director of RD +33 1 40 33 71 59 http://nuxeo.com [EMAIL PROTECTED] ___ Zope-Dev maillist - Zope-Dev@zope.org http://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - http://mail.zope.org/mailman/listinfo/zope-announce http://mail.zope.org/mailman/listinfo/zope )