Commit 5fc71985 authored by Boxiang Sun's avatar Boxiang Sun

apply 3.0.12 implementation with some Pyston change

parent 97bc7e89
Changelog Changelog
========= =========
2.13.14 (2015-12-21) For changes before verison 3.0, see ``HISTORY.txt``.
--------------------
3.0.12 (2015-12-21)
-------------------
- Avoid acquiring ``access`` from module wrapped by - Avoid acquiring ``access`` from module wrapped by
``SecurityInfo._ModuleSecurityInfo``. See: ``SecurityInfo._ModuleSecurityInfo``. See:
https://github.com/zopefoundation/AccessControl/issues/12 https://github.com/zopefoundation/AccessControl/issues/12
2.13.13 (2013-07-16) 3.0.11 (2014-11-02)
-------------------- -------------------
- LP #1169923: ensure initialization of shared ``ImplPython`` state
(used by ``ImplC``) when using the "C" security policy. Thanks to
Arnaud Fontaine for the patch.
2.13.12 (2012-10-31)
--------------------
- LP #1071067: Use a stronger random number generator and a constant time - Harden test fix for machines that do not define `localhost`.
comparison function.
2.13.11 (2012-10-21) 3.0.10 (2014-11-02)
-------------------- -------------------
- LP #966101: Recognize special ``zope2.Private`` permission in ZCML - Test fix for machines that do not define `localhost`.
role directive.
2.13.10 (2012-09-09) 3.0.9 (2014-08-08)
-------------------- ------------------
- LP #1047318: Tighten import restrictions for restricted code. - GitHub #6: Do not pass SecurityInfo instance itself to declarePublic/declarePrivate
when using the public/private decorator. This fixes ``Conflicting security declarations``
warnings on Zope startup.
2.13.9 (2012-08-23) - LP #1248529: Leave existing security manager in place inside
------------------- ``RoleManager.manage_getUserRolesAndPermissions``.
- Fix a bug in ZopeSecurityPolicy.py. Global variable ``rolesForPermissionOn`` 3.0.8 (2013-07-16)
could be overridden if ``__role__`` had custom ``rolesForPermissionOn``. ------------------
2.13.8 (2012-06-22) - LP #1169923: ensure initialization of shared ``ImplPython`` state
------------------- (used by ``ImplC``) when using the "C" security policy. Thanks to
Arnaud Fontaine for the patch.
- Add Anonymous as a default role for Public permission. 3.0.7 (2013-05-14)
------------------
2.13.7 (2011-12-12) - Remove long-deprecated 'Shared' roles support (pre-dates Zope, never
------------------- used by Zope itself)
- Exclude compiled ``.so`` and ``.dll`` files from source distributions. - Prevent infinite loop when looking up local roles in an acquisition chain
with cycles.
2.13.6 (2011-12-12) 3.0.6 (2012-10-31)
------------------- ------------------
- Added ``manifest.in`` to ensure the inclusion of the ``include`` directory - LP #1071067: Use a stronger random number generator and a constant time
into the release. comparison function.
2.13.5 (2011-12-12) 3.0.5 (2012-10-21)
------------------- ------------------
- Apply changes made available in ``Products.Zope_Hotfix_20111024`` and make - LP #966101: Recognize special `zope2.Private` permission in ZCML
them more robust. role directive.
2.13.4 (2011-01-11) 3.0.4 (2012-09-09)
------------------- ------------------
- Return the created user in ``_doAddUser``. - LP #1047318: Tighten import restrictions for restricted code.
- Added ``IUser`` interface. 3.0.3 (2012-08-23)
------------------
- LP #659968: Added support for ``level`` argument to the ``__import__`` - Fix a bug in ZopeSecurityPolicy.py. Global variable `rolesForPermissionOn`
function as introduced in Python 2.5. Currently only ``level = -1`` is could be overridden if `__role__` had custom rolesForPermissionOn.
supported.
2.13.3 (2010-08-28) 3.0.2 (2012-06-22)
------------------- ------------------
- Added a ``role`` subdirective for the ``permission`` ZCML directive. If any - Add Anonymous as a default role for Public permission.
roles are specified, they will override the default set of default roles
(Manager).
2.13.2 (2010-07-16) 3.0.1 (2012-05-24)
------------------- ------------------
- Added ``override_existing_protection`` parameter to the protectName helper. - Fix tests under Python 2.6.
2.13.1 (2010-06-19) 3.0 (2012-05-12)
------------------- ----------------
- Restore security declarations for deprecated ``sets`` module. - Added decorators for public, private and protected security declarations.
2.13.0 (2010-06-19) - Update tests to take advantage of automatic test suite discovery.
-------------------
- Released as separate package.
Pre 3.0 Changelog
=================
2.13.12 (2012-10-31)
--------------------
- LP #1071067: Use a stronger random number generator and a constant time
comparison function.
2.13.11 (2012-10-21)
--------------------
- LP #966101: Recognize special `zope2.Private` permission in ZCML
role directive.
2.13.10 (2012-09-09)
--------------------
- LP #1047318: Tighten import restrictions for restricted code.
2.13.9 (2012-08-23)
-------------------
- Fix a bug in ZopeSecurityPolicy.py. Global variable `rolesForPermissionOn`
could be overridden if `__role__` had custom rolesForPermissionOn.
2.13.8 (2012-06-22)
-------------------
- Add Anonymous as a default role for Public permission.
2.13.7 (2011-12-12)
-------------------
- Exclude compiled `.so` and `.dll` files from source distributions.
2.13.6 (2011-12-12)
-------------------
- Added `manifest.in` to ensure the inclusion of the `include` directory into
the release.
2.13.5 (2011-12-12)
-------------------
- Apply changes made available in `Products.Zope_Hotfix_20111024` and make them
more robust.
2.13.4 (2011-01-11)
-------------------
- Return the created user in _doAddUser.
- Added IUser interface.
- LP #659968: Added support for level argument to the ``__import__`` function
as introduced in Python 2.5. Currently only level=-1 is supported.
2.13.3 (2010-08-28)
-------------------
- Added a ``role`` subdirective for the ``permission`` ZCML directive. If any
roles are specified, they will override the default set of default roles
(Manager).
2.13.2 (2010-07-16)
-------------------
- Added ``override_existing_protection`` parameter to the protectName helper.
2.13.1 (2010-06-19)
-------------------
- Restore security declarations for deprecated ``sets`` module.
2.13.0 (2010-06-19)
-------------------
- Released as separate package.
include *.txt include *.txt
include *.rst
recursive-include include * recursive-include include *
recursive-include src/AccessControl * recursive-include src/AccessControl *
......
...@@ -18,75 +18,14 @@ The script accepts buildout command-line options, so you can ...@@ -18,75 +18,14 @@ The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file. use the -c option to specify an alternate configuration file.
""" """
import os, shutil, sys, tempfile, urllib, urllib2, subprocess import os
import shutil
import sys
import tempfile
from optparse import OptionParser from optparse import OptionParser
if sys.platform == 'win32': tmpeggs = tempfile.mkdtemp()
def quote(c):
if ' ' in c:
return '"%s"' % c # work around spawn lamosity on windows
else:
return c
else:
quote = str
# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
stdout, stderr = subprocess.Popen(
[sys.executable, '-Sc',
'try:\n'
' import ConfigParser\n'
'except ImportError:\n'
' print 1\n'
'else:\n'
' print 0\n'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
has_broken_dash_S = bool(int(stdout.strip()))
# In order to be more robust in the face of system Pythons, we want to
# run without site-packages loaded. This is somewhat tricky, in
# particular because Python 2.6's distutils imports site, so starting
# with the -S flag is not sufficient. However, we'll start with that:
if not has_broken_dash_S and 'site' in sys.modules:
# We will restart with python -S.
args = sys.argv[:]
args[0:0] = [sys.executable, '-S']
args = map(quote, args)
os.execv(sys.executable, args)
# Now we are running with -S. We'll get the clean sys.path, import site
# because distutils will do it later, and then reset the path and clean
# out any namespace packages from site-packages that might have been
# loaded by .pth files.
clean_path = sys.path[:]
import site # imported because of its side effects
sys.path[:] = clean_path
for k, v in sys.modules.items():
if k in ('setuptools', 'pkg_resources') or (
hasattr(v, '__path__') and
len(v.__path__) == 1 and
not os.path.exists(os.path.join(v.__path__[0], '__init__.py'))):
# This is a namespace package. Remove it.
sys.modules.pop(k)
is_jython = sys.platform.startswith('java')
setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
distribute_source = 'http://python-distribute.org/distribute_setup.py'
# parsing arguments
def normalize_to_url(option, opt_str, value, parser):
if value:
if '://' not in value: # It doesn't smell like a URL.
value = 'file://%s' % (
urllib.pathname2url(
os.path.abspath(os.path.expanduser(value))),)
if opt_str == '--download-base' and not value.endswith('/'):
# Download base needs a trailing slash to make the world happy.
value += '/'
else:
value = None
name = opt_str[2:].replace('-', '_')
setattr(parser.values, name, value)
usage = '''\ usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
...@@ -96,31 +35,13 @@ Bootstraps a buildout-based project. ...@@ -96,31 +35,13 @@ Bootstraps a buildout-based project.
Simply run this script in a directory containing a buildout.cfg, using the Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use. Python that you want bin/buildout to use.
Note that by using --setup-source and --download-base to point to Note that by using --find-links to point to local resources, you can keep
local resources, you can keep this script from going over the network. this script from going over the network.
''' '''
parser = OptionParser(usage=usage) parser = OptionParser(usage=usage)
parser.add_option("-v", "--version", dest="version", parser.add_option("-v", "--version", help="use a specific zc.buildout version")
help="use a specific zc.buildout version")
parser.add_option("-d", "--distribute",
action="store_true", dest="use_distribute", default=False,
help="Use Distribute rather than Setuptools.")
parser.add_option("--setup-source", action="callback", dest="setup_source",
callback=normalize_to_url, nargs=1, type="string",
help=("Specify a URL or file location for the setup file. "
"If you use Setuptools, this will default to " +
setuptools_source + "; if you use Distribute, this "
"will default to " + distribute_source + "."))
parser.add_option("--download-base", action="callback", dest="download_base",
callback=normalize_to_url, nargs=1, type="string",
help=("Specify a URL or directory for downloading "
"zc.buildout and either Setuptools or Distribute. "
"Defaults to PyPI."))
parser.add_option("--eggs",
help=("Specify a directory for storing eggs. Defaults to "
"a temporary directory that is deleted when the "
"bootstrap script completes."))
parser.add_option("-t", "--accept-buildout-test-releases", parser.add_option("-t", "--accept-buildout-test-releases",
dest='accept_buildout_test_releases', dest='accept_buildout_test_releases',
action="store_true", default=False, action="store_true", default=False,
...@@ -130,80 +51,80 @@ parser.add_option("-t", "--accept-buildout-test-releases", ...@@ -130,80 +51,80 @@ parser.add_option("-t", "--accept-buildout-test-releases",
"extensions for you. If you use this flag, " "extensions for you. If you use this flag, "
"bootstrap and buildout will get the newest releases " "bootstrap and buildout will get the newest releases "
"even if they are alphas or betas.")) "even if they are alphas or betas."))
parser.add_option("-c", None, action="store", dest="config_file", parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration " help=("Specify the path to the buildout configuration "
"file to be used.")) "file to be used."))
parser.add_option("-f", "--find-links",
help=("Specify a URL to search for buildout releases"))
parser.add_option("--allow-site-packages",
action="store_true", default=False,
help=("Let bootstrap.py use existing site packages"))
parser.add_option("--setuptools-version",
help="use a specific setuptools version")
options, args = parser.parse_args()
if options.eggs:
eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
else:
eggs_dir = tempfile.mkdtemp()
if options.setup_source is None: options, args = parser.parse_args()
if options.use_distribute:
options.setup_source = distribute_source
else:
options.setup_source = setuptools_source
if options.accept_buildout_test_releases: ######################################################################
args.insert(0, 'buildout:accept-buildout-test-releases=true') # load/install setuptools
try: try:
if options.allow_site_packages:
import setuptools
import pkg_resources import pkg_resources
import setuptools # A flag. Sometimes pkg_resources is installed alone. from urllib.request import urlopen
if not hasattr(pkg_resources, '_distribute'):
raise ImportError
except ImportError: except ImportError:
ez_code = urllib2.urlopen( from urllib2 import urlopen
options.setup_source).read().replace('\r\n', '\n')
ez = {} ez = {}
exec ez_code in ez exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
setup_args = dict(to_dir=eggs_dir, download_delay=0)
if options.download_base: if not options.allow_site_packages:
setup_args['download_base'] = options.download_base # ez_setup imports site, which adds site packages
if options.use_distribute: # this will remove them from the path to ensure that incompatible versions
setup_args['no_fake'] = True # of setuptools are not in the path
if sys.version_info[:2] == (2, 4): import site
setup_args['version'] = '0.6.32' # inside a virtualenv, there is no 'getsitepackages'.
ez['use_setuptools'](**setup_args) # We can't remove these reliably
if 'pkg_resources' in sys.modules: if hasattr(site, 'getsitepackages'):
reload(sys.modules['pkg_resources']) for sitepackage_path in site.getsitepackages():
import pkg_resources sys.path[:] = [x for x in sys.path if sitepackage_path not in x]
# This does not (always?) update the default working set. We will
# do it. setup_args = dict(to_dir=tmpeggs, download_delay=0)
for path in sys.path:
if options.setuptools_version is not None:
setup_args['version'] = options.setuptools_version
ez['use_setuptools'](**setup_args)
import setuptools
import pkg_resources
# This does not (always?) update the default working set. We will
# do it.
for path in sys.path:
if path not in pkg_resources.working_set.entries: if path not in pkg_resources.working_set.entries:
pkg_resources.working_set.add_entry(path) pkg_resources.working_set.add_entry(path)
cmd = [quote(sys.executable), ######################################################################
'-c', # Install buildout
quote('from setuptools.command.easy_install import main; main()'),
'-mqNxd', ws = pkg_resources.working_set
quote(eggs_dir)]
if not has_broken_dash_S: cmd = [sys.executable, '-c',
cmd.insert(1, '-S') 'from setuptools.command.easy_install import main; main()',
'-mZqNxd', tmpeggs]
find_links = options.download_base find_links = os.environ.get(
if not find_links: 'bootstrap-testing-find-links',
find_links = os.environ.get('bootstrap-testing-find-links') options.find_links or
if not find_links and options.accept_buildout_test_releases: ('http://downloads.buildout.org/'
find_links = 'http://downloads.buildout.org/' if options.accept_buildout_test_releases else None)
)
if find_links: if find_links:
cmd.extend(['-f', quote(find_links)]) cmd.extend(['-f', find_links])
if options.use_distribute: setuptools_path = ws.find(
setup_requirement = 'distribute' pkg_resources.Requirement.parse('setuptools')).location
else:
setup_requirement = 'setuptools'
ws = pkg_resources.working_set
setup_requirement_path = ws.find(
pkg_resources.Requirement.parse(setup_requirement)).location
env = dict(
os.environ,
PYTHONPATH=setup_requirement_path)
requirement = 'zc.buildout' requirement = 'zc.buildout'
version = options.version version = options.version
...@@ -213,12 +134,17 @@ if version is None and not options.accept_buildout_test_releases: ...@@ -213,12 +134,17 @@ if version is None and not options.accept_buildout_test_releases:
_final_parts = '*final-', '*final' _final_parts = '*final-', '*final'
def _final_version(parsed_version): def _final_version(parsed_version):
try:
return not parsed_version.is_prerelease
except AttributeError:
# Older setuptools
for part in parsed_version: for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts): if (part[:1] == '*') and (part not in _final_parts):
return False return False
return True return True
index = setuptools.package_index.PackageIndex( index = setuptools.package_index.PackageIndex(
search_path=[setup_requirement_path]) search_path=[setuptools_path])
if find_links: if find_links:
index.add_find_links((find_links,)) index.add_find_links((find_links,))
req = pkg_resources.Requirement.parse(requirement) req = pkg_resources.Requirement.parse(requirement)
...@@ -227,8 +153,6 @@ if version is None and not options.accept_buildout_test_releases: ...@@ -227,8 +153,6 @@ if version is None and not options.accept_buildout_test_releases:
bestv = None bestv = None
for dist in index[req.project_name]: for dist in index[req.project_name]:
distv = dist.parsed_version distv = dist.parsed_version
if distv >= pkg_resources.parse_version('2dev'):
continue
if _final_version(distv): if _final_version(distv):
if bestv is None or distv > bestv: if bestv is None or distv > bestv:
best = [dist] best = [dist]
...@@ -238,40 +162,28 @@ if version is None and not options.accept_buildout_test_releases: ...@@ -238,40 +162,28 @@ if version is None and not options.accept_buildout_test_releases:
if best: if best:
best.sort() best.sort()
version = best[-1].version version = best[-1].version
if version: if version:
requirement += '=='+version requirement = '=='.join((requirement, version))
else:
requirement += '<2dev'
cmd.append(requirement) cmd.append(requirement)
if is_jython: import subprocess
import subprocess if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
exitcode = subprocess.Popen(cmd, env=env).wait() raise Exception(
else: # Windows prefers this, apparently; otherwise we would prefer subprocess "Failed to execute command:\n%s" % repr(cmd)[1:-1])
exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
if exitcode != 0: ######################################################################
sys.stdout.flush() # Import and run buildout
sys.stderr.flush()
print ("An error occurred when trying to install zc.buildout. " ws.add_entry(tmpeggs)
"Look above this message for any errors that "
"were output by easy_install.")
sys.exit(exitcode)
ws.add_entry(eggs_dir)
ws.require(requirement) ws.require(requirement)
import zc.buildout.buildout import zc.buildout.buildout
# If there isn't already a command in the args, add bootstrap
if not [a for a in args if '=' not in a]: if not [a for a in args if '=' not in a]:
args.append('bootstrap') args.append('bootstrap')
# if -c was provided, we push it back into args for buildout' main function
# if -c was provided, we push it back into args for buildout's main function
if options.config_file is not None: if options.config_file is not None:
args[0:0] = ['-c', options.config_file] args[0:0] = ['-c', options.config_file]
zc.buildout.buildout.main(args) zc.buildout.buildout.main(args)
if not options.eggs: # clean up temporary egg directory shutil.rmtree(tmpeggs)
shutil.rmtree(eggs_dir)
[buildout] [buildout]
develop = . develop = .
parts = interpreter test parts = interpreter test coverage
[interpreter] [interpreter]
recipe = zc.recipe.egg recipe = zc.recipe.egg
...@@ -10,3 +10,8 @@ eggs = AccessControl ...@@ -10,3 +10,8 @@ eggs = AccessControl
[test] [test]
recipe = zc.recipe.testrunner recipe = zc.recipe.testrunner
eggs = AccessControl eggs = AccessControl
[coverage]
recipe = zc.recipe.testrunner
eggs = AccessControl
defaults = ['--coverage', '../../coverage', '-v', '--auto-progress']
...@@ -212,7 +212,7 @@ static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) 0, # NAME, \ ...@@ -212,7 +212,7 @@ static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) 0, # NAME, \
(PyMethod_Check((M)) ? ((PyMethodObject*)(M))->im_self : NULL) (PyMethod_Check((M)) ? ((PyMethodObject*)(M))->im_self : NULL)
/* Check whether an object has an __of__ method for returning itself /* Check whether an object has an __of__ method for returning itself
in the context of it's container. */ in the context of its container. */
#define has__of__(O) (PyObject_TypeCheck((O)->ob_type, ECExtensionClassType) \ #define has__of__(O) (PyObject_TypeCheck((O)->ob_type, ECExtensionClassType) \
&& (O)->ob_type->tp_descr_get != NULL) && (O)->ob_type->tp_descr_get != NULL)
......
...@@ -27,6 +27,19 @@ setup(name='AccessControl', ...@@ -27,6 +27,19 @@ setup(name='AccessControl',
packages=find_packages('src'), packages=find_packages('src'),
package_dir={'': 'src'}, package_dir={'': 'src'},
classifiers=[
"Development Status :: 6 - Mature",
"Environment :: Web Environment",
"Framework :: Zope2",
"License :: OSI Approved :: Zope Public License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2 :: Only",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: Pyston",
],
ext_modules=[Extension( ext_modules=[Extension(
name='AccessControl.cAccessControl', name='AccessControl.cAccessControl',
include_dirs=['include', 'src'], include_dirs=['include', 'src'],
...@@ -37,6 +50,8 @@ setup(name='AccessControl', ...@@ -37,6 +50,8 @@ setup(name='AccessControl',
install_requires=[ install_requires=[
'Acquisition', 'Acquisition',
'DateTime', # optional dependency of RestrictedPython 'DateTime', # optional dependency of RestrictedPython
# Pyston change: Pyston will use pure Python implementation.
# So the version of ExtenstionClass is not important.
'ExtensionClass', 'ExtensionClass',
'Persistence', 'Persistence',
'Record', 'Record',
......
...@@ -93,7 +93,8 @@ _policy_names = { ...@@ -93,7 +93,8 @@ _policy_names = {
# start with the default, mostly because we need something for the tests # start with the default, mostly because we need something for the tests
setImplementation("C") # Pyston change: use Python implementation by default
setImplementation("Python")
# allow the implementation to change from the default # allow the implementation to change from the default
_implementation_set = 0 _implementation_set = 0
...@@ -51,7 +51,6 @@ Persistent.__class_init__ = InitializeClass ...@@ -51,7 +51,6 @@ Persistent.__class_init__ = InitializeClass
LOG = getLogger('SecurityInfo') LOG = getLogger('SecurityInfo')
# Security constants - these are imported into the AccessControl # Security constants - these are imported into the AccessControl
# namespace and can be referenced as AccessControl.PUBLIC etc. # namespace and can be referenced as AccessControl.PUBLIC etc.
...@@ -61,6 +60,7 @@ ACCESS_PUBLIC = None ...@@ -61,6 +60,7 @@ ACCESS_PUBLIC = None
_marker = [] _marker = []
class SecurityInfo(Implicit): class SecurityInfo(Implicit):
"""Encapsulate security information.""" """Encapsulate security information."""
...@@ -71,6 +71,7 @@ class SecurityInfo(Implicit): ...@@ -71,6 +71,7 @@ class SecurityInfo(Implicit):
def __init__(self): def __init__(self):
self.names = {} self.names = {}
self.roles = {} self.roles = {}
self._unused_protected_decorators = set()
def _setaccess(self, names, access): def _setaccess(self, names, access):
for name in names: for name in names:
...@@ -79,37 +80,67 @@ class SecurityInfo(Implicit): ...@@ -79,37 +80,67 @@ class SecurityInfo(Implicit):
self._warnings = 1 self._warnings = 1
self.names[name] = access self.names[name] = access
declarePublic__roles__=ACCESS_PRIVATE declarePublic__roles__ = ACCESS_PRIVATE
def declarePublic(self, name, *names): def declarePublic(self, name, *names):
"""Declare names to be publicly accessible.""" """Declare names to be publicly accessible."""
self._setaccess((name,) + names, ACCESS_PUBLIC) self._setaccess((name,) + names, ACCESS_PUBLIC)
declarePrivate__roles__=ACCESS_PRIVATE declarePrivate__roles__ = ACCESS_PRIVATE
def declarePrivate(self, name, *names): def declarePrivate(self, name, *names):
"""Declare names to be inaccessible to restricted code.""" """Declare names to be inaccessible to restricted code."""
self._setaccess((name,) + names, ACCESS_PRIVATE) self._setaccess((name,) + names, ACCESS_PRIVATE)
declareProtected__roles__=ACCESS_PRIVATE declareProtected__roles__ = ACCESS_PRIVATE
def declareProtected(self, permission_name, name, *names): def declareProtected(self, permission_name, name, *names):
"""Declare names to be associated with a permission.""" """Declare names to be associated with a permission."""
self._setaccess((name,) + names, permission_name) self._setaccess((name,) + names, permission_name)
declareObjectPublic__roles__=ACCESS_PRIVATE declareObjectPublic__roles__ = ACCESS_PRIVATE
def declareObjectPublic(self): def declareObjectPublic(self):
"""Declare the object to be publicly accessible.""" """Declare the object to be publicly accessible."""
self._setaccess(('',), ACCESS_PUBLIC) self._setaccess(('',), ACCESS_PUBLIC)
declareObjectPrivate__roles__=ACCESS_PRIVATE declareObjectPrivate__roles__ = ACCESS_PRIVATE
def declareObjectPrivate(self): def declareObjectPrivate(self):
"""Declare the object to be inaccessible to restricted code.""" """Declare the object to be inaccessible to restricted code."""
self._setaccess(('',), ACCESS_PRIVATE) self._setaccess(('',), ACCESS_PRIVATE)
declareObjectProtected__roles__=ACCESS_PRIVATE declareObjectProtected__roles__ = ACCESS_PRIVATE
def declareObjectProtected(self, permission_name): def declareObjectProtected(self, permission_name):
"""Declare the object to be associated with a permission.""" """Declare the object to be associated with a permission."""
self._setaccess(('',), permission_name) self._setaccess(('',), permission_name)
setPermissionDefault__roles__=ACCESS_PRIVATE public__roles__ = ACCESS_PRIVATE
def public(self, func):
"""Decorate a function to be publicly accessible."""
self.declarePublic(func.__name__)
return func
private__roles__ = ACCESS_PRIVATE
def private(self, func):
"""Decorate a function to be inaccessible to restricted code."""
self.declarePrivate(func.__name__)
return func
protected__roles__ = ACCESS_PRIVATE
def protected(self, permission_name):
"""Return a decorator to associate a function with a permission."""
# the decorator returned is remembered in a set and will
# remove itself upon call. self.apply will check for an empty
# set and raise an AssertionError otherwise.
key = "'%s':%s" % (permission_name, id(lambda x: x))
def decor(func):
self.declareProtected(permission_name, func.__name__)
self._unused_protected_decorators.remove(key)
return func
# make sure our key algo creates unique-enough keys
if key in self._unused_protected_decorators:
raise KeyError("Duplicate key: %s" % (key,))
self._unused_protected_decorators.add(key)
return decor
setPermissionDefault__roles__ = ACCESS_PRIVATE
def setPermissionDefault(self, permission_name, roles): def setPermissionDefault(self, permission_name, roles):
"""Declare default roles for a permission""" """Declare default roles for a permission"""
rdict = {} rdict = {}
...@@ -121,7 +152,7 @@ class SecurityInfo(Implicit): ...@@ -121,7 +152,7 @@ class SecurityInfo(Implicit):
self._warnings = 1 self._warnings = 1
self.roles[permission_name] = rdict self.roles[permission_name] = rdict
setDefaultAccess__roles__=ACCESS_PRIVATE setDefaultAccess__roles__ = ACCESS_PRIVATE
def setDefaultAccess(self, access): def setDefaultAccess(self, access):
"""Declare default attribute access policy. """Declare default attribute access policy.
...@@ -135,7 +166,7 @@ class SecurityInfo(Implicit): ...@@ -135,7 +166,7 @@ class SecurityInfo(Implicit):
elif access == 'deny': elif access == 'deny':
access = 0 access = 0
else: else:
raise ValueError, "'allow' or 'deny' expected" raise ValueError("'allow' or 'deny' expected")
self.access = access self.access = access
...@@ -148,13 +179,19 @@ class ClassSecurityInfo(SecurityInfo): ...@@ -148,13 +179,19 @@ class ClassSecurityInfo(SecurityInfo):
def apply(self, classobj): def apply(self, classobj):
"""Apply security information to the given class object.""" """Apply security information to the given class object."""
dict = classobj.__dict__ # make sure all decorators handed out by security.protected were used
if self._unused_protected_decorators:
msg = "Class '%r' has %d non-decorator security.protected calls!"
raise AssertionError(msg % (classobj,
len(self._unused_protected_decorators)))
cdict = classobj.__dict__
# Check the class for an existing __ac_permissions__ and # Check the class for an existing __ac_permissions__ and
# incorporate that if present to support older classes or # incorporate that if present to support older classes or
# classes that haven't fully switched to using SecurityInfo. # classes that haven't fully switched to using SecurityInfo.
if dict.has_key('__ac_permissions__'): if '__ac_permissions__' in cdict:
for item in dict['__ac_permissions__']: for item in cdict['__ac_permissions__']:
permission_name = item[0] permission_name = item[0]
self._setaccess(item[1], permission_name) self._setaccess(item[1], permission_name)
if len(item) > 2: if len(item) > 2:
...@@ -167,7 +204,7 @@ class ClassSecurityInfo(SecurityInfo): ...@@ -167,7 +204,7 @@ class ClassSecurityInfo(SecurityInfo):
if access in (ACCESS_PRIVATE, ACCESS_PUBLIC, ACCESS_NONE): if access in (ACCESS_PRIVATE, ACCESS_PUBLIC, ACCESS_NONE):
setattr(classobj, '%s__roles__' % name, access) setattr(classobj, '%s__roles__' % name, access)
else: else:
if not ac_permissions.has_key(access): if access not in ac_permissions:
ac_permissions[access] = [] ac_permissions[access] = []
ac_permissions[access].append(name) ac_permissions[access].append(name)
...@@ -201,6 +238,7 @@ class ClassSecurityInfo(SecurityInfo): ...@@ -201,6 +238,7 @@ class ClassSecurityInfo(SecurityInfo):
LOG.warn('Class "%s" had conflicting ' LOG.warn('Class "%s" had conflicting '
'security declarations' % classobj.__name__) 'security declarations' % classobj.__name__)
class ClassSecurityInformation(ClassSecurityInfo): class ClassSecurityInformation(ClassSecurityInfo):
# Default policy is disallow # Default policy is disallow
access = 0 access = 0
...@@ -208,6 +246,7 @@ class ClassSecurityInformation(ClassSecurityInfo): ...@@ -208,6 +246,7 @@ class ClassSecurityInformation(ClassSecurityInfo):
_moduleSecurity = {} _moduleSecurity = {}
_appliedModuleSecurity = {} _appliedModuleSecurity = {}
def secureModule(mname, *imp): def secureModule(mname, *imp):
modsec = _moduleSecurity.get(mname, None) modsec = _moduleSecurity.get(mname, None)
if modsec is None: if modsec is None:
...@@ -223,6 +262,7 @@ def secureModule(mname, *imp): ...@@ -223,6 +262,7 @@ def secureModule(mname, *imp):
_appliedModuleSecurity[mname] = modsec _appliedModuleSecurity[mname] = modsec
return module return module
def ModuleSecurityInfo(module_name=None): def ModuleSecurityInfo(module_name=None):
if module_name is not None: if module_name is not None:
modsec = _moduleSecurity.get(module_name, None) modsec = _moduleSecurity.get(module_name, None)
...@@ -246,10 +286,11 @@ def ModuleSecurityInfo(module_name=None): ...@@ -246,10 +286,11 @@ def ModuleSecurityInfo(module_name=None):
# leading to the module # leading to the module
modname = module_name[dot + 1:] modname = module_name[dot + 1:]
pmodsec = ModuleSecurityInfo(module_name[:dot]) pmodsec = ModuleSecurityInfo(module_name[:dot])
if not pmodsec.names.has_key(modname): if modname not in pmodsec.names:
pmodsec.declarePublic(modname) pmodsec.declarePublic(modname)
return _ModuleSecurityInfo(module_name) return _ModuleSecurityInfo(module_name)
class _ModuleSecurityInfo(SecurityInfo): class _ModuleSecurityInfo(SecurityInfo):
"""Encapsulate security information for modules.""" """Encapsulate security information for modules."""
...@@ -284,23 +325,24 @@ class _ModuleSecurityInfo(SecurityInfo): ...@@ -284,23 +325,24 @@ class _ModuleSecurityInfo(SecurityInfo):
LOG.warn('Module "%s" had conflicting ' LOG.warn('Module "%s" had conflicting '
'security declarations' % dict['__name__']) 'security declarations' % dict['__name__'])
declareProtected__roles__=ACCESS_PRIVATE declareProtected__roles__ = ACCESS_PRIVATE
def declareProtected(self, permission_name, *names): def declareProtected(self, permission_name, *names):
"""Cannot declare module names protected.""" """Cannot declare module names protected."""
pass pass
declareObjectProtected__roles__=ACCESS_PRIVATE declareObjectProtected__roles__ = ACCESS_PRIVATE
def declareObjectProtected(self, permission_name): def declareObjectProtected(self, permission_name):
"""Cannot declare module protected.""" """Cannot declare module protected."""
pass pass
setDefaultRoles__roles__=ACCESS_PRIVATE setDefaultRoles__roles__ = ACCESS_PRIVATE
def setDefaultRoles(self, permission_name, roles): def setDefaultRoles(self, permission_name, roles):
"""Cannot set default roles for permissions in a module.""" """Cannot set default roles for permissions in a module."""
pass pass
# Handy little utility functions # Handy little utility functions
def allow_module(module_name): def allow_module(module_name):
"""Allow a module and all its contents to be used from a """Allow a module and all its contents to be used from a
restricted Script. The argument module_name may be a simple restricted Script. The argument module_name may be a simple
...@@ -312,6 +354,7 @@ def allow_module(module_name): ...@@ -312,6 +354,7 @@ def allow_module(module_name):
ModuleSecurityInfo(module_name[:dot]).setDefaultAccess(1) ModuleSecurityInfo(module_name[:dot]).setDefaultAccess(1)
dot = module_name.find('.', dot + 1) dot = module_name.find('.', dot + 1)
def allow_class(Class): def allow_class(Class):
"""Allow a class and all of its methods to be used from a """Allow a class and all of its methods to be used from a
restricted Script. The argument Class must be a class.""" restricted Script. The argument Class must be a class."""
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
"""Place to find special users """Place to find special users
This is needed to avoid a circular import problem. The 'real' values This is needed to avoid a circular import problem. The 'real' values
are stored here by the AccessControl.User module as part of it's are stored here by the AccessControl.User module as part of its
initialization. initialization.
""" """
......
...@@ -894,7 +894,7 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) { ...@@ -894,7 +894,7 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
/*| # We have an object without roles and we didn't get /*| # We have an object without roles and we didn't get
**| # a list of roles passed in. Presumably, the value **| # a list of roles passed in. Presumably, the value
**| # is some simple object like a string or a list. **| # is some simple object like a string or a list.
**| # We'll try to get roles from it's container **| # We'll try to get roles from its container
**| **|
**| if container is None: raise Unauthorized(name, value) **| if container is None: raise Unauthorized(name, value)
*/ */
......
...@@ -158,7 +158,6 @@ class RoleManager(Base, RoleManager): ...@@ -158,7 +158,6 @@ class RoleManager(Base, RoleManager):
else: else:
current = current.__parent__ current = current.__parent__
newSecurityManager(None, userObj) # necessary?
userObj = userObj.__of__(uf) userObj = userObj.__of__(uf)
d = {'user_defined_in': '/' + uf.absolute_url(1)} d = {'user_defined_in': '/' + uf.absolute_url(1)}
......
...@@ -10,24 +10,39 @@ ...@@ -10,24 +10,39 @@
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE
# #
############################################################################## ##############################################################################
""" Unit tests for ClassSecurityInfo.
"""
import unittest import unittest
class ClassSecurityInfoTests(unittest.TestCase): class ClassSecurityInfoTests(unittest.TestCase):
def _getTargetClass(self): def _getTargetClass(self):
from AccessControl.SecurityInfo import ClassSecurityInfo from AccessControl.SecurityInfo import ClassSecurityInfo
return ClassSecurityInfo return ClassSecurityInfo
def test_SetPermissionDefault(self): def assertRaises(self, excClass, callableObj, *args, **kwargs):
"""Fail unless an exception of class excClass is thrown
by callableObj when invoked with arguments args and keyword
arguments kwargs. If a different type of exception is
thrown, it will not be caught, and the test case will be
deemed to have suffered an error, exactly as for an
unexpected exception.
# Test setting default roles for permissions. Return the raised exception object, if it matches the expected type.
"""
try:
callableObj(*args, **kwargs)
except excClass as e:
return e
else:
if getattr(excClass,'__name__', None) is not None:
excName = excClass.__name__
else:
excName = str(excClass)
raise self.failureException("%s not raised" % excName)
def test_SetPermissionDefault(self):
# Test setting default roles for permissions.
from AccessControl.class_init import InitializeClass from AccessControl.class_init import InitializeClass
from ExtensionClass import Base from ExtensionClass import Base
...@@ -38,22 +53,39 @@ class ClassSecurityInfoTests(unittest.TestCase): ...@@ -38,22 +53,39 @@ class ClassSecurityInfoTests(unittest.TestCase):
"""Test class """Test class
""" """
__ac_roles__ = ('Role A', 'Role B', 'Role C') __ac_roles__ = ('Role A', 'Role B', 'Role C')
meta_type = "Test" meta_type = "Test"
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.setPermissionDefault('Make food', ('Chef',)) security.setPermissionDefault('Make food', ('Chef',))
security.setPermissionDefault( security.setPermissionDefault(
'Test permission', 'Test permission',
('Manager', 'Role A', 'Role B', 'Role C') ('Manager', 'Role A', 'Role B', 'Role C')
) )
security.declareProtected('Test permission', 'foo') security.declarePublic('public')
def foo(self, REQUEST=None): def public(self, REQUEST=None):
""" """
security.declarePrivate('private')
def private(self, REQUEST=None):
""" """
security.declareProtected('Test permission', 'protected')
def protected(self, REQUEST=None):
""" """
# same with decorators
@security.public
def public_new(self, REQUEST=None):
""" """
@security.private
def private_new(self, REQUEST=None):
""" """
@security.protected('Test permission')
def protected_new(self, REQUEST=None):
""" """ """ """
pass
# Do class initialization. # Do class initialization.
InitializeClass(Test) InitializeClass(Test)
...@@ -62,7 +94,24 @@ class ClassSecurityInfoTests(unittest.TestCase): ...@@ -62,7 +94,24 @@ class ClassSecurityInfoTests(unittest.TestCase):
# correctly. Note that this uses carnal knowledge of the internal # correctly. Note that this uses carnal knowledge of the internal
# structures used to store this information! # structures used to store this information!
object = Test() object = Test()
imPermissionRole = [r for r in object.foo__roles__ self.assertEqual(object.public__roles__, None)
self.assertEqual(object.private__roles__, ())
imPermissionRole = [r for r in object.protected__roles__
if not r.endswith('_Permission')]
self.failUnless(len(imPermissionRole) == 4)
for item in ('Manager', 'Role A', 'Role B', 'Role C'):
self.failUnless(item in imPermissionRole)
# functions exist, i.e. decorators returned them
self.assertEqual(object.public_new.__name__, 'public_new')
self.assertEqual(object.private_new.__name__, 'private_new')
self.assertEqual(object.protected_new.__name__, 'protected_new')
# roles for functions have been set via decorators
self.assertEqual(object.public_new__roles__, None)
self.assertEqual(object.private_new__roles__, ())
imPermissionRole = [r for r in object.protected_new__roles__
if not r.endswith('_Permission')] if not r.endswith('_Permission')]
self.failUnless(len(imPermissionRole) == 4) self.failUnless(len(imPermissionRole) == 4)
...@@ -74,11 +123,61 @@ class ClassSecurityInfoTests(unittest.TestCase): ...@@ -74,11 +123,61 @@ class ClassSecurityInfoTests(unittest.TestCase):
self.assertEquals([t for t in Test.__ac_permissions__ if not t[1]], self.assertEquals([t for t in Test.__ac_permissions__ if not t[1]],
[('Make food', (), ('Chef',))]) [('Make food', (), ('Chef',))])
def test_EnsureProtectedDecoCall(self):
from AccessControl.class_init import InitializeClass
from ExtensionClass import Base
def test_suite(): ClassSecurityInfo = self._getTargetClass()
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ClassSecurityInfoTests))
return suite
if __name__ == '__main__': class Test(Base):
unittest.main(defaultTest='test_suite') """Test class
"""
meta_type = "Test"
security = ClassSecurityInfo()
security.protected('Test permission 1')
def unprotected1(self, REQUEST=None):
""" """
security.protected('Test permission 2')
def unprotected2(self, REQUEST=None):
""" """
@security.protected('Test permission 3')
def protected(self, REQUEST=None):
""" """
# Do class initialization.
exc = self.assertRaises(AssertionError,
InitializeClass, Test)
self.assertTrue('has 2 non-decorator' in str(exc))
def test_aq_context_in_decorators(self):
from Acquisition import Implicit
info = self._getTargetClass()
class A(Implicit):
security = info()
a = 1
@security.public
def public(self):
return self.a
@security.private
def private(self):
# make sure the acquisition context is still intact
return self.b
class B(Implicit):
security = info()
b = 2
a = A()
b = B()
a = a.__of__(b)
self.assertEqual(a.b, 2)
self.assertEqual(a.public(), 1)
self.assertEqual(a.private(), 2)
...@@ -62,6 +62,3 @@ class AccessControlImplementationTest(unittest.TestCase): ...@@ -62,6 +62,3 @@ class AccessControlImplementationTest(unittest.TestCase):
def test_suite(): def test_suite():
return unittest.makeSuite(AccessControlImplementationTest) return unittest.makeSuite(AccessControlImplementationTest)
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")
...@@ -84,7 +84,3 @@ class ModuleSecurityTests(unittest.TestCase): ...@@ -84,7 +84,3 @@ class ModuleSecurityTests(unittest.TestCase):
def test_level_nondefault(self): def test_level_nondefault(self):
self.assertUnauth('AccessControl.tests.public_module', (), level=1) self.assertUnauth('AccessControl.tests.public_module', (), level=1)
def test_suite():
return unittest.makeSuite(ModuleSecurityTests)
...@@ -290,10 +290,3 @@ class OwnershipChangeTests(unittest.TestCase): ...@@ -290,10 +290,3 @@ class OwnershipChangeTests(unittest.TestCase):
self.assertEquals( self.root.parent.child.grandchild._owner self.assertEquals( self.root.parent.child.grandchild._owner
, previous_grandchild_owner , previous_grandchild_owner
) )
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(OwnedTests),
unittest.makeSuite(OwnershipChangeTests),
))
...@@ -78,15 +78,3 @@ class PasswordDigestTests (unittest.TestCase): ...@@ -78,15 +78,3 @@ class PasswordDigestTests (unittest.TestCase):
# Sanity check # Sanity check
pw = 'my-password' pw = 'my-password'
assert AuthEncoding.pw_validate(pw, pw) assert AuthEncoding.pw_validate(pw, pw)
def test_suite():
suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite( PasswordDigestTests ) )
return suite
def main():
unittest.TextTestRunner().run(test_suite())
if __name__ == '__main__':
main()
...@@ -9,9 +9,3 @@ class TestRoleManager(unittest.TestCase): ...@@ -9,9 +9,3 @@ class TestRoleManager(unittest.TestCase):
from zope.interface.verify import verifyClass from zope.interface.verify import verifyClass
verifyClass(IPermissionMappingSupport, RoleManager) verifyClass(IPermissionMappingSupport, RoleManager)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestRoleManager),
))
...@@ -114,14 +114,3 @@ class PermissionRoleTests (unittest.TestCase): ...@@ -114,14 +114,3 @@ class PermissionRoleTests (unittest.TestCase):
self.failUnless(getattr(a, '_d') == ('Manager',)) self.failUnless(getattr(a, '_d') == ('Manager',))
self.failUnless(getattr(a, '__name__') == 'a') self.failUnless(getattr(a, '__name__') == 'a')
self.failUnless(getattr(a, '_p') == '_a_Permission') self.failUnless(getattr(a, '_p') == '_a_Permission')
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(PermissionRoleTests))
return suite
def main():
unittest.TextTestRunner().run(test_suite())
if __name__ == '__main__':
main()
import unittest import unittest
def _makeRootAndUser():
from AccessControl.rolemanager import RoleManager
from Acquisition import Implicit, Explicit
class DummyContext(Implicit, RoleManager):
__roles__ = ('Manager',)
class DummyUser(Explicit):
def getRoles(self):
return ('Manager',)
def getRolesInContext(self, context):
return ('Manager',)
def has_permission(self, permission, context):
return True
class DummyAclUsers(Explicit):
def getUser(self, user_id):
user = DummyUser()
return user.__of__(self)
def absolute_url(self, relative=0):
return 'acl_users'
class DummyRoot(Explicit):
acl_users = DummyAclUsers()
root = DummyRoot()
root.acl_users = DummyAclUsers()
root.context1 = DummyContext()
root.context2 = DummyContext()
user = DummyUser().__of__(root.acl_users)
return root, user
class TestRoleManager(unittest.TestCase): class TestRoleManager(unittest.TestCase):
def tearDown(self):
from AccessControl.SecurityManagement import noSecurityManager
noSecurityManager()
def test_interfaces(self): def test_interfaces(self):
from AccessControl.interfaces import IRoleManager from AccessControl.interfaces import IRoleManager
from AccessControl.rolemanager import RoleManager from AccessControl.rolemanager import RoleManager
...@@ -10,8 +55,12 @@ class TestRoleManager(unittest.TestCase): ...@@ -10,8 +55,12 @@ class TestRoleManager(unittest.TestCase):
verifyClass(IRoleManager, RoleManager) verifyClass(IRoleManager, RoleManager)
def test_manage_getUserRolesAndPermissions(self):
def test_suite(): from AccessControl.ImplPython import verifyAcquisitionContext
return unittest.TestSuite(( from AccessControl.SecurityManagement import getSecurityManager
unittest.makeSuite(TestRoleManager), from AccessControl.SecurityManagement import newSecurityManager
)) root, user = _makeRootAndUser()
newSecurityManager(None, user)
root.context1.manage_getUserRolesAndPermissions('dummy_user')
user = getSecurityManager().getUser()
self.assertTrue(verifyAcquisitionContext(user, root.context2, ()))
...@@ -262,10 +262,6 @@ class C_SecurityManagerTests(SecurityManagerTestBase, ...@@ -262,10 +262,6 @@ class C_SecurityManagerTests(SecurityManagerTestBase,
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite( PythonSecurityManagerTests ) ) suite.addTest(unittest.makeSuite(PythonSecurityManagerTests))
suite.addTest( unittest.makeSuite( C_SecurityManagerTests ) ) suite.addTest(unittest.makeSuite(C_SecurityManagerTests))
return suite return suite
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
...@@ -438,6 +438,7 @@ def test_register_permission_with_non_default_roles(): ...@@ -438,6 +438,7 @@ def test_register_permission_with_non_default_roles():
>>> tearDown() >>> tearDown()
""" """
def test_suite(): def test_suite():
import doctest import doctest
return doctest.DocTestSuite(optionflags=doctest.ELLIPSIS) return doctest.DocTestSuite(optionflags=doctest.ELLIPSIS)
...@@ -857,9 +857,9 @@ protected_inplacevar allows inplce ops on sets: ...@@ -857,9 +857,9 @@ protected_inplacevar allows inplce ops on sets:
[2, 7, 8, 9] [2, 7, 8, 9]
>>> sorted(s) >>> sorted(s)
[2, 7, 8, 9] [2, 7, 8, 9]
""" """
def test_suite(): def test_suite():
suite = unittest.TestSuite([ suite = unittest.TestSuite([
doctest.DocTestSuite(), doctest.DocTestSuite(),
...@@ -874,7 +874,3 @@ def test_suite(): ...@@ -874,7 +874,3 @@ def test_suite():
): ):
suite.addTest(unittest.makeSuite(cls)) suite.addTest(unittest.makeSuite(cls))
return suite return suite
if __name__ == '__main__':
unittest.main()
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
# #
############################################################################## ##############################################################################
from doctest import DocTestSuite
import sys import sys
import thread import thread
import unittest import unittest
...@@ -635,10 +636,8 @@ def test_zsp_gets_right_roles_for_methods(): ...@@ -635,10 +636,8 @@ def test_zsp_gets_right_roles_for_methods():
>>> c.__allow_access_to_unprotected_subobjects__ = 1 >>> c.__allow_access_to_unprotected_subobjects__ = 1
>>> bool(zsp.validate(c, c, 'bar', c.bar, Context(User(['spam'])))) >>> bool(zsp.validate(c, c, 'bar', c.bar, Context(User(['spam']))))
True True
""" """
from doctest import DocTestSuite
class GetRolesWithMultiThreadTest(unittest.TestCase): class GetRolesWithMultiThreadTest(unittest.TestCase):
......
...@@ -14,18 +14,16 @@ ...@@ -14,18 +14,16 @@
from zope.interface import implements from zope.interface import implements
from zope.publisher.interfaces.browser import IBrowserRequest from zope.publisher.interfaces.browser import IBrowserRequest
class DummyRequest: class DummyRequest:
implements(IBrowserRequest) implements(IBrowserRequest)
def __init__(self, method): def __init__(self, method):
self.method = method self.method = method
def test_suite(): def test_suite():
from doctest import DocFileSuite from doctest import DocFileSuite
return DocFileSuite('../requestmethod.txt', return DocFileSuite('../requestmethod.txt',
globs=dict(GET=DummyRequest('GET'), globs=dict(GET=DummyRequest('GET'),
POST=DummyRequest('POST'))) POST=DummyRequest('POST')))
if __name__ == '__main__':
import unittest
unittest.main(defaultTest='test_suite')
...@@ -60,7 +60,3 @@ class SafeIterTestCase(unittest.TestCase): ...@@ -60,7 +60,3 @@ class SafeIterTestCase(unittest.TestCase):
self.assertEqual(self.checks, [(contid, 1), self.assertEqual(self.checks, [(contid, 1),
(contid, 2), (contid, 2),
(contid, 3)]) (contid, 3)])
def test_suite():
return unittest.makeSuite(SafeIterTestCase)
...@@ -151,9 +151,3 @@ class TestTaintedString(unittest.TestCase): ...@@ -151,9 +151,3 @@ class TestTaintedString(unittest.TestCase):
def testQuoted(self): def testQuoted(self):
self.assertEquals(self.tainted.quoted(), self.quoted) self.assertEquals(self.tainted.quoted(), self.quoted)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestTaintedString))
return suite
...@@ -168,9 +168,3 @@ class UserFolderTests(unittest.TestCase): ...@@ -168,9 +168,3 @@ class UserFolderTests(unittest.TestCase):
self.assertEqual(user.__, ENCRYPTED) self.assertEqual(user.__, ENCRYPTED)
self.failUnless(uf._isPasswordEncrypted(user.__)) self.failUnless(uf._isPasswordEncrypted(user.__))
self.failUnless(pw_validate(user.__, PASSWORD)) self.failUnless(pw_validate(user.__, PASSWORD))
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(UserFolderTests))
return suite
...@@ -54,11 +54,363 @@ class BasicUserTests(unittest.TestCase): ...@@ -54,11 +54,363 @@ class BasicUserTests(unittest.TestCase):
self.assertRaises(NotImplementedError, derived.getRoles) self.assertRaises(NotImplementedError, derived.getRoles)
self.assertRaises(NotImplementedError, derived.getDomains) self.assertRaises(NotImplementedError, derived.getDomains)
# TODO: def test_getRolesInContext (w/wo local, callable, aq) def test_getRolesInContext_no_aq_no_local_roles(self):
# TODO: def test_authenticate (w/wo domains) derived = self._makeDerived()
# TODO: def test_allowed (...) derived.getId = lambda *x: 'user'
# TODO: def test_has_role (w/wo str, context) derived.getRoles = lambda *x: ['Manager']
# TODO: def test_has_permission (w/wo str) self.assertEqual(derived.getRolesInContext(self), ['Manager'])
def test_getRolesInContext_no_aq_w_local_roles_as_dict(self):
class Target(object):
__ac_local_roles__ = {'user': ['Other']}
derived = self._makeDerived()
derived.getId = lambda *x: 'user'
derived.getRoles = lambda *x: ['Manager']
self.assertEqual(derived.getRolesInContext(Target()),
['Manager', 'Other'])
def test_getRolesInContext_no_aq_w_local_roles_as_callable(self):
class Context(object):
def __ac_local_roles__(self):
return {'user': ['Other']}
derived = self._makeDerived()
derived.getId = lambda *x: 'user'
derived.getRoles = lambda *x: ['Manager']
self.assertEqual(derived.getRolesInContext(Context()),
['Manager', 'Other'])
def test_getRolesInContext_w_aq(self):
class Context(object):
pass
derived = self._makeDerived()
derived.getId = lambda *x: 'user'
derived.getRoles = lambda *x: ['Manager']
parent = Context()
parent.__ac_local_roles__ = {'user': ['Another']}
target = Context()
target.__ac_local_roles__ = {'user': ['Other']}
target.__parent__ = parent
self.assertEqual(derived.getRolesInContext(target),
['Manager', 'Other', 'Another'])
def test_getRolesInContext_w_method(self):
class Context(object):
__ac_local_roles__ = {'user': ['Other']}
def method(self):
pass
derived = self._makeDerived()
derived.getId = lambda *x: 'user'
derived.getRoles = lambda *x: ['Manager']
target = Context()
self.assertEqual(derived.getRolesInContext(target.method),
['Manager', 'Other'])
def test_authenticate_miss_wo_domains(self):
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ()
self.assertFalse(derived.authenticate('notpassword', {}))
def test_authenticate_hit_wo_domains(self):
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ()
self.assertTrue(derived.authenticate('password', {}))
def test_authenticate_hit_w_domains_any(self):
class Request(dict):
def getClientAddr(self):
return '192.168.1.1'
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('*',)
request = Request(REMOTE_HOST='example.com')
self.assertTrue(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_both(self):
class Request(dict):
def getClientAddr(self):
return '192.168.1.1'
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('127.0.0.1',)
request = Request(REMOTE_HOST='example.com')
self.assertFalse(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_wo_host_wo_addr(self):
class Request(dict):
def getClientAddr(self):
return ''
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('127.0.0.1',)
request = Request(REMOTE_HOST='')
self.assertFalse(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_host_hit_addr(self):
class Request(dict):
def getClientAddr(self):
return '127.0.0.1'
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('127.0.0.1',)
request = Request(REMOTE_HOST='example.com')
self.assertTrue(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_host_hit_addr_wo_host(self):
class Request(dict):
def getClientAddr(self):
return '127.0.0.1'
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('127.0.0.1',)
request = Request(REMOTE_HOST='')
self.assertTrue(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_host_hit_addr_wo_addr(self):
class Request(dict):
def getClientAddr(self):
return ''
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('127.0.0.1',)
request = Request(REMOTE_HOST='localhost')
self.assertTrue(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_addr_hit_host(self):
class Request(dict):
def getClientAddr(self):
return '192.168.1.1'
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('example.com',)
request = Request(REMOTE_HOST='host.example.com')
self.assertTrue(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_addr_hit_host_wo_addr(self):
class Request(dict):
def getClientAddr(self):
return ''
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('example.com',)
request = Request(REMOTE_HOST='host.example.com')
self.assertTrue(derived.authenticate('password', request))
def test_authenticate_hit_w_domains_miss_addr_hit_host_wo_host(self):
class Request(dict):
def getClientAddr(self):
return '127.0.0.1'
derived = self._makeDerived()
derived._getPassword = lambda *x: 'password'
derived.getDomains = lambda *x: ('localhost',)
request = Request(REMOTE_HOST='localhost')
self.assertTrue(derived.authenticate('password', request))
def test_allowed__what_not_even_god_should_do(self):
from AccessControl.PermissionRole import _what_not_even_god_should_do
derived = self._makeDerived()
self.assertFalse(derived.allowed(self, _what_not_even_god_should_do))
def test_allowed_w_roles_is_None(self):
derived = self._makeDerived()
self.assertTrue(derived.allowed(self, None))
def test_allowed_w_Anonymous_in_roles(self):
derived = self._makeDerived()
self.assertTrue(derived.allowed(self, ['Anonymous']))
def test_allowed_w_Authenticated_in_roles_w_Anonymous(self):
derived = self._makeDerived()
derived.getUserName = lambda *x: 'Anonymous User'
derived.getRoles = lambda *x: ['Anonymous']
self.assertFalse(derived.allowed(self, ['Authenticated']))
def test_allowed_w_Authenticated_in_roles_not_Anonymous(self):
derived = self._makeDerived()
derived.getUserName = lambda *x: 'user'
self.assertTrue(derived.allowed(self, ['Authenticated']))
def test_allowed_w_Authenticated_in_roles_not_Anonymous_context_miss(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: []
self.assertFalse(derived.allowed(self, ['Authenticated']))
def test_allowed_w_Authenticated_in_roles_not_Anonymous_context_hit(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: []
self.assertTrue(derived.allowed(folder, ['Authenticated']))
# TODO: def test_allowed_w_Shared_in_roles XXX rip that out instead
def test_allowed_w_global_roles_hit_context_miss(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: ['Editor']
self.assertFalse(derived.allowed(self, ['Editor']))
def test_allowed_w_global_roles_hit_context_hit(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: ['Editor']
self.assertTrue(derived.allowed(folder, ['Editor']))
def test_allowed_w_global_roles_miss_wo_local_roles_wo_aq(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: ['Author']
self.assertFalse(derived.allowed(self, ['Editor']))
def test_allowed_w_global_roles_miss_w_local_roles_miss_wo_aq(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
class Folder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
other = Folder() # no aq
other.__ac_local_roles__ = {'user': ['Editor']}
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: ['Author']
self.assertFalse(derived.allowed(other, ['Reviewer']))
def test_allowed_w_global_roles_miss_w_local_roles_hit_wo_aq(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
class Folder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
other = Folder() # no aq
other.__ac_local_roles__ = {'user': ['Editor']}
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: ['Author']
self.assertFalse(derived.allowed(other, ['Editor']))
def test_allowed_w_global_roles_miss_w_local_roles_hit_w_aq(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
class Folder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
other = Folder().__of__(root)
other.__ac_local_roles__ = {'user': ['Editor']}
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: ['Author']
self.assertTrue(derived.allowed(other, ['Editor']))
def test_has_role_w_str_wo_context_miss(self):
derived = self._makeDerived()
derived.getRoles = lambda *x: ['Author']
self.assertFalse(derived.has_role('Editor'))
def test_has_role_w_list_wo_context_hit(self):
derived = self._makeDerived()
derived.getRoles = lambda *x: ['Author']
self.assertTrue(derived.has_role(['Author']))
def test_has_role_w_list_w_context_miss(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class Folder(Implicit):
pass
root = Root()
root.__ac_local_roles__ = {'user': ['Editor']}
folder = Folder().__of__(root)
derived = self._makeDerived()
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: []
self.assertFalse(derived.has_role(['Author'], folder))
def test_has_role_w_list_w_context_hit(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class Folder(Implicit):
pass
root = Root()
root.__ac_local_roles__ = {'user': ['Editor']}
folder = Folder().__of__(root)
derived = self._makeDerived()
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: []
self.assertTrue(derived.has_role(['Editor'], folder))
def test_has_permission_miss(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getUserName = lambda *x: 'user'
derived.getRoles = lambda *x: []
self.assertFalse(derived.has_permission('Permission', folder))
def test_has_permission_hit(self):
from Acquisition import Implicit
class Root(Implicit):
pass
class UserFolder(Implicit):
pass
root = Root()
folder = UserFolder().__of__(root)
derived = self._makeDerived().__of__(folder)
derived.getRoles = lambda *x: ['Manager']
self.assertTrue(derived.has_permission('Permission', folder))
def test___len__(self): def test___len__(self):
derived = self._makeDerived() derived = self._makeDerived()
...@@ -252,13 +604,3 @@ class NullUnrestrictedUserTests(unittest.TestCase): ...@@ -252,13 +604,3 @@ class NullUnrestrictedUserTests(unittest.TestCase):
# See https://bugs.launchpad.net/zope2/+bug/142563 # See https://bugs.launchpad.net/zope2/+bug/142563
null = self._makeOne() null = self._makeOne()
self.assertEqual(str(null), "<NullUnrestrictedUser (None, None)>") self.assertEqual(str(null), "<NullUnrestrictedUser (None, None)>")
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(BasicUserTests))
suite.addTest(unittest.makeSuite(SimpleUserTests))
suite.addTest(unittest.makeSuite(SpecialUserTests))
suite.addTest(unittest.makeSuite(UnrestrictedUserTests))
suite.addTest(unittest.makeSuite(NullUnrestrictedUserTests))
return suite
...@@ -55,7 +55,7 @@ class BasicUser(Implicit): ...@@ -55,7 +55,7 @@ class BasicUser(Implicit):
# functionality that we cant anticipate from the base scaffolding. # functionality that we cant anticipate from the base scaffolding.
def __allow_access_to_unprotected_subobjects__(self, name, value=None): def __allow_access_to_unprotected_subobjects__(self, name, value=None):
deny_names=('name', '__', 'roles', 'domains', '_getPassword', deny_names=('name', '__', 'roles', 'domains', '_getPassword',
'authenticate', '_shared_roles') 'authenticate')
if name in deny_names: if name in deny_names:
return 0 return 0
return 1 return 1
...@@ -128,29 +128,6 @@ class BasicUser(Implicit): ...@@ -128,29 +128,6 @@ class BasicUser(Implicit):
return result and domainSpecMatch(domains, request) return result and domainSpecMatch(domains, request)
return result return result
def _shared_roles(self, parent):
r=[]
while 1:
if hasattr(parent, '__roles__'):
roles = parent.__roles__
if roles is None:
return 'Anonymous',
if 'Shared' in roles:
roles=list(roles)
roles.remove('Shared')
r = r + roles
else:
try:
return r + list(roles)
except:
return r
if getattr(parent, '__parent__', None) is not None:
while hasattr(parent.aq_self, 'aq_self'):
parent = parent.aq_self
parent = aq_parent(parent)
else:
return r
def _check_context(self, object): def _check_context(self, object):
# Check that 'object' exists in the acquisition context of # Check that 'object' exists in the acquisition context of
# the parent of the acl_users object containing this user, # the parent of the acl_users object containing this user,
...@@ -188,14 +165,6 @@ class BasicUser(Implicit): ...@@ -188,14 +165,6 @@ class BasicUser(Implicit):
if self._check_context(object): if self._check_context(object):
return 1 return 1
# Check for ancient role data up front, convert if found.
# This should almost never happen, and should probably be
# deprecated at some point.
if 'Shared' in object_roles:
object_roles = self._shared_roles(object)
if object_roles is None or 'Anonymous' in object_roles:
return 1
# Check for a role match with the normal roles given to # Check for a role match with the normal roles given to
# the user, then with local roles only if necessary. We # the user, then with local roles only if necessary. We
# want to avoid as much overhead as possible. # want to avoid as much overhead as possible.
...@@ -211,6 +180,7 @@ class BasicUser(Implicit): ...@@ -211,6 +180,7 @@ class BasicUser(Implicit):
# we can incur only the overhead required to find a match. # we can incur only the overhead required to find a match.
inner_obj = getattr(object, 'aq_inner', object) inner_obj = getattr(object, 'aq_inner', object)
userid = self.getId() userid = self.getId()
parents = set()
while 1: while 1:
local_roles = getattr(inner_obj, '__ac_local_roles__', None) local_roles = getattr(inner_obj, '__ac_local_roles__', None)
if local_roles: if local_roles:
...@@ -226,16 +196,19 @@ class BasicUser(Implicit): ...@@ -226,16 +196,19 @@ class BasicUser(Implicit):
inner = getattr(inner_obj, 'aq_inner', inner_obj) inner = getattr(inner_obj, 'aq_inner', inner_obj)
parent = getattr(inner, '__parent__', None) parent = getattr(inner, '__parent__', None)
if parent is not None: if parent is not None:
if parent in parents:
break
parents.add(parent)
inner_obj = parent inner_obj = parent
continue continue
if hasattr(inner_obj, 'im_self'): if hasattr(inner_obj, 'im_self'):
inner_obj=inner_obj.im_self inner_obj = inner_obj.im_self
inner_obj=getattr(inner_obj, 'aq_inner', inner_obj) inner_obj = getattr(inner_obj, 'aq_inner', inner_obj)
continue continue
break break
return None return None
domains=[] domains = []
def has_role(self, roles, object=None): def has_role(self, roles, object=None):
"""Check if the user has at least one role from a list of roles. """Check if the user has at least one role from a list of roles.
...@@ -459,14 +432,18 @@ def domainSpecMatch(spec, request): ...@@ -459,14 +432,18 @@ def domainSpecMatch(spec, request):
if not host: if not host:
try: try:
host=socket.gethostbyaddr(addr)[0] host = socket.gethostbyaddr(addr)[0]
except: except Exception:
pass pass
if not addr: if not addr:
try: try:
addr=socket.gethostbyname(host) addr = socket.gethostbyname(host)
except: except Exception:
pass # always define localhost, even if the underlying system
# doesn't know about it, this fixes tests on travis
if host == 'localhost':
addr = '127.0.0.1'
_host = host.split('.') _host = host.split('.')
_addr = addr.split('.') _addr = addr.split('.')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment