[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/apidoc/c * Fixed
security hole by disabling automatic import of paths when a
Stephan Richter
srichter at cosmos.phy.tufts.edu
Sat Jun 18 09:25:59 EDT 2005
Log message for revision 30838:
* Fixed security hole by disabling automatic import of paths when a
module is not available in ``sys.modules`` by default. It can be
activated using::
<apidoc:moduleImport allow="true" />
Changed:
U Zope3/trunk/src/zope/app/apidoc/classregistry.py
U Zope3/trunk/src/zope/app/apidoc/classregistry.txt
D Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt
A Zope3/trunk/src/zope/app/apidoc/codemodule/directives.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/meta.zcml
U Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/metadirectives.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py
-=-
Modified: Zope3/trunk/src/zope/app/apidoc/classregistry.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classregistry.py 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/classregistry.py 2005-06-18 13:25:59 UTC (rev 30838)
@@ -16,6 +16,9 @@
$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
"""
__docformat__ = 'restructuredtext'
+
+__import_unknown_modules__ = False
+
import sys
from zope.app import zapi
@@ -52,7 +55,7 @@
def safe_import(path, default=None):
"""Import a given path as efficiently as possible and without failure."""
module = sys.modules.get(path, default)
- if module is default:
+ if module is default and __import_unknown_modules__:
try:
module = __import__(path, {}, {}, ('*',))
except ImportError:
Modified: Zope3/trunk/src/zope/app/apidoc/classregistry.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classregistry.txt 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/classregistry.txt 2005-06-18 13:25:59 UTC (rev 30838)
@@ -4,8 +4,8 @@
This little registry allows us to quickly query a complete list of classes
that are defined and used by Zope 3. The prime feature of the class is the
-'getClassesThatImplement(iface)' method that returns all classes that
-implement the passed interface. Another method, 'getSubclassesOf(klass)'
+``getClassesThatImplement(iface)`` method that returns all classes that
+implement the passed interface. Another method, ``getSubclassesOf(klass)``
returns all registered subclassess of the given class.
The class registry, subclassing the dictionary type, can be instantiated like
@@ -96,14 +96,17 @@
Safe Imports
------------
-Using the `safe_import()` we can quickly look up modules by minimizing import
-calls.
+Using the ``safe_import()`` we can quickly look up modules by minimizing
+import calls.
+ >>> from zope.app.apidoc import classregistry
>>> from zope.app.apidoc.classregistry import safe_import
-First we try to find the path in 'sys.modules', since this lookup is much
+First we try to find the path in ``sys.modules``, since this lookup is much
more efficient than importing it. If it was not found, we go back and try
-to import the path. If that also fails, we return the 'default' value.
+to import the path. For security reasons, importing new modules is disabled by
+default, unless the global ``__import_unknown_modules__`` variable is set to
+true. If that also fails, we return the `default` value.
Here are some examples::
@@ -126,12 +129,23 @@
>>> f.write('# dummy module\n')
>>> f.close()
-The temporary module is not already imported, but will be once
-we've called safe_import():
+The temporary module is not already imported:
>>> module_name = 'zope.app.apidoc.testmodule'
>>> module_name in sys.modules
False
+
+When we try ``safe_import()`` now, we will still get the `default` value,
+because importing new modules is disabled by default:
+
+ >>> safe_import(module_name) is None
+ True
+
+But once we activate the ``__import_unknown_modules__`` hook, the module
+should be imported:
+
+ >>> classregistry.__import_unknown_modules__ = True
+
>>> safe_import(module_name).__name__ == module_name
True
>>> module_name in sys.modules
@@ -145,4 +159,9 @@
>>> if os.path.exists(filename + 'o'):
... os.unlink(filename + 'o')
- >>> del sys.modules['zope.app.apidoc.testmodule']
\ No newline at end of file
+ >>> del sys.modules['zope.app.apidoc.testmodule']
+
+We also need to play nice concerning variables and have to reset the module
+globals:
+
+ >>> classregistry.__import_unknown_modules__ = False
\ No newline at end of file
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt 2005-06-18 13:25:59 UTC (rev 30838)
@@ -1,34 +0,0 @@
-=================================
-The `apidoc:rootModule` Directive
-=================================
-
-The `rootModule` directive allows you to register a third party Python package
-with apidoc's code browser.
-
-Before we can register a new root module, we need to load the
-metaconfiguration:
-
- >>> from zope.configuration import xmlconfig
- >>> import zope.app.apidoc.codemodule
- >>> context = xmlconfig.file('meta.zcml', zope.app.apidoc.codemodule)
-
-Now we can run the directive. First, let's make sure that no root modules have
-been registered yet:
-
- >>> from zope.app import zapi
- >>> from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
- >>> list(zapi.getUtilitiesFor(IAPIDocRootModule))
- []
-
-Now run the registration code:
-
- >>> context = xmlconfig.string('''
- ... <configure
- ... xmlns='http://namespaces.zope.org/apidoc'>
- ... <rootModule module="zope" />
- ... </configure>''', context)
-
-and the root module is available:
-
- >>> list(zapi.getUtilitiesFor(IAPIDocRootModule))
- [(u'zope', 'zope')]
Copied: Zope3/trunk/src/zope/app/apidoc/codemodule/directives.txt (from rev 30837, Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt)
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/directives.txt 2005-06-18 13:25:59 UTC (rev 30838)
@@ -0,0 +1,78 @@
+========================================
+Code Module specific `apidoc` Directives
+========================================
+
+The `apidoc:rootModule` Directive
+---------------------------------
+
+The `rootModule` directive allows you to register a third party Python package
+with apidoc's code browser.
+
+Before we can register a new root module, we need to load the
+metaconfiguration:
+
+ >>> from zope.configuration import xmlconfig
+ >>> import zope.app.apidoc.codemodule
+ >>> context = xmlconfig.file('meta.zcml', zope.app.apidoc.codemodule)
+
+Now we can run the directive. First, let's make sure that no root modules have
+been registered yet:
+
+ >>> from zope.app import zapi
+ >>> from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
+ >>> list(zapi.getUtilitiesFor(IAPIDocRootModule))
+ []
+
+Now run the registration code:
+
+ >>> context = xmlconfig.string('''
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/apidoc">
+ ... <rootModule module="zope" />
+ ... </configure>''', context)
+
+and the root module is available:
+
+ >>> list(zapi.getUtilitiesFor(IAPIDocRootModule))
+ [(u'zope', 'zope')]
+
+
+The `apidoc:importModule` Directive
+-----------------------------------
+
+The `importModule` directive allows you to set the
+``__import_unknown_modules__`` flag of the class registry. When this flag is
+set to false, paths will only be looked up in ``sys.modules``. When set true,
+and the ``sus.modules`` lookup fails, the import function of the class
+registry tries to import the path. The hook was provided for security reasons,
+since uncontrolled importing of modules in a running application is considered
+a security hole.
+
+By default the flag is set to false:
+
+ >>> from zope.app.apidoc import classregistry
+ >>> classregistry.__import_unknown_modules__
+ False
+
+We can now use the directive to set it to true:
+
+ >>> context = xmlconfig.string('''
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/apidoc">
+ ... <moduleImport allow="true" />
+ ... </configure>''', context)
+
+ >>> classregistry.__import_unknown_modules__
+ True
+
+We can also set it back to false of course:
+
+ >>> context = xmlconfig.string('''
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/apidoc">
+ ... <moduleImport allow="false" />
+ ... </configure>''', context)
+
+ >>> classregistry.__import_unknown_modules__
+ False
+
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/meta.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/meta.zcml 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/meta.zcml 2005-06-18 13:25:59 UTC (rev 30838)
@@ -6,6 +6,12 @@
<meta:directives namespace="http://namespaces.zope.org/apidoc">
<meta:directive
+ name="moduleImport"
+ schema=".metadirectives.IModuleImport"
+ handler=".metaconfigure.moduleImport"
+ />
+
+ <meta:directive
name="rootModule"
schema=".metadirectives.IRootModule"
handler=".metaconfigure.rootModule"
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py 2005-06-18 13:25:59 UTC (rev 30838)
@@ -18,11 +18,25 @@
__docformat__ = 'restructuredtext'
from zope.interface import implements
from zope.app.component.metaconfigure import utility
+
+from zope.app.apidoc import classregistry
from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
+
class RootModule(str):
implements(IAPIDocRootModule)
def rootModule(_context, module):
"""Register a new module as a root module for the class browser."""
utility(_context, IAPIDocRootModule, RootModule(module), name=module)
+
+
+def setModuleImport(flag):
+ classregistry.__import_unknown_modules__ = flag
+
+def moduleImport(_context, allow):
+ """Set the __import_unknown_modules__ flag"""
+ return _context.action(
+ ('apidoc', '__import_unknown_modules__'),
+ setModuleImport,
+ (allow, ))
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/metadirectives.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/metadirectives.py 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/metadirectives.py 2005-06-18 13:25:59 UTC (rev 30838)
@@ -16,15 +16,26 @@
$Id: metadirectives.py 26613 2004-07-18 21:50:40Z srichter $
"""
__docformat__ = 'restructuredtext'
-from zope.interface import Interface
-from zope.schema import TextLine
+import zope.interface
+import zope.schema
-class IRootModule(Interface):
+class IRootModule(zope.interface.Interface):
"""Declares a new root module to be available for the class documentation
module."""
- module = TextLine(
+ module = zope.schema.TextLine(
title=u"Root Module Name",
description=u"This is the Python path of the new root module.",
required=True
)
+
+class IModuleImport(zope.interface.Interface):
+ """Set a flag whether new modules can be imported to the class registry or
+ not."""
+
+ allow = zope.schema.Bool(
+ title=u"Allow Importing Modules",
+ description=u"When set to true, new modules will be imported by path.",
+ required=True,
+ default=False
+ )
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py 2005-06-17 23:09:06 UTC (rev 30837)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py 2005-06-18 13:25:59 UTC (rev 30838)
@@ -49,7 +49,7 @@
setUp=setUp, tearDown=tearDown,
globs={'pprint': doctestunit.pprint},
optionflags=doctest.NORMALIZE_WHITESPACE),
- doctest.DocFileSuite('directive.txt',
+ doctest.DocFileSuite('directives.txt',
setUp=placelesssetup.setUp,
tearDown=placelesssetup.tearDown),
))
More information about the Zope3-Checkins
mailing list