PageTemplateFile vs. Bindings vs. Security
So... remember way back when Brian warned about the binding breakage due to the improved security checks? It just bit me in a way I didn't forsee. I forgot that PageTemplates use bindings too, which means those changes affect more than just PythonScripts they affect Products that use PageTemplateFile methods. My product had declared its object instances to be private, and in doing so it totally breaks the ability to use PageTemplateFile methods. This sucks. Using DTML for product methods goes against the fiber of my being, I just can't bring myself to do it; the namespace pollution as programing paradigm is so frustrating it just makes me want to throw things. But DTMLFile has a huge advantage ... it does the Right Thing with respect to Zope security. It ignores it completely. Paradoxically, by ignoring Zope's security framework in the context of on-disk methods this actually improves Zope's overall security. It allows you to fully take advantage of the API seperation available to Products. To briefly enumerate, you've got 3 basic types of methods: def _python_only_methods(): """docstring doesn't "matter" as this can't be published or accessed TTW, security declarations are superfluous, can't be accessed by RestrictedPython either""" def python_or_RestrictedPython_methods(): # no docstring ensures its not publishable, security declarations # are necessary to dictate RestrictedPython's privileges pass def publishable_python_or_RestrictedPython_methods(): """docstring dictates publishablility, security declarations are necessary and dictate both RestrictedPython's privileges and TTW privileges""" Now DTMLFile does its work with the privileges of "python" code, which is great because it means you can define methods which generate content fragments without any restrictions on what APIs it can and can't use. This is useful--more on why in a sec. Conversely the PageTemplateFile does it work with the privileges of "RestrictedPython" code, which might seem great at first, ("More security? What can possibly be bad about that?!") but rapidly wears thin when you try to use PageTemplateFiles in API code, and screws Product authors who were trying to write secure code. To illustrate the first point where PageTemplateFile forces a weakened API, consider the case of Tabs.manage_tabs() ... this method must be declared *public* so that Products using PageTemplateFile can access it. The caller's security context is taken into account with PageTemplateFiles and as 2 different products using PageTemplateFile methods might require completely different permissions to access the method which in turn relies upon Tabs.manage_tabs() the only way to satisfy all possible permission combinations is to just give up and declare the method public so it always succeeds. Products using DTMLFile OTOH don't care, it could be totally private, as it *should* be, and DTMLFile methods would still be able to call it and use the results to display content without regards to callers security context, this makes DTMLFiles useful because you can maintain the integrity of your API and not expose stuff to RestrictedPython that true RestrictedPython has no business calling. If only DTML wasn't such a horrible, syntactically braindamaged, stack-bound HELL to work with! But DTML is hell, and thats not going to change, its better to focus energies on the future which is ZPT, and I assert that PageTemplateFile behavior needs to change. Back to the second point, that the current behavior screws Product authors trying to write secure code. My product called security.declareObjectPrivate() because this is the only way I know of to ensure a product and its attributes are safe from tampering, and until the Binding changes, I thought this was a great deal. Now that the hole in bindings have been fixed though it turns out that because my product uses PageTemplateFile methods which in turn pay attention to bindings, and, unfortunately, pay attention to the callers security context as well, none of those methods work anymore, they raise Unauthorized: Not authorized to access binding: container I can fix this by changing my object security declaration to be public or restricted to a permission, but that has side effects that I don't want, namely opening my object instances up to tampering from within RestrictedPython given the appropriate security context. Given that my need to have the object instance completely private and my desire to avoid DTML are now in direct conflict I'm basically forced to choose between a range of compromises and I don't like any of them. So here's the questions I have for you all... is there a way to declare appropriate security on the bindings that are screwing me right now from within my product code so that I can selectively poke holes to allow container access where needed, or am I to be forcibly coerced into exposing my object to restricted code? And two, assuming I haven't overlooked some detail about why forcing PageTemplateFile to work within the calling security context is a good thing... Shouldn't we fix PageTemplateFile to work like DTMLFile wrt security? How hard is it going to be to do that? -- Jamie Heilman http://audible.transient.net/~jamie/ "...thats the metaphorical equivalent of flopping your wedding tackle into a lion's mouth and flicking his lovespuds with a wet towel, pure insanity..." -Rimmer
Jamie Heilman wrote at 2004-3-22 16:42 -0800:
... So here's the questions I have for you all... is there a way to declare appropriate security on the bindings that are screwing me right now from within my product code so that I can selectively poke holes to allow container access where needed,
One approach (hopefully quite near to your wishes) looks like: Protect your object by a role, say "Manager". This looks like "__roles__ = ('Manager',)" Give your "PageTemplateFile" the "Manager" proxy role: "_proxy_roles = ('Manager',)" Make your "PageTemplateFile" unowned: "_owner = None". Instead of "Manager", you can use another role that you do not assign any permissions. Alternative: An incredibly long time ago, Evan published a product "XXXPythonScripts". These are "PythonScripts" without security checks. Looking at the differences between these two products may show what is needed to get security unaware "PageTemplateFiles". -- Dieter
Jamie Heilman wrote:
Paradoxically, by ignoring Zope's security framework in the context of on-disk methods this actually improves Zope's overall security.
I can see that. It's interesting that when security is burdensome, it is often less secure overall as a result. I see this pattern everywhere.
So here's the questions I have for you all... is there a way to declare appropriate security on the bindings that are screwing me right now from within my product code so that I can selectively poke holes to allow container access where needed, or am I to be forcibly coerced into exposing my object to restricted code? And two, assuming I haven't overlooked some detail about why forcing PageTemplateFile to work within the calling security context is a good thing... Shouldn't we fix PageTemplateFile to work like DTMLFile wrt security? How hard is it going to be to do that?
There certainly ought to be a way to create an unrestricted PageTemplateFile, though it should be an explicit step. To do this, I would change Products/PageTemplates/Expressions.py. It creates an expression evaluation engine and adds expression types to it. It chooses the unrestricted or the restricted expression types based on whether the "Zope" module exists. This is a wart. Instead, I think it should create two engines, one restricted and one unrestricted. Then you should be able to tell the PageTemplateFile constructor which engine to use. Shane
Shane Hathaway wrote:
To do this, I would change Products/PageTemplates/Expressions.py. It creates an expression evaluation engine and adds expression types to it. It chooses the unrestricted or the restricted expression types based on whether the "Zope" module exists. This is a wart. Instead, I think it should create two engines, one restricted and one unrestricted. Then you should be able to tell the PageTemplateFile constructor which engine to use.
That sounds mighty handy. What needs to happen for that to happen? Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
On Wed, 24 Mar 2004, Chris Withers wrote:
Shane Hathaway wrote:
To do this, I would change Products/PageTemplates/Expressions.py. It creates an expression evaluation engine and adds expression types to it. It chooses the unrestricted or the restricted expression types based on whether the "Zope" module exists. This is a wart. Instead, I think it should create two engines, one restricted and one unrestricted. Then you should be able to tell the PageTemplateFile constructor which engine to use.
That sounds mighty handy. What needs to happen for that to happen?
A voluntary volunteer needs to volunteer voluntarily. Shane
Shane Hathaway wrote:
On Wed, 24 Mar 2004, Chris Withers wrote:
That sounds mighty handy. What needs to happen for that to happen?
A voluntary volunteer needs to volunteer voluntarily.
I'll probably tackle it, but not before next month due to more immediate fires. -- Jamie Heilman http://audible.transient.net/~jamie/ "I was in love once -- a Sinclair ZX-81. People said, "No, Holly, she's not for you." She was cheap, she was stupid and she wouldn't load -- well, not for me, anyway." -Holly
Shane Hathaway wrote:
That sounds mighty handy. What needs to happen for that to happen?
A voluntary volunteer needs to volunteer voluntarily.
I think I was offering to be such a person. So, what would such a person need to do? Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Shane Hathaway wrote:
There certainly ought to be a way to create an unrestricted PageTemplateFile, though it should be an explicit step.
That is a good suggestion. I'd like that option. It would also be a potential performance benefit. On the other hand, in situations where the PageTemplate designers are *not* security conscious (they're designers, not primarily programmers) the option of explicit checks is useful. Regards, Martijn
Martijn Faassen wrote:
Shane Hathaway wrote:
There certainly ought to be a way to create an unrestricted PageTemplateFile, though it should be an explicit step.
That is a good suggestion. I'd like that option. It would also be a potential performance benefit.
On the other hand, in situations where the PageTemplate designers are *not* security conscious (they're designers, not primarily programmers) the option of explicit checks is useful.
PageTemplateFile is a class used by Product authors, just like DTMLFile. If you can write a product, you are either security conscious or your product is worthless. -- Jamie Heilman http://audible.transient.net/~jamie/ "I was in love once -- a Sinclair ZX-81. People said, "No, Holly, she's not for you." She was cheap, she was stupid and she wouldn't load -- well, not for me, anyway." -Holly
Jamie Heilman wrote:
Martijn Faassen wrote:
On the other hand, in situations where the PageTemplate designers are *not* security conscious (they're designers, not primarily programmers) the option of explicit checks is useful.
PageTemplateFile is a class used by Product authors, just like DTMLFile. If you can write a product, you are either security conscious or your product is worthless.
exactly. let's not design technical solutions to non-technical problems. These kind of tools (ie Zope and Zope products) should be versatile, and constraints on their usage should come from best practices anc conscient knowledge and not from the way the tools are implemented. /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
Dario Lopez-Kästen wrote:
Jamie Heilman wrote:
Martijn Faassen wrote:
On the other hand, in situations where the PageTemplate designers are *not* security conscious (they're designers, not primarily programmers) the option of explicit checks is useful.
PageTemplateFile is a class used by Product authors, just like DTMLFile. If you can write a product, you are either security conscious or your product is worthless.
exactly. let's not design technical solutions to non-technical problems.
If a technical solution indeed exists to a non-technical problem, let's by all means use it to solve it. As then we can forget about it. :) Reality is of course more subtle, as in this case the technical solution (no need to worry about page template security declarations at all) causes increased complexity in some cases.
These kind of tools (ie Zope and Zope products) should be versatile, and constraints on their usage should come from best practices anc conscient knowledge and not from the way the tools are implemented.
I'm advocating an explicit option to disable security checks here. I'm just also advocating that the current behavior can be sensible in certain circumstances. This is the only backwards compatible way anyway. Anyway, I disagree on the general philosophical point that it is undesirable to have tool or framework support for various best practices and experience. Regards, Martijn
Martijn Faassen wrote:
I'm advocating an explicit option to disable security checks here. I'm just also advocating that the current behavior can be sensible in certain circumstances. This is the only backwards compatible way anyway.
+1
Anyway, I disagree on the general philosophical point that it is undesirable to have tool or framework support for various best practices and experience.
Well, basicalle my point boils down to "if not broken: pass". Potentially dangeraous breakness in an extreme use case where the solution really is to avoid the use case alltoghether does not motivate a technical solution to that particular case - YMMV. I am not sure we disagree, though I might add that I am not at all for tools that overdo the "we need to protect the developer as if they were end users" way of thinking and implements the tools like that. Tools should be verstile and not too clever in "helping" the user (user=developer in this case) - I react instinctively to those tools like I react when MS Word tries to "Help" :-) /dario -- -- ------------------------------------------------------------------- Dario Lopez-Kästen, IT Systems & Services Chalmers University of Tech.
Jamie Heilman wrote:
Martijn Faassen wrote:
Shane Hathaway wrote:
There certainly ought to be a way to create an unrestricted PageTemplateFile, though it should be an explicit step.
That is a good suggestion. I'd like that option. It would also be a potential performance benefit.
On the other hand, in situations where the PageTemplate designers are *not* security conscious (they're designers, not primarily programmers) the option of explicit checks is useful.
PageTemplateFile is a class used by Product authors, just like DTMLFile. If you can write a product, you are either security conscious or your product is worthless.
I don't always write products by myself. I work in a larger team which may include some people who are very good at making beautiful HTML and can get a page template to work, but aren't Python developers and can't be expected to be experts on Zope security. In such situations it can be a good idea that security checks against the underlying API take place, though of course other forms of collarboration are possible where this need does not exist. Regards, Martijn
participants (6)
-
Chris Withers -
Dario Lopez-Kästen -
Dieter Maurer -
Jamie Heilman -
Martijn Faassen -
Shane Hathaway