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 *
......
This diff is collapsed.
[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
This diff is collapsed.
...@@ -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