[Zope3-checkins] SVN: Zope3/trunk/src/zope/ Merged from ZopeX3-3.0 branch:

Jim Fulton jim at zope.com
Fri Aug 27 20:59:05 EDT 2004


Log message for revision 27322:
  Merged from ZopeX3-3.0 branch:
  
    r27321 | jim | 2004-08-27 20:43:53 -0400 (Fri, 27 Aug 2004) | 2 lines
  
    Changed to import removeSecurityProxy from zope.security.proxy
  
    ------------------------------------------------------------------------
    r27320 | jim | 2004-08-27 20:43:51 -0400 (Fri, 27 Aug 2004) | 4 lines
  
    Changed so that removeAllProxies is no-longer needed.
  
    Updated README.txt to test handling of faults.
  
    ------------------------------------------------------------------------
    r27319 | jim | 2004-08-27 20:43:49 -0400 (Fri, 27 Aug 2004) | 3 lines
  
    Removed unneeded removeAllProxies call. I'm pretty sure it was
    unneeded. No tests failed. ;)
  
    ------------------------------------------------------------------------
    r27318 | jim | 2004-08-27 20:43:48 -0400 (Fri, 27 Aug 2004) | 2 lines
  
    Moved the proxy-aware isinstance to zope.security.proxy
  
  


Changed:
  U   Zope3/trunk/src/zope/app/apidoc/classmodule/browser.py
  U   Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py
  U   Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py
  U   Zope3/trunk/src/zope/app/apidoc/utilities.py
  U   Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py
  U   Zope3/trunk/src/zope/app/i18n/xmlrpc/methods.py
  U   Zope3/trunk/src/zope/app/publisher/xmlrpc/README.txt
  U   Zope3/trunk/src/zope/app/publisher/xmlrpc/configure.zcml
  U   Zope3/trunk/src/zope/app/zapi/__init__.py
  D   Zope3/trunk/src/zope/app/zapi/tests.py
  A   Zope3/trunk/src/zope/publisher/tests/test_xmlrpc.py
  U   Zope3/trunk/src/zope/publisher/xmlrpc.py
  U   Zope3/trunk/src/zope/security/proxy.py
  U   Zope3/trunk/src/zope/security/tests/test_proxy.py


-=-
Modified: Zope3/trunk/src/zope/app/apidoc/classmodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/apidoc/classmodule/browser.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -31,6 +31,7 @@
 from zope.interface.interface import InterfaceClass
 from zope.proxy import removeAllProxies
 from zope.schema import getFieldsInOrder
+from zope.security.proxy import removeSecurityProxy
 
 import zope.app
 from zope.app import zapi
@@ -134,7 +135,7 @@
         self.request = request
         # TODO: This is not the best way to do this. We really need to revisit
         # the entire implementation and move more to the ZCMLFile object.
-        package = zapi.removeSecurityProxy(
+        package = removeSecurityProxy(
             zapi.getParent(context))._Module__module
         # Keep track of the package that is used for relative paths
         self._package_stack = [package]
@@ -557,7 +558,7 @@
             # we have to remove the security wrapper to get to the API calls. 
             checker = self.context.getSecurityChecker()
             entry.update(
-                getPermissionIds(name, zapi.removeSecurityProxy(checker)))
+                getPermissionIds(name, removeSecurityProxy(checker)))
             attrs.append(entry)
         return attrs
 
@@ -597,7 +598,7 @@
         #
         # `getPermissionIds()` also expects the class's security checker not
         # to be proxied.
-        klass = zapi.removeSecurityProxy(self.context)
+        klass = removeSecurityProxy(self.context)
         for name, attr, iface in klass.getMethods():
             entry = {'name': name,
                      'signature': getFunctionSignature(attr),
@@ -719,7 +720,7 @@
         crumbs = []
         module = self.context
         # I really need the class here, so remove the proxy.
-        while zapi.removeSecurityProxy(module).__class__ is Module:
+        while removeSecurityProxy(module).__class__ is Module:
             crumbs.append(
                 {'name': zapi.name(module),
                  'url': zapi.getView(module, 'absolute_url', self.request)()}

Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -23,6 +23,7 @@
 from zope.interface.interfaces import IMethod, IInterface 
 from zope.proxy import removeAllProxies
 from zope.schema.interfaces import IField
+from zope.security.proxy import removeSecurityProxy
 
 from zope.app import zapi
 from zope.app.i18n import ZopeMessageIDFactory as _
@@ -233,20 +234,20 @@
         return zapi.name(self.context)
 
     def getDoc(self):
-        """Return the main documentation string of the interface.
+        r"""Return the main documentation string of the interface.
 
         Example::
 
           >>> from tests import getInterfaceDetails
           >>> details = getInterfaceDetails()
-          >>> details.getDoc()[:34]
-          '<h1>This is the Foo interface</h1>'
+          >>> details.getDoc()[:55]
+          '<div class="document">\n<p>This is the Foo interface</p>'
         """
         # We must remove all proxies here, so that we get the context's
         # __module__ attribute. If we only remove security proxies, the
         # location proxy's module will be returned.
         return renderText(self.context.__doc__,
-                          removeAllProxies(self.context).__module__)
+                          removeSecurityProxy(self.context).__module__)
 
     def getBases(self):
         """Get all bases of this class
@@ -431,7 +432,7 @@
         service = zapi.getService('Adapters')
         # Must remove security proxies, so that we have access to the API
         # methods. 
-        iface = zapi.removeSecurityProxy(self.context)
+        iface = removeSecurityProxy(self.context)
         adapters = []
         for reg in service.registrations():
             # Only grab the adapters for which this interface is required

Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -22,6 +22,7 @@
 __docformat__ = 'restructuredtext'
 
 from zope.interface import implements
+from zope.security.proxy import removeSecurityProxy
 
 from zope.app import zapi
 from zope.app.location.interfaces import ILocation
@@ -113,7 +114,7 @@
     def getChildObjects(self):
         """See zope.app.tree.interfaces.IChildObject"""
         objects = {}
-        names = zapi.removeSecurityProxy(self.context.keys())
+        names = removeSecurityProxy(self.context.keys())
         names.sort()
         for name in names:
             # Split these long names and make part of the module path separate

Modified: Zope3/trunk/src/zope/app/apidoc/utilities.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilities.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/apidoc/utilities.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -28,6 +28,7 @@
 from zope.publisher.browser import TestRequest
 from zope.security.checker import getCheckerForInstancesOf, Global
 from zope.security.interfaces import INameBasedChecker
+from zope.security.proxy import removeSecurityProxy
 
 from zope.app import zapi
 from zope.app.i18n import ZopeMessageIDFactory as _
@@ -157,7 +158,7 @@
     # Even for methods `im_class` and `__module__` is not allowed to be
     # accessed (which is probably not a bad idea). So, we remove the security
     # proxies for this check.
-    naked = zapi.removeSecurityProxy(obj)
+    naked = removeSecurityProxy(obj)
     if hasattr(naked, "im_class"):
         naked = naked.im_class
     module = naked.__module__

Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -18,6 +18,7 @@
 __docformat__ = 'restructuredtext'
 
 from zope.configuration.xmlconfig import ParserInfo
+from zope.security.proxy import removeSecurityProxy
 
 from zope.app import zapi
 from zope.app.location import LocationProxy
@@ -167,7 +168,7 @@
         # ZCML directive `info` objects do not have security declarations, so
         # everything is forbidden by default. We need to remove the security
         # proxies in order to get to the data.  
-        info = zapi.removeSecurityProxy(self.context.info)
+        info = removeSecurityProxy(self.context.info)
         if zapi.isinstance(info, ParserInfo):
             return {'file': relativizePath(info.file),
                     'line': info.line,

Modified: Zope3/trunk/src/zope/app/i18n/xmlrpc/methods.py
===================================================================
--- Zope3/trunk/src/zope/app/i18n/xmlrpc/methods.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/i18n/xmlrpc/methods.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -17,10 +17,8 @@
 """
 __docformat__ = 'restructuredtext'
 
-from zope.proxy import removeAllProxies
 from zope.app.publisher.xmlrpc import XMLRPCView
 
-
 class Methods(XMLRPCView):
 
     def getAllLanguages(self):
@@ -30,6 +28,6 @@
         messages = []
         for msg in self.context.getMessages():
             if msg['language'] in languages:
-                messages.append(removeAllProxies(msg))
+                messages.append(msg)
 
         return messages

Modified: Zope3/trunk/src/zope/app/publisher/xmlrpc/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/publisher/xmlrpc/README.txt	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/publisher/xmlrpc/README.txt	2004-08-28 00:59:04 UTC (rev 27322)
@@ -1,6 +1,9 @@
 XML-RPC views
 =============
 
+XML-RPC Methods
+---------------
+
 There are two ways to write XML-RPV views. You can write views that
 provide "methods" for other objects, and you can write views that have
 their own methods.  Let's look at the former case first, since it's a
@@ -45,8 +48,7 @@
   ... Content-Length: 73
   ... Content-Type: application/x-www-form-urlencoded
   ... 
-  ... type_name=zope.app.browser.add.zope.app.folder.folder.Folder&new_value=f1"""
-  ... , handle_errors=False)
+  ... type_name=zope.app.browser.add.zope.app.folder.folder.Folder&new_value=f1""")
   HTTP/1.1 303 See Other
   ...
 
@@ -123,6 +125,8 @@
   </methodResponse>
   <BLANKLINE>
 
+Named XM-RPC Views
+------------------
 
 Now let's look at views that have their own methods or other
 subobjects.  Views that have their own methods have names that appear
@@ -194,7 +198,7 @@
   ... <params>
   ... </params>
   ... </methodCall>
-  ... """, handle_errors=False)
+  ... """)
   HTTP/1.0 200 Ok
   Content-Length: 208
   Content-Type: text/xml;charset=utf-8
@@ -240,3 +244,78 @@
   </params>
   </methodResponse>
   <BLANKLINE>
+
+Faults
+------
+
+If you need to raise an error, the prefered way to do it is via an
+`xmlrpclib.Fault`:
+
+  >>> import xmlrpclib
+
+  >>> class FaultDemo:
+  ...     def __init__(self, context, request):
+  ...         self.context = context
+  ...         self.request = request
+  ...
+  ...     def your_fault(self):
+  ...         return xmlrpclib.Fault(42, "It's your fault!")
+
+Now we'll register it as a view:
+
+  >>> from zope.configuration import xmlconfig
+  >>> ignored = xmlconfig.string("""
+  ... <configure 
+  ...     xmlns="http://namespaces.zope.org/zope"
+  ...     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
+  ...     >
+  ...   <!-- We only need to do this include in this example, 
+  ...        Normally the include has already been done for us. -->
+  ...   <include package="zope.app.publisher.xmlrpc" file="meta.zcml" />
+  ...
+  ...   <xmlrpc:view
+  ...       for="zope.app.folder.folder.IFolder"
+  ...       methods="your_fault"
+  ...       class="zope.app.publisher.xmlrpc.README.FaultDemo"
+  ...       permission="zope.ManageContent"
+  ...       />
+  ... </configure>
+  ... """)
+
+Now, when we call it, we get a proper XML-RPC fault:
+
+  >>> print http(r"""
+  ... POST / HTTP/1.0
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 104
+  ... Content-Type: text/xml
+  ... 
+  ... <?xml version='1.0'?>
+  ... <methodCall>
+  ... <methodName>your_fault</methodName>
+  ... <params>
+  ... </params>
+  ... </methodCall>
+  ... """, handle_errors=False)
+  HTTP/1.0 200 Ok
+  Content-Length: 272
+  Content-Type: text/xml;charset=utf-8
+  <BLANKLINE>
+  <?xml version='1.0'?>
+  <methodResponse>
+  <fault>
+  <value><struct>
+  <member>
+  <name>faultCode</name>
+  <value><int>42</int></value>
+  </member>
+  <member>
+  <name>faultString</name>
+  <value><string>It's your fault!</string></value>
+  </member>
+  </struct></value>
+  </fault>
+  </methodResponse>
+  <BLANKLINE>
+
+

Modified: Zope3/trunk/src/zope/app/publisher/xmlrpc/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/publisher/xmlrpc/configure.zcml	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/publisher/xmlrpc/configure.zcml	2004-08-28 00:59:04 UTC (rev 27322)
@@ -3,6 +3,10 @@
     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
     >
 
+  <class class="xmlrpclib.Fault">
+    <require permission="zope.Public" attributes="faultCode faultString" />
+  </class>
+
   <view 
       for="zope.interface.Interface"
       type="zope.publisher.interfaces.xmlrpc.IXMLRPCRequest"

Modified: Zope3/trunk/src/zope/app/zapi/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/zapi/__init__.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/zapi/__init__.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -21,7 +21,7 @@
 from interfaces import IZAPI
 from zope.interface import moduleProvides
 
-from zope.security.proxy import removeSecurityProxy
+from zope.security.proxy import isinstance
 
 from zope.app import servicenames
 from zope.app.interface import queryType
@@ -36,38 +36,3 @@
 from zope.app.exception.interfaces import UserError
 
 name = getName
-
-builtin_isinstance = isinstance
-def isinstance(object, cls):
-    """Test whether an object is an instance of a type.
-
-    This works even if the object is security proxied:
-
-      >>> class C1(object):
-      ...     pass
-
-      >>> c = C1()
-      >>> isinstance(c, C1)
-      True
-
-      >>> from zope.security.checker import ProxyFactory
-      >>> isinstance(ProxyFactory(c), C1)
-      True
-
-      >>> class C2(C1):
-      ...     pass
-
-      >>> c = C2()
-      >>> isinstance(c, C1)
-      True
-
-      >>> from zope.security.checker import ProxyFactory
-      >>> isinstance(ProxyFactory(c), C1)
-      True
-      
-    """
-
-    # The removeSecurityProxy call is OK here because it is *only*
-    # being used for isinstance
-    
-    return builtin_isinstance(removeSecurityProxy(object), cls)

Deleted: Zope3/trunk/src/zope/app/zapi/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/zapi/tests.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/app/zapi/tests.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -1,28 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Test zapi-provided implementation
-
-$Id$
-"""
-import unittest
-from zope.testing.doctestunit import DocTestSuite
-
-def test_suite():
-    return unittest.TestSuite((
-        DocTestSuite('zope.app.zapi.__init__'),
-        ))
-
-if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')
-

Copied: Zope3/trunk/src/zope/publisher/tests/test_xmlrpc.py (from rev 27321, Zope3/branches/ZopeX3-3.0/src/zope/publisher/tests/test_xmlrpc.py)


Property changes on: Zope3/trunk/src/zope/publisher/tests/test_xmlrpc.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: Zope3/trunk/src/zope/publisher/xmlrpc.py
===================================================================
--- Zope3/trunk/src/zope/publisher/xmlrpc.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/publisher/xmlrpc.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -26,8 +26,9 @@
 from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
 
 from zope.publisher.http import HTTPRequest, HTTPResponse
-from zope.proxy import removeAllProxies
 
+from zope.security.proxy import isinstance
+
 class XMLRPCRequest(HTTPRequest):
     implements(IXMLRPCRequest)
 
@@ -93,18 +94,17 @@
         If is_error is true then the HTML will be formatted as a Zope error
         message instead of a generic HTML page.
         """
-        body = removeAllProxies(body)
+        body = premarshal(body)
         if isinstance(body, xmlrpclib.Fault):
             # Convert Fault object to XML-RPC response.
-            body = xmlrpclib.dumps(body, methodresponse=1)
+            body = xmlrpclib.dumps(body, methodresponse=True)
         else:
             # Marshall our body as an XML-RPC response. Strings will be sent
             # strings, integers as integers, etc. We do *not* convert
             # everything to a string first.
-            if body is None:
-                body = xmlrpclib.False # Argh, XML-RPC doesn't handle null
             try:
-                body = xmlrpclib.dumps((body,), methodresponse=1)
+                body = xmlrpclib.dumps((body,), methodresponse=True,
+                                       allow_none=True)
             except:
                 # We really want to catch all exceptions at this point!
                 self.handleException(sys.exc_info())
@@ -143,3 +143,83 @@
         # Do the damage.
         self.setBody(fault_text)
         self.setStatus(200)
+
+
+def premarshal_dict(data):
+    return dict([(premarshal(k), premarshal(v))
+                 for (k, v) in data.items()])
+
+def premarshal_list(data):
+    return map(premarshal, data)
+
+def premarshal_fault(data):
+    return xmlrpclib.Fault(
+        premarshal(data.faultCode),
+        premarshal(data.faultString),
+        )
+
+premarshal_dispatch_table = {
+    dict: premarshal_dict,
+    list: premarshal_list,
+    tuple: premarshal_list,
+    xmlrpclib.Fault: premarshal_fault,
+    }
+premarshal_dispatch = premarshal_dispatch_table.get
+
+def premarshal(data):
+    """Premarshal data before handing it to xmlrpclib for marhalling
+
+    The initial putpuse of this function is to remove security proxies
+    without resorting to removeSecurityProxy.   This way, we can avoid
+    inadvertently providing access to data that should be protected.
+
+    Suppose we have a sample data structure:
+
+      >>> sample = {'foo': (1, ['x', 'y', 1.2])}
+
+    if we put the sample in a security procy:
+
+      >>> from zope.security.checker import ProxyFactory
+      >>> proxied_sample = ProxyFactory(sample)
+
+    We can still get to the data, but the non-rock data is proxied:
+
+      >>> from zope.security.proxy import Proxy
+      >>> proxied_sample['foo']
+      (1, ['x', 'y', 1.2])
+      
+      >>> type(proxied_sample['foo']) is Proxy
+      True
+      >>> type(proxied_sample['foo'][1]) is Proxy
+      True
+
+    But we can strip the proxies using premarshal:
+
+      >>> stripped = premarshal(proxied_sample)
+      >>> stripped
+      {'foo': [1, ['x', 'y', 1.2]]}
+
+      >>> type(stripped['foo']) is Proxy
+      False
+      >>> type(stripped['foo'][1]) is Proxy
+      False
+
+    So xmlrpclib will be happy. :)
+
+    We can also use premarshal to strip proxies off of Fault objects.
+    We have to make a security declaration first though:
+
+      >>> from zope.security.checker import NamesChecker, defineChecker
+      >>> defineChecker(xmlrpclib.Fault,
+      ...               NamesChecker(['faultCode', 'faultString']))
+    
+      >>> fault = xmlrpclib.Fault(1, 'waaa')
+      >>> proxied_fault = ProxyFactory(fault)
+      >>> stripped_fault = premarshal(proxied_fault)
+      >>> type(stripped_fault) is Proxy
+      False
+    """
+    premarshaller = premarshal_dispatch(data.__class__)
+    if premarshaller is not None:
+        return premarshaller(data)
+    return data

Modified: Zope3/trunk/src/zope/security/proxy.py
===================================================================
--- Zope3/trunk/src/zope/security/proxy.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/security/proxy.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -54,3 +54,39 @@
     items = checker.get_permissions.items()
     items.sort()
     return items
+
+
+builtin_isinstance = isinstance
+def isinstance(object, cls):
+    """Test whether an object is an instance of a type.
+
+    This works even if the object is security proxied:
+
+      >>> class C1(object):
+      ...     pass
+
+      >>> c = C1()
+      >>> isinstance(c, C1)
+      True
+
+      >>> from zope.security.checker import ProxyFactory
+      >>> isinstance(ProxyFactory(c), C1)
+      True
+
+      >>> class C2(C1):
+      ...     pass
+
+      >>> c = C2()
+      >>> isinstance(c, C1)
+      True
+
+      >>> from zope.security.checker import ProxyFactory
+      >>> isinstance(ProxyFactory(c), C1)
+      True
+      
+    """
+
+    # The removeSecurityProxy call is OK here because it is *only*
+    # being used for isinstance
+    
+    return builtin_isinstance(removeSecurityProxy(object), cls)

Modified: Zope3/trunk/src/zope/security/tests/test_proxy.py
===================================================================
--- Zope3/trunk/src/zope/security/tests/test_proxy.py	2004-08-28 00:43:53 UTC (rev 27321)
+++ Zope3/trunk/src/zope/security/tests/test_proxy.py	2004-08-28 00:59:04 UTC (rev 27322)
@@ -436,6 +436,7 @@
     suite = unittest.makeSuite(ProxyTests)
     from doctest import DocTestSuite
     suite.addTest(DocTestSuite())
+    suite.addTest(DocTestSuite('zope.security.proxy'))
     return suite
 
 if __name__=='__main__':



More information about the Zope3-Checkins mailing list