Ambiguities in "Inheritance and Class Security Declaration"
After reading this section of the development guide, I have a lot of questions (pp 75-76 of the guide). 1. If a subclass redefines a base class method, does the subclass need to do a security declaration on it? The document says "You only need to make security declarations for methods .... your class actually defines. If your class inherits from other classes, the methods of the base classes are protected by the security declarations made in the base classes." The first sentence seems to indicate a security declaration is necessary (since you define the method); the second sentence suggests its not. It depends partly on the meaning of "define" and also "method" (that is, is redefinition considered definition? does method refer to a name or to a specific classes implementation of that name?). 2. Does a subclass need to have security = ClassSecurityInfo() in it if the base class does? Judging from the example, yes. 3. Under what circumstances is the declaration in 2 necessary? For example, only if new method names are introduced and protected? Or any reference to security in the subclass? It seems the latter, from the example. 4. Suppose we wanted to change the security of a base class method without otherwise redefining it. What's necessary then? 5. Under what conditions is InitializeClass necessary for the subclass when the base class has been through InitializeClass? (The guide only addresses the case when the base class has not been so processed. It also says the declarations "filter down", but the implication of this for new method is unclear.) This section has a lot of explicit discussion of odd cases (no security in superclass, redefining permissions on existing methods without changing them) and not enough about the normal cases (my subclass extends some base class methods and defines some new ones). Also, the second paragraph uses "superclass" where I hope it means subclass. Although I would appreciate and responses from the list, I would also like to send these comments to the documents authors. Unfortunately, I see no authorship or contact information in the document. Can anyone suggest some? Thanks.
Ross Boylan wrote:
After reading this section of the development guide, I have a lot of questions (pp 75-76 of the guide).
1. If a subclass redefines a base class method, does the subclass need to do a security declaration on it? The document says "You only need to make security declarations for methods .... your class actually defines. If your class inherits from other classes, the methods of the base classes are protected by the security declarations made in the base classes." The first sentence seems to indicate a security declaration is necessary (since you define the method); the second sentence suggests its not. It depends partly on the meaning of "define" and also "method" (that is, is redefinition considered definition? does method refer to a name or to a specific classes implementation of that name?).
You should have security declarations for each method you define, even if they are defined in the base class.
2. Does a subclass need to have security = ClassSecurityInfo() in it if the base class does? Judging from the example, yes.
Yes.
3. Under what circumstances is the declaration in 2 necessary? For example, only if new method names are introduced and protected? Or any reference to security in the subclass? It seems the latter, from the example.
Define security assertions for all the methods you define.
4. Suppose we wanted to change the security of a base class method without otherwise redefining it. What's necessary then?
Define a security declaration for a method without actually defining the method. Your security declaration will override those of the base class.
5. Under what conditions is InitializeClass necessary for the subclass when the base class has been through InitializeClass? (The guide only addresses the case when the base class has not been so processed. It also says the declarations "filter down", but the implication of this for new method is unclear.)
When you define new methods or when you want to override security declarations in the base class. It never hurts to run a class through InitializeClass.
This section has a lot of explicit discussion of odd cases (no security in superclass, redefining permissions on existing methods without changing them) and not enough about the normal cases (my subclass extends some base class methods and defines some new ones).
Also, the second paragraph uses "superclass" where I hope it means subclass.
These comments would be more helpful if they were made using the comment system that is in the book itself. I will unfortunately forget about this maillist message in about 10 minutes, but if they were made inline, when I went to go edit the book, there they'd be. ;-)
Although I would appreciate and responses from the list, I would also like to send these comments to the documents authors. Unfortunately, I see no authorship or contact information in the document. Can anyone suggest some?
I wrote most of it. You can ask, I may be able to answer. ;-) -- Chris McDonough Zope Corporation http://www.zope.org http://www.zope.com "Killing hundreds of birds with thousands of stones"
Chris McDonough <chrism@zope.com> wrote:
You should have security declarations for each method you define, even if they are defined in the base class.
Is that to be future-proof, or to be clean & explicit, or does the current implementation really require that ? My understanding of the code is that it's not needed currently. Florent -- Florent Guillaume, Nuxeo (Paris, France) +33 1 40 33 79 87 http://nuxeo.com mailto:fg@nuxeo.com
Let's do some investigation. This is going to be sublimely painful, I'm sure. ;-) Let's define a simple Product named SecurityTest. Its __init__.py is this: import SecurityTest from Products.Transience import Transience form = SecurityTest.constructSecurityTestForm constructor = SecurityTest.constructSecurityTest def initialize(context): context.registerClass( SecurityTest.SecurityTest, constructors=(form, constructor), ) We define a module named SecurityTest in the Product, which is initially just the following: from Products.Transience.Transience import TransientObjectContainer from Globals import HTMLFile, InitializeClass from AccessControl import ClassSecurityInfo class SecurityTest(TransientObjectContainer): meta_type = 'Security Test' constructSecurityTestForm = HTMLFile( 'dtml/addSecurityTest', globals()) def constructSecurityTest(self, id, title='', timeout_mins=20, addNotification=None, delNotification=None, limit=0, REQUEST=None): """ """ ob = SecurityTest(id, title, timeout_mins, addNotification, delNotification, limit=limit) self._setObject(id, ob) if REQUEST is not None: return self.manage_main(self, REQUEST, update_menu=1) The HTMLFile instance is just a copy of the constructTransientObjectContainer form in the Transience product modified with the right target to create a SecurityTest instance. Note that we don't run the SecurityTest class through InitializeClass, nor do we allow it to make any of its own security declarations. Then we fire up Zope, log in as the admin user and call the URL http://localhost:8080/security_test/foo/getSubobjectLimit . Note that we didn't declare any security assertions on the SecurityTest class and we didn't run the SecurityTest class through InitializeClass, and we can still view the getSubobjectLimit method, which is defined in the base class and protected by the 'View management screens' permission in the base class. So we know we don't have to run InitializeClass on a subclass of a security-aware class which doesn't override any of its superclass' methods. Let's go override the getObjectLimit method in the SecurityTest subclass. class SecurityTest(TransientObjectContainer): meta_type = 'Security Test' def getSubobjectLimit(self): """ """ return 100 When calling the same URL, we find that we can still call the getSubobjectLimit method while logged in as the admin user, even though we didn't give it any security declarations of its own (its security declaration was inherited from the base class). So we know we don't need to declare security assertions on methods of classes which inherit from base classes which have security assertions unless we want to change those assertions. So now let's go modify the base class, declaring the getSubobjectLimit method private by changing the class: #security.declareProtected(MGMT_SCREEN_PERM, 'getSubobjectLimit') security.declarePrivate('getSubobjectLimit') def getSubobjectLimit(self): """ """ return self._limit In either the case where we override the security declaration in the SecurityTest subclass or we remove the method from the subclass, we are not able to access the method any longer via its URL. So we are really, definitely, positively sure that we inherit security declarations from our base class. Then let's make our own security declaration on the getSubobjectLimit method in the subclass, but we won't run the class through InitializeClass: class SecurityTest(TransientObjectContainer): meta_type = 'Security Test' security = ClassSecurityInfo() security.declarePublic('getSubobjectLimit') def getSubobjectLimit(self): """ """ return 100 In the base class, the getSubobjectLimit method is still declared private. But we find that even though we didn't run the SecurityTest class through InitializeClass, the getSubobjectLimit method is now accessible! This leads us to believe that we needn't run InitializeClass on our subclass if one of its base classes has already been run through InitializeClass. How this security declaration gets applied to our class, I don't know. ;-) That's the job of InitializeClass, but it's apparently unnecessary in subclasses of classes that are already run through InitializeClass. Let's run the SecurityTest class through InitializeClass now: class SecurityTest(TransientObjectContainer): meta_type = 'Security Test' security = ClassSecurityInfo() security.declarePublic('getSubobectLimit') def getSubobjectLimit(self): """ """ return 100 InitializeClass(SecurityTest) This works, of course, and the method is still public. Now, lets go pare out our method declaration and our security assertions from our subclass, but we'll still run the class through InitializeClass: class SecurityTest(TransientObjectContainer): meta_type = 'Security Test' # security = ClassSecurityInfo() # security.declarePublic('getSubobjectLimit') # def getSubobjectLimit(self): # """ """ # return 100 InitializeClass(SecurityTest) We also go back and change our TransientObjectContainer base class' security declarations back to standard: security.declareProtected(MGMT_SCREEN_PERM, 'getSubobjectLimit') #security.declarePrivate('getSubobjectLimit') def getSubobjectLimit(self): """ """ return self._limit We find that we can still access getSubobjectLimit, which is what I would expect. So, the (somewhat suprising) morals of the story are: - you needn't use InitializeClass on classes which inherit from a base class which has security assertions and has itself been run through InitializeClass if a) you don't add any methods to the subclass and b) you're willing to accept the base class' security assertions. Not suprising. - You needn't declare security assertions on overriding methods of subclasses of security-aware base classes unless you want to change those assertions. Not suprising. - It's always safe to run a class through InitializeClass even if it does not have security declarations of its own. Not suprising. - If you declare differing security assertions in your subclass, you do not need to run the subclass through InitializeClass for those security assertions to have an effect. Why this is the case is still somewhat a mystery. Surprising. I'm sort of stumped as to how the subclass' assertions are applied in the absence of InitializeClass! This is not what I expected, I would have thought that differing assertions would only be applied if InitializeClass was called on the subclass. There's some magic going on here that I don't understand. But in a nutshell, if you don't want to think about any of this (and god knows I don't): - declare security assertions for each method that you define, even if there is an existing security declaration for the method in a superclass. It's always clear what the intention of your code is then, and you won't piss off any of your coworkers. ;-) - always run your classes through InitializeClass - C ----- Original Message ----- From: "Chris McDonough" <chrism@zope.com> To: "Ross Boylan" <RossBoylan@stanfordalumni.org> Cc: <zope-dev@zope.org> Sent: Friday, July 19, 2002 9:20 PM Subject: Re: [Zope-dev] Ambiguities in "Inheritance and Class Security Declaration"
Ross Boylan wrote:
After reading this section of the development guide, I have a lot of questions (pp 75-76 of the guide).
1. If a subclass redefines a base class method, does the subclass need to do a security declaration on it? The document says "You only need to make security declarations for methods .... your class actually defines. If your class inherits from other classes, the methods of the base classes are protected by the security declarations made in the base classes." The first sentence seems to indicate a security declaration is necessary (since you define the method); the second sentence suggests its not. It depends partly on the meaning of "define" and also "method" (that is, is redefinition considered definition? does method refer to a name or to a specific classes implementation of that name?).
You should have security declarations for each method you define, even if they are defined in the base class.
2. Does a subclass need to have security = ClassSecurityInfo() in it if the base class does? Judging from the example, yes.
Yes.
3. Under what circumstances is the declaration in 2 necessary? For example, only if new method names are introduced and protected? Or any reference to security in the subclass? It seems the latter, from the example.
Define security assertions for all the methods you define.
4. Suppose we wanted to change the security of a base class method without otherwise redefining it. What's necessary then?
Define a security declaration for a method without actually defining the method. Your security declaration will override those of the base class.
5. Under what conditions is InitializeClass necessary for the
subclass
when the base class has been through InitializeClass? (The guide only addresses the case when the base class has not been so processed. It also says the declarations "filter down", but the implication of this for new method is unclear.)
When you define new methods or when you want to override security declarations in the base class. It never hurts to run a class through InitializeClass.
This section has a lot of explicit discussion of odd cases (no security in superclass, redefining permissions on existing methods without changing them) and not enough about the normal cases (my subclass extends some base class methods and defines some new
ones).
Also, the second paragraph uses "superclass" where I hope it means subclass.
These comments would be more helpful if they were made using the comment system that is in the book itself. I will unfortunately forget about this maillist message in about 10 minutes, but if they were made inline, when I went to go edit the book, there they'd be. ;-)
Although I would appreciate and responses from the list, I would also like to send these comments to the documents authors. Unfortunately, I see no authorship or contact information in the document. Can anyone suggest some?
I wrote most of it. You can ask, I may be able to answer. ;-)
-- Chris McDonough Zope Corporation http://www.zope.org http://www.zope.com "Killing hundreds of birds with thousands of stones"
_______________________________________________ Zope-Dev maillist - Zope-Dev@zope.org http://lists.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - http://lists.zope.org/mailman/listinfo/zope-announce http://lists.zope.org/mailman/listinfo/zope )
Chris McDonough <chrism@zope.com> wrote:
So, the (somewhat suprising) morals of the story are:
- you needn't use InitializeClass on classes which inherit from a base class which has security assertions and has itself been run through InitializeClass if a) you don't add any methods to the subclass and b) you're willing to accept the base class' security assertions. Not suprising.
- You needn't declare security assertions on overriding methods of subclasses of security-aware base classes unless you want to change those assertions. Not suprising.
This is understandable given that the underlying implementation of security assertions is to set a getSubobjectLimit__roles__ attribute, which gets inherited by subclasses.
- It's always safe to run a class through InitializeClass even if it does not have security declarations of its own. Not suprising.
InitializeClass checks for an attribute itself having a __security_info__ attribute (security = ClassSecurityInfo() does that), interprets it (by calling security.apply(cls)), and removes it after having being done with it.
- If you declare differing security assertions in your subclass, you do not need to run the subclass through InitializeClass for those security assertions to have an effect. Why this is the case is still somewhat a mystery. Surprising.
I'm sort of stumped as to how the subclass' assertions are applied in the absence of InitializeClass! This is not what I expected, I would have thought that differing assertions would only be applied if InitializeClass was called on the subclass. There's some magic going on here that I don't understand.
The magic is that Persistent has a __class_init__ that calls InitializeClass for you. (This attribute is actually set by App.PersistentExtra, called from Globals.) __class_init__ is an ExtensionClass feature. Florent -- Florent Guillaume, Nuxeo (Paris, France) +33 1 40 33 79 87 http://nuxeo.com mailto:fg@nuxeo.com
participants (3)
-
Chris McDonough -
Florent Guillaume -
Ross Boylan