Commit d2b68599 authored by Hanno Schlichting's avatar Hanno Schlichting

Use the external AccessControl distribution

parent ccc10355
......@@ -36,6 +36,7 @@ scripts = zopepy
recipe = zc.recipe.testrunner
eggs =
Zope2
AccessControl
Acquisition
DateTime
ExtensionClass
......
......@@ -31,15 +31,6 @@ setup(name='Zope2',
package_dir={'': 'src'},
ext_modules=[
# AccessControl
Extension(
name='AccessControl.cAccessControl',
include_dirs=['include', 'src'],
sources=['src/AccessControl/cAccessControl.c'],
depends=['include/ExtensionClass/ExtensionClass.h',
'include/Acquisition/Acquisition.h']),
# DocumentTemplate
Extension(
name='DocumentTemplate.cDocumentTemplate',
......@@ -58,6 +49,7 @@ setup(name='Zope2',
],
install_requires=[
'AccessControl',
'Acquisition',
'DateTime',
'ExtensionClass',
......
Security Architecture
---------------------
Users
-----
Objects representing users may be created in Principia
User Folder objects. User objects maintain the information
used to authenticate users, and allow roles to be associated
with a user.
Permissions
-----------
A "permission" is the smallest unit of access to an object,
roughly equivalent to the atomic permissions seen in NT:
R (Read), W(Write), X(Execute), etc. In Principia, a permission
usually describes a fine-grained logical operation on an object,
such as "View Management Screens", "Add Properties", etc.
Different types of objects will define different permissions
as appropriate for the object.
Types of access
---------------
A "type of access" is a named grouping of 0 or more of the
permissions defined by an object. All objects have one predefined
type of access called Full Access (all permissions defined by that
object). A user who has the special role "Manager" always has Full
Access to all objects at or below the level in the object hierarchy
at which the user is defined.
New types of access may be defined as combinations of the
various permissions defined by a given object. These new
types of access may be defined by the programmer, or by
users at runtime.
Roles
-----
A role is a name that ties users (authentication of identity)
to permissions (authorization for that identity) in the system.
Roles may be defined in any Folder (or Folderish) object in the
system. Sub folders can make use of roles defined higher in the
hierarchy. These roles can be assigned to users. All users,
including non-authenticated users have the built-in role of
"Anonymous".
Principia objects allow the association of defined roles
with a single "type of access" each, in the context of that
object. A single role is associated with one and only one
type of access in the context of a given object.
Examples
--------
User Object1
o has the role "RoleA" o has given "RoleA" Full Access
Result: the user has Full Access to Object1.
User Object2
o has the role "RoleA" o has given "RoleB" Full Access
o has given the role "RoleA" View Access,
a custom type of access that allows only
viewing of the object.
Result: the user has only View Access.
Notes
-----
All objects define a permission called "Default permission". If this
permission is given to a role, users with that role will be able to
access subobjects which do not explicitly restrict access.
Technical
---------
Objects define their permissions as logical operations.
Programmers have to determine the appropriate operations
for their object type, and provide a mapping of permission
name to attribute names. It is important to note that permissions
cannot overlap - none of the attributes named in a permission
can occur in any of the other permissions. The following are
proposed permissions for some current principia objects:
Folder
o View management screens
o Change permissions
o Undo changes
o Add objects
o Delete objects
o Add properties
o Change properties
o Delete properties
o Default permission
Confera Topic
o View management screens
o Change permissions
o Undo changes
o Add objects
o Delete objects
o Add properties
o Change properties
o Delete properties
o Default permission
o Change Configuration
o Add Messages
o Change Messages
o Delete Messages
Tabula Collection
o View management screens
o Change permissions
o Undo changes
o Add objects
o Delete objects
o Add properties
o Change properties
o Delete properties
o Default permission
o Change schema
o Upload data
o Add computed fields
o Change computed fields
o Delete computed fields
Document/Image/File
o View management screens
o Change permissions
o Change/upload data
o View
Session
o View management screens
o Change permissions
o Change session config
o Join/leave session
o Save/discard session
Mail Host
o View management screens
o Change permissions
o Change configuration
To support the architecture, developers must derive an
object from the AccessControl.rolemanager.RoleManager mixin class,
and define in their class an __ac_permissions__ attribute.
This should be a tuple of tuples, where each tuple represents
a permission and contains a string permission name as its first
element and a list of attribute names as its second element.
Example:
__ac_permissions__=(
('View management screens',
['manage','manage_menu','manage_main','manage_copyright',
'manage_tabs','manage_propertiesForm','manage_UndoForm']),
('Undo changes', ['manage_undo_transactions']),
('Change permissions', ['manage_access']),
('Add objects', ['manage_addObject']),
('Delete objects', ['manage_delObjects']),
('Add properties', ['manage_addProperty']),
('Change properties', ['manage_editProperties']),
('Delete properties', ['manage_delProperties']),
('Default permission', ['']),
)
The developer may also predefine useful types of access, by
specifying an __ac_types__ attribute. This should be a tuple of
tuples, where each tuple represents a type of access and contains
a string name as its first element and a list of permission names
as its second element.
By default, only "Full Access" is defined (by the RoleManager mixin).
If you wish to override __ac_types__ to provide convenient types of
access, you must always be sure to define "Full Access" as containing
the names of all possible permissions for your object.
Example:
__ac_types__=(
('Full Access', map(lambda x: x[0], __ac_permissions__)),
('Change', ['Add Objects', 'Add Properties', 'Change Properties']),
)
Developers may also provide pre-defined role names that are
not deletable via the interface by specifying an __ac_roles__
attribute. This is probably not something we'll ever use under
the new architecture, but it's there if you need it.
Example:
__ac_roles__=('Manager', 'Anonymous')
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__version__='$Revision: 1.9 $'[11:-2]
try:
from hashlib import sha1 as sha
except:
from sha import new as sha
import binascii
from binascii import b2a_base64, a2b_base64
from random import choice, randrange
class PasswordEncryptionScheme: # An Interface
def encrypt(pw):
"""
Encrypt the provided plain text password.
"""
def validate(reference, attempt):
"""
Validate the provided password string. Reference is the
correct password, which may be encrypted; attempt is clear text
password attempt.
"""
_schemes = []
def registerScheme(id, s):
'''
Registers an LDAP password encoding scheme.
'''
_schemes.append((id, '{%s}' % id, s))
def listSchemes():
r = []
for id, prefix, scheme in _schemes:
r.append(id)
return r
class SSHADigestScheme:
'''
SSHA is a modification of the SHA digest scheme with a salt
starting at byte 20 of the base64-encoded string.
'''
# Source: http://developer.netscape.com/docs/technote/ldap/pass_sha.html
def generate_salt(self):
# Salt can be any length, but not more than about 37 characters
# because of limitations of the binascii module.
# 7 is what Netscape's example used and should be enough.
# All 256 characters are available.
salt = ''
for n in range(7):
salt += chr(randrange(256))
return salt
def encrypt(self, pw):
pw = str(pw)
salt = self.generate_salt()
return b2a_base64(sha(pw + salt).digest() + salt)[:-1]
def validate(self, reference, attempt):
try:
ref = a2b_base64(reference)
except binascii.Error:
# Not valid base64.
return 0
salt = ref[20:]
compare = b2a_base64(sha(attempt + salt).digest() + salt)[:-1]
return (compare == reference)
registerScheme('SSHA', SSHADigestScheme())
class SHADigestScheme:
def encrypt(self, pw):
return b2a_base64(sha(pw).digest())[:-1]
def validate(self, reference, attempt):
compare = b2a_base64(sha(attempt).digest())[:-1]
return (compare == reference)
registerScheme('SHA', SHADigestScheme())
# Bogosity on various platforms due to ITAR restrictions
try:
from crypt import crypt
except ImportError:
crypt = None
if crypt is not None:
class CryptDigestScheme:
def generate_salt(self):
choices = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789./")
return choice(choices) + choice(choices)
def encrypt(self, pw):
return crypt(pw, self.generate_salt())
def validate(self, reference, attempt):
a = crypt(attempt, reference[:2])
return (a == reference)
registerScheme('CRYPT', CryptDigestScheme())
class MySQLDigestScheme:
def encrypt(self, pw):
nr = 1345345333L
add = 7
nr2 = 0x12345671L
for i in pw:
if i == ' ' or i == '\t':
continue
nr ^= (((nr & 63) + add) * ord(i)) + (nr << 8)
nr2 += (nr2 << 8) ^ nr
add += ord(i)
r0 = nr & ((1L << 31) - 1L)
r1 = nr2 & ((1L << 31) - 1L)
return "%08lx%08lx" % (r0, r1)
def validate(self, reference, attempt):
a = self.encrypt(attempt)
return (a == reference)
registerScheme('MYSQL', MySQLDigestScheme())
def pw_validate(reference, attempt):
"""Validate the provided password string, which uses LDAP-style encoding
notation. Reference is the correct password, attempt is clear text
password attempt."""
for id, prefix, scheme in _schemes:
lp = len(prefix)
if reference[:lp] == prefix:
return scheme.validate(reference[lp:], attempt)
# Assume cleartext.
return (reference == attempt)
def is_encrypted(pw):
for id, prefix, scheme in _schemes:
lp = len(prefix)
if pw[:lp] == prefix:
return 1
return 0
def pw_encrypt(pw, encoding='SSHA'):
"""Encrypt the provided plain text password using the encoding if provided
and return it in an LDAP-style representation."""
for id, prefix, scheme in _schemes:
if encoding == id:
return prefix + scheme.encrypt(pw)
raise ValueError, 'Not supported: %s' % encoding
pw_encode = pw_encrypt # backward compatibility
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Add security system support to Document Templates
"""
from zope.deferredimport import deprecated
deprecated("Please import from DocumentTemplate.security",
DTMLSecurityAPI = 'DocumentTemplate.security:DTMLSecurityAPI',
RestrictedDTML = 'DocumentTemplate.security:RestrictedDTML',
)
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""C implementation of the access control machinery."""
try:
from AccessControl.cAccessControl import rolesForPermissionOn
from AccessControl.cAccessControl import PermissionRole
from AccessControl.cAccessControl import imPermissionRole
from AccessControl.cAccessControl import _what_not_even_god_should_do
from AccessControl.cAccessControl import aq_validate
from AccessControl.cAccessControl import guarded_getattr
from AccessControl.cAccessControl import setDefaultBehaviors
from AccessControl.cAccessControl import ZopeSecurityPolicy \
as cZopeSecurityPolicy
from AccessControl.cAccessControl import SecurityManager \
as cSecurityManager
except ImportError:
import sys
# make sure a partial import doesn't pollute sys.modules
del sys.modules[__name__]
raise
from AccessControl.ImplPython import SecurityManager
from AccessControl.ImplPython import ZopeSecurityPolicy
class ZopeSecurityPolicy(cZopeSecurityPolicy, ZopeSecurityPolicy):
"""A security manager provides methods for checking access and managing
executable context and policies
"""
class SecurityManager(cSecurityManager, SecurityManager):
"""A security manager provides methods for checking access and managing
executable context and policies
"""
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Python implementation of the access control machinery."""
import os
import string
from logging import getLogger
from Acquisition import aq_acquire
from Acquisition import aq_base
from Acquisition import aq_inner
from Acquisition import aq_inContextOf
from Acquisition import aq_parent
from ExtensionClass import Base
from zope.interface import implements
# This is used when a permission maps explicitly to no permission. We
# try and get this from cAccessControl first to make sure that if both
# security implementations exist, we can switch between them later.
try:
from cAccessControl import _what_not_even_god_should_do
except ImportError:
_what_not_even_god_should_do = []
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.unauthorized import Unauthorized
from AccessControl.interfaces import ISecurityPolicy
from AccessControl.interfaces import ISecurityManager
from AccessControl.SimpleObjectPolicies import Containers
from AccessControl.SimpleObjectPolicies import _noroles
from AccessControl.ZopeGuards import guarded_getitem
LOG = getLogger('ImplPython')
# AccessControl.PermissionRole
# ----------------------------
_ident_chars = string.ascii_letters + string.digits + "_"
name_trans = filter(lambda c, an=_ident_chars: c not in an,
map(chr, range(256)))
name_trans = string.maketrans(''.join(name_trans), '_' * len(name_trans))
_default_roles = ('Manager',)
# If _embed_permission_in_roles is enabled, computed __roles__
# attributes will often include a special role that encodes the name
# of the permission from which the roles were derived. This is useful
# for verbose security exceptions.
_embed_permission_in_roles = 0
def rolesForPermissionOn(perm, object, default=_default_roles, n=None):
"""Return the roles that have the given permission on the given object
"""
n = n or '_' + string.translate(perm, name_trans) + "_Permission"
r = None
while 1:
if hasattr(object, n):
roles = getattr(object, n)
if roles is None:
if _embed_permission_in_roles:
return ('Anonymous', n)
return 'Anonymous',
t = type(roles)
if t is tuple:
# If we get a tuple, then we don't acquire
if r is None:
if _embed_permission_in_roles:
return roles + (n,)
return roles
if _embed_permission_in_roles:
return r + list(roles) + [n]
return r + list(roles)
if t is str:
# We found roles set to a name. Start over
# with the new permission name. If the permission
# name is '', then treat as private!
if roles:
n = roles
else:
return _what_not_even_god_should_do
elif roles:
if r is None:
r = list(roles)
else:
r = r + list(roles)
object = aq_inner(object)
if object is None:
break
object = aq_parent(object)
if r is None:
if _embed_permission_in_roles:
if default:
if isinstance(default, tuple):
return default + (n,)
else:
return default + [n]
else:
return [n]
return default
if _embed_permission_in_roles:
return r + [n]
return r
class PermissionRole(Base):
"""Implement permission-based roles.
Under normal circumstances, our __of__ method will be
called with an unwrapped object. The result will then be called
with a wrapped object, if the original object was wrapped.
To deal with this, we have to create an intermediate object.
"""
def __init__(self, name, default=('Manager',)):
self.__name__ = name
self._p = '_' + string.translate(name, name_trans) + "_Permission"
self._d = self.__roles__ = default
def __of__(self, parent):
r = imPermissionRole()
r._p = self._p
r._pa = parent
r._d = self._d
p = getattr(parent, 'aq_inner', None)
if p is not None:
return r.__of__(p)
else:
return r
def rolesForPermissionOn(self, value):
return rolesForPermissionOn(None, value, self._d, self._p)
class imPermissionRole(Base):
"""Implement permission-based roles"""
def __of__(self, value):
return rolesForPermissionOn(None, value, self._d, self._p)
rolesForPermissionOn = __of__
# The following methods are needed in the unlikely case that an unwrapped
# object is accessed:
def __getitem__(self, i):
try:
v = self._v
except:
v = self._v = self.__of__(self._pa)
del self._pa
return v[i]
def __len__(self):
try:
v = self._v
except:
v = self._v = self.__of__(self._pa)
del self._pa
return len(v)
# AccessControl.ZopeSecurityPolicy
# --------------------------------
#
# TODO: implement this in cAccessControl, and have Implementation
# do the indirection.
#
from AccessControl.ZopeSecurityPolicy import getRoles # XXX
class ZopeSecurityPolicy:
implements(ISecurityPolicy)
def __init__(self, ownerous=1, authenticated=1, verbose=0):
"""Create a Zope security policy.
Optional arguments may be provided:
ownerous -- Untrusted users can create code
(e.g. Python scripts or templates),
so check that code owners can access resources.
The argument must have a truth value.
The default is true.
authenticated -- Allow access to resources based on the
privaledges of the authenticated user.
The argument must have a truth value.
The default is true.
This (somewhat experimental) option can be set
to false on sites that allow only public
(unauthenticated) access. An anticipated
scenario is a ZEO configuration in which some
clients allow only public access and other
clients allow full management.
verbose -- Include debugging information in Unauthorized
exceptions. Not suitable for public sites.
"""
self._ownerous = ownerous
self._authenticated = authenticated
self._verbose = verbose
def validate(self, accessed, container, name, value, context,
roles=_noroles, getattr=getattr, _noroles=_noroles,
valid_aq_=('aq_parent','aq_inner', 'aq_explicit')):
############################################################
# Provide special rules for the acquisition attributes
if isinstance(name, str):
if name.startswith('aq_') and name not in valid_aq_:
if self._verbose:
raiseVerbose(
'aq_* names (other than %s) are not allowed'
% ', '.join(valid_aq_),
accessed, container, name, value, context
)
raise Unauthorized(name, value)
containerbase = aq_base(container)
accessedbase = aq_base(accessed)
if accessedbase is accessed:
# accessed is not a wrapper, so assume that the
# value could not have been acquired.
accessedbase = container
############################################################
# If roles weren't passed in, we'll try to get them from the object
if roles is _noroles:
roles = getRoles(container, name, value, _noroles)
############################################################
# We still might not have any roles
if roles is _noroles:
############################################################
# We have an object without roles and we didn't get a list
# of roles passed in. Presumably, the value is some simple
# object like a string or a list. We'll try to get roles
# from its container.
if container is None:
# Either container or a list of roles is required
# for ZopeSecurityPolicy to know whether access is
# allowable.
if self._verbose:
raiseVerbose(
'No container provided',
accessed, container, name, value, context)
raise Unauthorized(name, value)
roles = getattr(container, '__roles__', roles)
if roles is _noroles:
if containerbase is container:
# Container is not wrapped.
if containerbase is not accessedbase:
if self._verbose:
raiseVerbose(
'Unable to find __roles__ in the container '
'and the container is not wrapped',
accessed, container, name, value, context)
raise Unauthorized(name, value)
else:
# Try to acquire roles
try: roles = aq_acquire(container, '__roles__')
except AttributeError:
if containerbase is not accessedbase:
if self._verbose:
raiseVerbose(
'Unable to find or acquire __roles__ '
'from the container',
accessed, container, name, value, context)
raise Unauthorized(name, value)
# We need to make sure that we are allowed to
# get unprotected attributes from the container. We are
# allowed for certain simple containers and if the
# container says we can. Simple containers
# may also impose name restrictions.
p = Containers(type(container), None)
if p is None:
p = getattr(container,
'__allow_access_to_unprotected_subobjects__',
None)
if p is not None:
if not isinstance(p, int): # catches bool too
if isinstance(p, dict):
if isinstance(name, basestring):
p = p.get(name)
else:
p = 1
else:
p = p(name, value)
if not p:
if self._verbose:
raiseVerbose(
'The container has no security assertions',
accessed, container, name, value, context)
raise Unauthorized(name, value)
if roles is _noroles:
return 1
# We are going to need a security-aware object to pass
# to allowed(). We'll use the container.
value = container
# Short-circuit tests if we can:
try:
if roles is None or 'Anonymous' in roles:
return 1
except TypeError:
# 'roles' isn't a sequence
LOG.error("'%s' passed as roles"
" during validation of '%s' is not a sequence." % (
`roles`, name))
raise
# Check executable security
stack = context.stack
if stack:
eo = stack[-1]
# If the executable had an owner, can it execute?
if self._ownerous:
owner = eo.getOwner()
if (owner is not None) and not owner.allowed(value, roles):
# We don't want someone to acquire if they can't
# get an unacquired!
if self._verbose:
if len(roles) < 1:
raiseVerbose(
"The object is marked as private",
accessed, container, name, value, context)
elif userHasRolesButNotInContext(owner, value, roles):
raiseVerbose(
"The owner of the executing script is defined "
"outside the context of the object being "
"accessed",
accessed, container, name, value, context,
required_roles=roles, eo_owner=owner, eo=eo)
else:
raiseVerbose(
"The owner of the executing script does not "
"have the required permission",
accessed, container, name, value, context,
required_roles=roles, eo_owner=owner, eo=eo,
eo_owner_roles=getUserRolesInContext(
owner, value))
raise Unauthorized(name, value)
# Proxy roles, which are a lot safer now.
proxy_roles = getattr(eo, '_proxy_roles', None)
if proxy_roles:
# Verify that the owner actually can state the proxy role
# in the context of the accessed item; users in subfolders
# should not be able to use proxy roles to access items
# above their subfolder!
owner = eo.getWrappedOwner()
if owner is not None:
if container is not containerbase:
# Unwrapped objects don't need checking
if not owner._check_context(container):
# container is higher up than the owner,
# deny access
if self._verbose:
raiseVerbose(
"The owner of the executing script is "
"defined outside the context of the "
"object being accessed. The script has "
"proxy roles, but they do not apply in "
"this context.",
accessed, container, name, value, context,
required_roles=roles, eo_owner=owner,
eo=eo)
raise Unauthorized(name, value)
for r in proxy_roles:
if r in roles:
return 1
# Proxy roles actually limit access!
if self._verbose:
if len(roles) < 1:
raiseVerbose(
"The object is marked as private",
accessed, container, name, value, context)
else:
raiseVerbose(
"The proxy roles set on the executing script "
"do not allow access",
accessed, container, name, value, context,
eo=eo, eo_proxy_roles=proxy_roles,
required_roles=roles)
raise Unauthorized(name, value)
try:
if self._authenticated and context.user.allowed(value, roles):
return 1
except AttributeError:
pass
if self._verbose:
if len(roles) < 1:
raiseVerbose(
"The object is marked as private",
accessed, container, name, value, context)
elif not self._authenticated:
raiseVerbose(
"Authenticated access is not allowed by this "
"security policy",
accessed, container, name, value, context)
elif userHasRolesButNotInContext(context.user, value, roles):
raiseVerbose(
"Your user account is defined outside "
"the context of the object being accessed",
accessed, container, name, value, context,
required_roles=roles, user=context.user)
else:
raiseVerbose(
"Your user account does not "
"have the required permission",
accessed, container, name, value, context,
required_roles=roles, user=context.user,
user_roles=getUserRolesInContext(context.user, value))
raise Unauthorized(name, value)
def checkPermission(self, permission, object, context):
roles = rolesForPermissionOn(permission, object)
if isinstance(roles, basestring):
roles = [roles]
# check executable owner and proxy roles
stack = context.stack
if stack:
eo = stack[-1]
# If the executable had an owner, can it execute?
if self._ownerous:
owner = eo.getOwner()
if (owner is not None) and not owner.allowed(object, roles):
# We don't want someone to acquire if they can't
# get an unacquired!
return 0
proxy_roles = getattr(eo, '_proxy_roles', None)
if proxy_roles:
# Verify that the owner actually can state the proxy role
# in the context of the accessed item; users in subfolders
# should not be able to use proxy roles to access items
# above their subfolder!
owner = eo.getWrappedOwner()
if owner is not None:
if object is not aq_base(object):
if not owner._check_context(object):
# object is higher up than the owner,
# deny access
return 0
for r in proxy_roles:
if r in roles:
return 1
return 0
return context.user.allowed(object, roles)
# AccessControl.SecurityManager
# -----------------------------
# There is no corresponding control in the C implementation of the
# access control machinery (cAccessControl.c); this should probably go
# away in a future version. If you're concerned about the size of
# security stack, you probably have bigger problems.
#
try: max_stack_size = int(os.environ.get('Z_MAX_STACK_SIZE','100'))
except: max_stack_size = 100
def setDefaultBehaviors(ownerous, authenticated, verbose):
global _defaultPolicy
global _embed_permission_in_roles
_defaultPolicy = ZopeSecurityPolicy(
ownerous=ownerous,
authenticated=authenticated,
verbose=verbose)
_embed_permission_in_roles = verbose
setDefaultBehaviors(True, True, False)
class SecurityManager:
"""A security manager provides methods for checking access and managing
executable context and policies
"""
implements(ISecurityManager)
__allow_access_to_unprotected_subobjects__ = {
'validate': 1, 'checkPermission': 1,
'getUser': 1, 'calledByExecutable': 1
}
def __init__(self, thread_id, context):
self._thread_id = thread_id
self._context = context
self._policy = _defaultPolicy
def validate(self, accessed=None, container=None, name=None, value=None,
roles=_noroles):
"""Validate access.
Arguments:
accessed -- the object that was being accessed
container -- the object the value was found in
name -- The name used to access the value
value -- The value retrieved though the access.
roles -- The roles of the object if already known.
The arguments may be provided as keyword arguments. Some of these
arguments may be ommitted, however, the policy may reject access
in some cases when arguments are ommitted. It is best to provide
all the values possible.
"""
policy = self._policy
if roles is _noroles:
return policy.validate(accessed, container, name, value,
self._context)
else:
return policy.validate(accessed, container, name, value,
self._context, roles)
def DTMLValidate(self, accessed=None, container=None, name=None,
value=None, md=None):
"""Validate access.
* THIS EXISTS FOR DTML COMPATIBILITY *
Arguments:
accessed -- the object that was being accessed
container -- the object the value was found in
name -- The name used to access the value
value -- The value retrieved though the access.
md -- multidict for DTML (ignored)
The arguments may be provided as keyword arguments. Some of these
arguments may be ommitted, however, the policy may reject access
in some cases when arguments are ommitted. It is best to provide
all the values possible.
"""
policy = self._policy
return policy.validate(accessed, container, name, value, self._context)
def checkPermission(self, permission, object):
"""Check whether the security context allows the given permission on
the given object.
Arguments:
permission -- A permission name
object -- The object being accessed according to the permission
"""
policy = self._policy
return policy.checkPermission(permission, object, self._context)
def addContext(self, anExecutableObject,
getattr=getattr):
"""Add an ExecutableObject to the current security
context. Optionally, add a new SecurityPolicy as well.
"""
stack = self._context.stack
if len(stack) > max_stack_size:
raise SystemError, 'Excessive recursion'
stack.append(anExecutableObject)
p = getattr(anExecutableObject, '_customSecurityPolicy', None)
if p is not None:
p = p()
else:
p = _defaultPolicy
self._policy = p
def removeContext(self, anExecutableObject):
"""Remove an ExecutableObject, and optionally, a
SecurityPolicy, from the current security context.
"""
stack = self._context.stack
if not stack:
return
top = stack[-1]
if top is anExecutableObject:
del stack[-1]
else:
indexes = range(len(stack))
indexes.reverse()
for i in indexes:
top = stack[i]
if top is anExecutableObject:
del stack[i:]
break
else:
return
if stack:
top = stack[-1]
p = getattr(top, '_customSecurityPolicy', None)
if p is not None:
p = p()
else:
p = _defaultPolicy
self._policy = p
else:
self._policy = _defaultPolicy
def getUser(self):
"""Get the current authenticated user"""
return self._context.user
def calledByExecutable(self):
"""Return a boolean value indicating if this context was called
by an executable"""
return len(self._context.stack)
# AccessControl.ZopeGuards
# ------------------------
def aq_validate(inst, object, name, v, validate):
return validate(inst, object, name, v)
_marker = object()
def guarded_getattr(inst, name, default=_marker):
"""Retrieves an attribute, checking security in the process.
Raises Unauthorized if the attribute is found but the user is
not allowed to access the attribute.
"""
if name[:1] == '_':
raise Unauthorized, name
# Try to get the attribute normally so that unusual
# exceptions are caught early.
try:
v = getattr(inst, name)
except AttributeError:
if default is not _marker:
return default
raise
try:
container = v.im_self
except AttributeError:
container = aq_parent(aq_inner(v)) or inst
assertion = Containers(type(container))
if isinstance(assertion, dict):
# We got a table that lets us reason about individual
# attrs
assertion = assertion.get(name)
if assertion:
# There's an entry, but it may be a function.
if callable(assertion):
return assertion(inst, name)
# Nope, it's boolean
return v
raise Unauthorized, name
if assertion:
if callable(assertion):
factory = assertion(name, v)
if callable(factory):
return factory(inst, name)
assert factory == 1
else:
assert assertion == 1
return v
# See if we can get the value doing a filtered acquire.
# aq_acquire will either return the same value as held by
# v or it will return an Unauthorized raised by validate.
validate = getSecurityManager().validate
aq_acquire(inst, name, aq_validate, validate)
return v
# Helpers for verbose authorization exceptions
# --------------------------------------------
def item_repr(ob):
"""Generates a repr without angle brackets (to avoid HTML quoting)"""
return repr(ob).replace('<', '(').replace('>', ')')
def simplifyRoles(roles):
"""Sorts and removes duplicates from a role list."""
d = {}
for r in roles:
d[r] = 1
lst = d.keys()
lst.sort()
return lst
def raiseVerbose(msg, accessed, container, name, value, context,
required_roles=None,
user_roles=None,
user=None,
eo=None,
eo_owner=None,
eo_owner_roles=None,
eo_proxy_roles=None,
):
"""Raises an Unauthorized error with a verbose explanation."""
s = '%s. Access to %s of %s' % (
msg, repr(name), item_repr(container))
if aq_base(container) is not aq_base(accessed):
s += ', acquired through %s,' % item_repr(accessed)
info = [s + ' denied.']
if user is not None:
try:
ufolder = '/'.join(aq_parent(aq_inner(user)).getPhysicalPath())
except:
ufolder = '(unknown)'
info.append('Your user account, %s, exists at %s.' % (
str(user), ufolder))
if required_roles is not None:
p = None
required_roles = list(required_roles)
for r in required_roles:
if r.startswith('_') and r.endswith('_Permission'):
p = r[1:]
required_roles.remove(r)
break
sr = simplifyRoles(required_roles)
if p:
# got a permission name
info.append('Access requires %s, '
'granted to the following roles: %s.' %
(p, sr))
else:
# permission name unknown
info.append('Access requires one of the following roles: %s.'
% sr)
if user_roles is not None:
info.append(
'Your roles in this context are %s.' % simplifyRoles(user_roles))
if eo is not None:
s = 'The executing script is %s' % item_repr(eo)
if eo_proxy_roles is not None:
s += ', with proxy roles: %s' % simplifyRoles(eo_proxy_roles)
if eo_owner is not None:
s += ', owned by %s' % repr(eo_owner)
if eo_owner_roles is not None:
s += ', who has the roles %s' % simplifyRoles(eo_owner_roles)
info.append(s + '.')
text = ' '.join(info)
LOG.debug('Unauthorized: %s' % text)
raise Unauthorized(text)
def getUserRolesInContext(user, context):
"""Returns user roles for a context."""
if hasattr(aq_base(user), 'getRolesInContext'):
return user.getRolesInContext(context)
else:
return ()
def userHasRolesButNotInContext(user, object, object_roles):
'''Returns 1 if the user has any of the listed roles but
is not defined in a context which is not an ancestor of object.
'''
if object_roles is None or 'Anonymous' in object_roles:
return 0
usr_roles = getUserRolesInContext(user, object)
for role in object_roles:
if role in usr_roles:
# User has the roles.
return (not verifyAcquisitionContext(
user, object, object_roles))
return 0
def verifyAcquisitionContext(user, object, object_roles=None):
"""Mimics the relevant section of User.allowed().
Returns true if the object is in the context of the user's user folder.
"""
ufolder = aq_parent(user)
ucontext = aq_parent(ufolder)
if ucontext is not None:
if object is None:
# This is a strange rule, though
# it doesn't cause any security holes. SDH
return 1
if hasattr(object, 'im_self'):
# This is a method. Grab its self.
object=object.im_self
if not aq_inContextOf(object, ucontext, 1):
if 'Shared' in object_roles:
# Old role setting. Waaa
object_roles=user._shared_roles(object)
if 'Anonymous' in object_roles:
return 1
return None
# Note that if the user were not wrapped, it would
# not be possible to determine the user's context
# and this method would return 1.
# However, as long as user folders always return
# wrapped user objects, this is safe.
return 1
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Controller that can switch between security machinery implementations.
This module allows configuration of the security implementation after
the initial import of the modules. It is intended to allow runtime
selection of the machinery based on Zope's configuration file.
The helper function defined here switches between the 'C' and 'PYTHON'
security implementations by loading the appropriate implementation
module and wiring the implementation into the other modules of the
AccessControl package that defined the various components before this
module was introduced.
"""
def getImplementationName():
"""Return the name of the implementation currently being used."""
return _implementation_name
def setImplementation(name):
"""Select the policy implementation to use. The 'name' must be either
'PYTHON' or 'C'. NOTE: this function is intended to be called
exactly once, so that the Zope config file can dictate the policy
implementation to be used. Subsequent calls to this function will
have no effect!!
"""
import sys
global _implementation_name
global _implementation_set
if _implementation_set:
return
name = name.upper()
if name == _implementation_name:
return
if name == "C":
from AccessControl import ImplC as impl
elif name == "PYTHON":
from AccessControl import ImplPython as impl
else:
raise ValueError("unknown policy implementation: %r" % name)
_implementation_name = name
for modname, names in _policy_names.items():
__import__(modname)
mod = sys.modules[modname]
for n in names:
setattr(mod, n, getattr(impl, n))
if hasattr(mod, "initialize"):
mod.initialize(impl)
from AccessControl.SecurityManager import setSecurityPolicy
policy = impl.ZopeSecurityPolicy(True, True)
setSecurityPolicy(policy)
_implementation_set = 1
_implementation_name = None
_implementation_set = 0
_policy_names = {
"AccessControl": ("setDefaultBehaviors",
),
"AccessControl.PermissionRole": ("_what_not_even_god_should_do",
"rolesForPermissionOn",
"PermissionRole",
"imPermissionRole",
),
"AccessControl.SecurityManagement": ("SecurityManager",
),
"AccessControl.SecurityManager": ("SecurityManager",
),
"AccessControl.ZopeGuards": ("aq_validate",
"guarded_getattr",
),
"AccessControl.ZopeSecurityPolicy": ("ZopeSecurityPolicy",
),
}
# start with the default, mostly because we need something for the tests
setImplementation("C")
# allow the implementation to change from the default
_implementation_set = 0
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Support for owned objects
"""
# BBB
from .owner import absattr
from .owner import EditUnowned
from .owner import EmergencyUserCannotOwn
from .owner import ownableFilter
from .owner import ownerInfo
from .owner import UnownableOwner
from zope.deferredimport import deprecated
deprecated("Owned is no longer part of AccessControl, please "
"depend on Zope2 and import from OFS.owner or use the "
"new minimal Owned class from AccessControl.owner.",
Owned = 'OFS.owner:Owned',
)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Permissions
"""
import string
from Acquisition import aq_base
name_trans=filter(lambda c, an=string.letters+string.digits+'_': c not in an,
map(chr, range(256)))
name_trans=string.maketrans(''.join(name_trans), '_'*len(name_trans))
def pname(name, translate=string.translate, name_trans=name_trans):
return '_'+translate(name, name_trans) + "_Permission"
_marker=[]
class Permission:
# A Permission maps a named logical permission to a set
# of attribute names. Attribute names which appear in a
# permission may not appear in any other permission defined
# by the object.
def __init__(self, name, data, obj, default=None):
self.name = name
self._p = '_' + string.translate(name, name_trans) + "_Permission"
self.data = data
self.obj = aq_base(obj)
self.default = default
def getRoles(self, default=_marker):
# Return the list of role names which have been given
# this permission for the object in question. To do
# this, we try to get __roles__ from all of the object
# attributes that this permission represents.
obj = self.obj
name = self._p
if hasattr(obj, name):
return getattr(obj, name)
roles = default
for name in self.data:
if name:
if hasattr(obj, name):
attr = getattr(obj, name)
if hasattr(attr, 'im_self'):
attr = attr.im_self
if hasattr(attr, '__dict__'):
attr = attr.__dict__
name = name + '__roles__'
if name in attr:
roles = attr[name]
break
elif hasattr(obj, '__dict__'):
attr = obj.__dict__
if '__roles__' in attr:
roles = attr['__roles__']
break
if roles:
try:
if 'Shared' not in roles:
return tuple(roles)
roles = list(roles)
roles.remove('Shared')
return roles
except:
return []
if roles is None:
return ['Manager', 'Anonymous']
if roles is _marker:
return ['Manager']
return roles
def setRoles(self, roles):
obj = self.obj
if isinstance(roles, list) and not roles:
if hasattr(obj, self._p):
delattr(obj, self._p)
else:
setattr(obj, self._p, roles)
for name in self.data:
if name=='':
attr = obj
else:
attr = getattr(obj, name)
try:
del attr.__roles__
except:
pass
try:
delattr(obj, name + '__roles__')
except:
pass
def setRole(self, role, present):
roles = self.getRoles()
if role in roles:
if present:
return
if isinstance(roles, list):
roles.remove(role)
else:
roles = list(roles)
roles.remove(role)
roles = tuple(roles)
elif not present:
return
else:
if isinstance(roles, list):
roles.append(role)
else:
roles=roles + (role, )
self.setRoles(roles)
def __len__(self):
return 1
def __str__(self):
return self.name
_registeredPermissions = {}
_ac_permissions = ()
def getPermissions():
return _ac_permissions
def addPermission(perm, default_roles=('Manager', )):
if perm in _registeredPermissions:
return
entry = ((perm, (), default_roles), )
global _ac_permissions
_ac_permissions = _ac_permissions + entry
_registeredPermissions[perm] = 1
mangled = pname(perm) # get mangled permission name
if not hasattr(ApplicationDefaultPermissions, mangled):
setattr(ApplicationDefaultPermissions, mangled, default_roles)
def registerPermissions(permissions, defaultDefault=('Manager', )):
"""Register an __ac_permissions__ sequence.
"""
for setting in permissions:
if setting[0] in _registeredPermissions:
continue
if len(setting)==2:
perm, methods = setting
default = defaultDefault
else:
perm, methods, default = setting
addPermission(perm, default)
class ApplicationDefaultPermissions:
_View_Permission = ('Manager', 'Anonymous')
_Access_contents_information_Permission = ('Manager', 'Anonymous')
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Permission Mapping
Sometimes, we need an object's permissions to be remapped to other permissions
when the object is used in special ways. This is rather hard, since we
need the object's ordinary permissions intact so we can manage it.
"""
from cgi import escape
from Acquisition import ImplicitAcquisitionWrapper
from ExtensionClass import Base
from zope.interface import implements
from AccessControl.class_init import InitializeClass
from AccessControl.interfaces import IPermissionMappingSupport
from AccessControl.owner import UnownableOwner
from AccessControl.Permission import pname
from AccessControl.requestmethod import requestmethod
class RoleManager:
implements(IPermissionMappingSupport)
# XXX: No security declarations?
def manage_getPermissionMapping(self):
"""Return the permission mapping for the object
This is a list of dictionaries with:
permission_name -- The name of the native object permission
class_permission -- The class permission the permission is
mapped to.
"""
wrapper=getattr(self, '_permissionMapper', None)
if wrapper is None: wrapper=PM()
perms={}
for p in self.possible_permissions():
perms[pname(p)]=p
r=[]
a=r.append
for ac_perms in self.ac_inherited_permissions(1):
p=perms.get(getPermissionMapping(ac_perms[0], wrapper), '')
a({'permission_name': ac_perms[0], 'class_permission': p})
return r
@requestmethod('POST')
def manage_setPermissionMapping(self,
permission_names=[],
class_permissions=[], REQUEST=None):
"""Change the permission mapping
"""
wrapper=getattr(self, '_permissionMapper', None)
if wrapper is None: wrapper=PM()
perms=self.possible_permissions()
for i in range(len(permission_names)):
name=permission_names[i]
p=class_permissions[i]
if p and (p not in perms):
__traceback_info__=perms, p, i
raise ValueError, (
"""Attempted to map a permission to a permission, %s,
that is not valid. This should never happen. (Waaa).
""" % escape(p))
setPermissionMapping(name, wrapper, p)
self._permissionMapper=wrapper
if REQUEST is not None:
return self.manage_access(
REQUEST,
manage_tabs_message='The permission mapping has been updated')
def _isBeingUsedAsAMethod(self, REQUEST =None, wannaBe=0):
try:
if hasattr(self, 'aq_self'):
r=self.aq_acquire('_isBeingUsedAsAMethod_')
else:
r=self._isBeingUsedAsAMethod_
except: r=0
if REQUEST is not None:
if not r != (not wannaBe): REQUEST.response.notFoundError()
return r
InitializeClass(RoleManager)
def getPermissionMapping(name, obj, st=type('')):
obj=getattr(obj, 'aq_base', obj)
name=pname(name)
r=getattr(obj, name, '')
if type(r) is not st: r=''
return r
def setPermissionMapping(name, obj, v):
name=pname(name)
if v: setattr(obj, name, pname(v))
elif obj.__dict__.has_key(name): delattr(obj, name)
class PM(Base):
_owner=UnownableOwner
_View_Permission='_View_Permission'
_is_wrapperish = 1
def __getattr__(self, name):
# We want to make sure that any non-explicitly set methods are
# private!
if name.startswith('_') and name.endswith("_Permission"): return ''
raise AttributeError, escape(name)
PermissionMapper=PM
def aqwrap(object, wrapper, parent):
r=Rewrapper()
r._ugh=wrapper, object, parent
return r
class Rewrapper(Base):
def __of__(self, parent):
w, m, p = self._ugh
return m.__of__(
ImplicitAcquisitionWrapper(
w, parent))
def __getattr__(self, name):
w, m, parent = self._ugh
self=m.__of__(
ImplicitAcquisitionWrapper(
w, parent))
return getattr(self, name)
def __call__(self, *args, **kw):
w, m, parent = self._ugh
self=m.__of__(
ImplicitAcquisitionWrapper(
w, parent))
return apply(self, args, kw)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''Objects that implement Permission-based roles.
'''
# The following names are inserted by AccessControl.Implementation:
#
# rolesForPermissionOn, PermissionRole, imPermissionRole,
# _what_not_even_god_should_do
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Constant definitions for built-in Zope permissions
"""
access_contents_information='Access contents information'
add_database_methods='Add Database Methods'
add_documents_images_and_files='Add Documents, Images, and Files'
add_external_methods='Add External Methods'
add_folders='Add Folders'
add_mailhost_objects='Add MailHost objects'
add_page_templates='Add Page Templates'
add_python_scripts='Add Python Scripts'
add_user_folders='Add User Folders'
add_vocabularies='Add Vocabularies'
add_z_gadfly_database_connections='Add Z Gadfly Database Connections'
add_zcatalogs='Add ZCatalogs'
add_zope_tutorials='Add Zope Tutorials'
change_database_connections='Change Database Connections'
change_database_methods='Change Database Methods'
change_external_methods='Change External Methods'
change_images_and_files='Change Images and Files'
change_python_scripts='Change Python Scripts'
change_configuration='Change configuration'
change_page_templates='Change Page Templates'
change_permissions='Change permissions'
change_proxy_roles='Change proxy roles'
copy_or_move='Copy or Move'
create_class_instances='Create class instances'
define_permissions='Define permissions'
delete_objects='Delete objects'
edit_factories='Edit Factories'
ftp_access='FTP access'
import_export_objects='Import/Export objects'
manage_vocabulary='Manage Vocabulary'
manage_zcatalog_entries='Manage ZCatalog Entries'
manage_zcatalog_indexes='Manage ZCatalogIndex Entries'
manage_properties='Manage properties'
manage_users='Manage users'
open_close_database_connection='Open/Close Database Connection'
open_close_database_connections='Open/Close Database Connections'
query_vocabulary='Query Vocabulary'
search_zcatalog='Search ZCatalog'
take_ownership='Take ownership'
test_database_connections='Test Database Connections'
undo_changes='Undo changes'
use_database_methods='Use Database Methods'
use_factories='Use Factories'
use_mailhost_services='Use mailhost services'
view='View'
view_history='View History'
view_management_screens='View management screens'
webdav_access='WebDAV access'
webdav_lock_items='WebDAV Lock items'
webdav_unlock_items='WebDAV Unlock items'
from zope.deferredimport import deprecated
new_loc = 'DocumentTemplate.permissions'
deprecated("Please import from %s" % new_loc,
change_dtml_documents = '%s:change_dtml_documents' % new_loc,
change_dtml_methods = '%s:change_dtml_methods' % new_loc,
)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Access control support
"""
# BBB
from .rolemanager import DEFAULTMAXLISTUSERS
from .rolemanager import _isBeingUsedAsAMethod
from .rolemanager import _isNotBeingUsedAsAMethod
from .rolemanager import reqattr
from .rolemanager import classattr
from .rolemanager import instance_dict
from .rolemanager import class_dict
from .rolemanager import instance_attrs
from .rolemanager import class_attrs
from .rolemanager import gather_permissions
from zope.deferredimport import deprecated
deprecated("RoleManager is no longer part of AccessControl, please "
"depend on Zope2 and import from OFS.role or use the new minimal "
"RoleManager class from AccessControl.rolemanager.",
RoleManager = 'OFS.role:RoleManager',
)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""SecurityInfo objects and access control constants.
SecurityInfo objects are used in class definitions to allow
a declarative style of associating access control information
with class attributes.
More information on using SecurityInfo and guide to Zope security
for developers can be found in the dev.zope.org "Declarative Security"
project:
http://dev.zope.org/Wikis/DevSite/Projects/DeclarativeSecurity
While SecurityInfo objects largely remove the need for Python
programmers to care about the underlying implementation, there
are several constants defined that should be used by code that
must set __roles__ attributes directly. (the constants are also
accessible from the AccessControl namespace). The defined access
control constants and their meanings are:
ACCESS_PUBLIC: accessible from restricted code and possibly
through the web (if object has a docstring)
ACCESS_PRIVATE: accessible only from python code
ACCESS_NONE: no access
"""
import sys
from logging import getLogger
from AccessControl.ImplPython import _what_not_even_god_should_do
from Acquisition import Implicit
LOG = getLogger('SecurityInfo')
# Security constants - these are imported into the AccessControl
# namespace and can be referenced as AccessControl.PUBLIC etc.
ACCESS_NONE = _what_not_even_god_should_do
ACCESS_PRIVATE = ()
ACCESS_PUBLIC = None
_marker = []
class SecurityInfo(Implicit):
"""Encapsulate security information."""
__security_info__ = 1
__roles__ = ACCESS_PRIVATE
def __init__(self):
self.names = {}
self.roles = {}
def _setaccess(self, names, access):
for name in names:
if self.names.get(name, access) != access:
LOG.warn('Conflicting security declarations for "%s"' % name)
self._warnings = 1
self.names[name] = access
declarePublic__roles__=ACCESS_PRIVATE
def declarePublic(self, name, *names):
"""Declare names to be publicly accessible."""
self._setaccess((name,) + names, ACCESS_PUBLIC)
declarePrivate__roles__=ACCESS_PRIVATE
def declarePrivate(self, name, *names):
"""Declare names to be inaccessible to restricted code."""
self._setaccess((name,) + names, ACCESS_PRIVATE)
declareProtected__roles__=ACCESS_PRIVATE
def declareProtected(self, permission_name, name, *names):
"""Declare names to be associated with a permission."""
self._setaccess((name,) + names, permission_name)
declareObjectPublic__roles__=ACCESS_PRIVATE
def declareObjectPublic(self):
"""Declare the object to be publicly accessible."""
self._setaccess(('',), ACCESS_PUBLIC)
declareObjectPrivate__roles__=ACCESS_PRIVATE
def declareObjectPrivate(self):
"""Declare the object to be inaccessible to restricted code."""
self._setaccess(('',), ACCESS_PRIVATE)
declareObjectProtected__roles__=ACCESS_PRIVATE
def declareObjectProtected(self, permission_name):
"""Declare the object to be associated with a permission."""
self._setaccess(('',), permission_name)
setPermissionDefault__roles__=ACCESS_PRIVATE
def setPermissionDefault(self, permission_name, roles):
"""Declare default roles for a permission"""
rdict = {}
for role in roles:
rdict[role] = 1
if self.roles.get(permission_name, rdict) != rdict:
LOG.warn('Conflicting default role'
'declarations for permission "%s"' % permission_name)
self._warnings = 1
self.roles[permission_name] = rdict
setDefaultAccess__roles__=ACCESS_PRIVATE
def setDefaultAccess(self, access):
"""Declare default attribute access policy.
This should be a boolean value, a map of attribute names to
booleans, or a callable (name, value) -> boolean.
"""
if isinstance(access, str):
access = access.lower()
if access == 'allow':
access = 1
elif access == 'deny':
access = 0
else:
raise ValueError, "'allow' or 'deny' expected"
self.access = access
class ClassSecurityInfo(SecurityInfo):
"""Encapsulate security information for class objects."""
__roles__ = ACCESS_PRIVATE
apply__roles__ = ACCESS_PRIVATE
def apply(self, classobj):
"""Apply security information to the given class object."""
dict = classobj.__dict__
# Check the class for an existing __ac_permissions__ and
# incorporate that if present to support older classes or
# classes that haven't fully switched to using SecurityInfo.
if dict.has_key('__ac_permissions__'):
for item in dict['__ac_permissions__']:
permission_name = item[0]
self._setaccess(item[1], permission_name)
if len(item) > 2:
self.setPermissionDefault(permission_name, item[2])
# Set __roles__ for attributes declared public or private.
# Collect protected attribute names in ac_permissions.
ac_permissions = {}
for name, access in self.names.items():
if access in (ACCESS_PRIVATE, ACCESS_PUBLIC, ACCESS_NONE):
setattr(classobj, '%s__roles__' % name, access)
else:
if not ac_permissions.has_key(access):
ac_permissions[access] = []
ac_permissions[access].append(name)
# Now transform our nested dict structure into the nested tuple
# structure expected of __ac_permissions__ attributes and set
# it on the class object.
getRoles = self.roles.get
__ac_permissions__ = []
permissions = ac_permissions.items()
permissions.sort()
for permission_name, names in permissions:
roles = getRoles(permission_name, ())
if len(roles):
entry = (permission_name, tuple(names), tuple(roles.keys()))
else:
entry = (permission_name, tuple(names))
__ac_permissions__.append(entry)
for permission_name, roles in self.roles.items():
if permission_name not in ac_permissions:
entry = (permission_name, (), tuple(roles.keys()))
__ac_permissions__.append(entry)
setattr(classobj, '__ac_permissions__', tuple(__ac_permissions__))
# Take care of default attribute access policy
access = getattr(self, 'access', _marker)
if access is not _marker:
setattr(classobj, '__allow_access_to_unprotected_subobjects__',
access)
if getattr(self, '_warnings', None):
LOG.warn('Class "%s" had conflicting '
'security declarations' % classobj.__name__)
class ClassSecurityInformation(ClassSecurityInfo):
# Default policy is disallow
access = 0
_moduleSecurity = {}
_appliedModuleSecurity = {}
def secureModule(mname, *imp):
modsec = _moduleSecurity.get(mname, None)
if modsec is None:
return
if imp:
__import__(mname, *imp)
del _moduleSecurity[mname]
module = sys.modules[mname]
modsec.apply(module.__dict__)
_appliedModuleSecurity[mname] = modsec
return module
def ModuleSecurityInfo(module_name=None):
if module_name is not None:
modsec = _moduleSecurity.get(module_name, None)
if modsec is not None:
return modsec
modsec = _appliedModuleSecurity.get(module_name, None)
if modsec is not None:
# Move security info back to to-apply dict (needed for product
# refresh). Also invoke this check for parent packages already
# applied
del _appliedModuleSecurity[module_name]
_moduleSecurity[module_name] = modsec
dot = module_name.rfind('.')
if dot > 0:
ModuleSecurityInfo(module_name[:dot])
return modsec
dot = module_name.rfind('.')
if dot > 0:
# If the module is in a package, recursively make sure
# there are security declarations for the package steps
# leading to the module
modname = module_name[dot + 1:]
pmodsec = ModuleSecurityInfo(module_name[:dot])
if not pmodsec.names.has_key(modname):
pmodsec.declarePublic(modname)
return _ModuleSecurityInfo(module_name)
class _ModuleSecurityInfo(SecurityInfo):
"""Encapsulate security information for modules."""
__roles__ = ACCESS_PRIVATE
def __init__(self, module_name=None):
self.names = {}
if module_name is not None:
global _moduleSecurity
_moduleSecurity[module_name] = self
__call____roles__ = ACCESS_PRIVATE
def __call__(self, name, value):
"""Callback for __allow_access_to_unprotected_subobjects__ hook."""
access = self.names.get(name, _marker)
if access is not _marker:
return access == ACCESS_PUBLIC
return getattr(self, 'access', 0)
apply__roles__ = ACCESS_PRIVATE
def apply(self, dict):
"""Apply security information to the given module dict."""
# Start with default attribute access policy
access = getattr(self, 'access', _marker)
if access is not _marker or len(self.names):
dict['__allow_access_to_unprotected_subobjects__'] = self
if getattr(self, '_warnings', None):
LOG.warn('Module "%s" had conflicting '
'security declarations' % dict['__name__'])
declareProtected__roles__=ACCESS_PRIVATE
def declareProtected(self, permission_name, *names):
"""Cannot declare module names protected."""
pass
declareObjectProtected__roles__=ACCESS_PRIVATE
def declareObjectProtected(self, permission_name):
"""Cannot declare module protected."""
pass
setDefaultRoles__roles__=ACCESS_PRIVATE
def setDefaultRoles(self, permission_name, roles):
"""Cannot set default roles for permissions in a module."""
pass
# Handy little utility functions
def allow_module(module_name):
"""Allow a module and all its contents to be used from a
restricted Script. The argument module_name may be a simple
or dotted module or package name. Note that if a package
path is given, all modules in the path will be available."""
ModuleSecurityInfo(module_name).setDefaultAccess(1)
dot = module_name.find('.')
while dot > 0:
ModuleSecurityInfo(module_name[:dot]).setDefaultAccess(1)
dot = module_name.find('.', dot + 1)
def allow_class(Class):
"""Allow a class and all of its methods to be used from a
restricted Script. The argument Class must be a class."""
Class._security = sec = ClassSecurityInfo()
sec.declareObjectPublic()
sec.setDefaultAccess(1)
sec.apply(Class)
from AccessControl.class_init import InitializeClass
InitializeClass(Class)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Security management
"""
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
nobody = getattr(SpecialUsers, 'nobody', None)
if nobody is None:
# Initialize SpecialUsers by importing User.py.
import User
nobody = SpecialUsers.nobody
manager = SecurityManager(thread_id, SecurityContext(nobody))
_managers[thread_id]=manager
return manager
def setSecurityManager(manager):
"""install *manager* as current security manager for this thread."""
thread_id=get_ident()
_managers[thread_id]=manager
import SpecialUsers
# AccessControl.Implementation inserts SecurityManager.
try:
from thread import get_ident
except ImportError:
def get_ident():
return 0
_managers={}
def newSecurityManager(request, user):
"""Set up a new security context for a request for a user
"""
thread_id=get_ident()
_managers[thread_id]=SecurityManager(
thread_id,
SecurityContext(user),
)
def noSecurityManager():
try: del _managers[get_ident()]
except: pass
def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy.
This method should only be caused by system startup code. It should
never, for example, be called during a web request.
"""
SecurityManager.setSecurityPolicy(aSecurityPolicy)
class SecurityContext:
"""The security context is an object used internally to the security
machinery. It captures data about the current security context.
"""
def __init__(self, user):
self.stack=[]
self.user=user
self.objectCache = {}
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''API module to set the security policy
'''
from AccessControl import ImplPython as _ImplPython
from AccessControl.SimpleObjectPolicies import _noroles
def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy.
This method should only be caused by system startup code. It should
never, for example, be called during a web request.
"""
last = _ImplPython._defaultPolicy
_ImplPython._defaultPolicy = aSecurityPolicy
return last
# AccessControl.Implementation inserts SecurityManager.
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''Collect rules for access to objects that don\'t have roles.
The rules are expressed as a mapping from type -> assertion
An assertion can be:
- A dict
- A callable
- Something with a truth value
If the assertion is a callable, then it will be called with
a name being accessed and the name used. Its return value is ignored,
but in may veto an access by raising an exception.
If the assertion is a dictionary, then the keys are attribute names.
The values may be callables or objects with boolean values. If a value
is callable, it will be called with the object we are accessing an
attribute of and the attribute name. It should return an attribute
value. Callables are often used to returned guarded versions of
methods. Otherwise, accesses are allowed if values in this dictionary
are true and disallowed if the values are false or if an item for an
attribute name is not present.
If the assertion is not a dict and is not callable, then access to
unprotected attributes is allowed if the assertion is true, and
disallowed otherwise.
XXX This descrition doesn't actually match what's done in ZopeGuards
or in ZopeSecurityPolicy. :(
'''
_noroles = [] # this is imported in various places
import Record
# Allow access to unprotected attributes
Record.Record.__allow_access_to_unprotected_subobjects__=1
# ContainerAssertions are used by cAccessControl to check access to
# attributes of container types, like dict, list, or string.
# ContainerAssertions maps types to a either a dict, a function, or a
# simple boolean value. When guarded_getattr checks the type of its
# first argument against ContainerAssertions, and invokes checking
# logic depending on what value it finds.
# If the value for a type is:
# - a boolean value:
# - the value determines whether access is allowed
# - a function (or callable):
# - The function is called with the name of the attribute and
# the actual attribute value, then the value is returned.
# The function can raise an exception.
# - a dict:
# - The dict maps attribute names to boolean values or functions.
# The boolean values behave as above, but the functions do not.
# The value returned for attribute access is the result of
# calling the function with the object and the attribute name.
ContainerAssertions={
type(()): 1,
type(''): 1,
type(u''): 1,
}
Containers = ContainerAssertions.get
def allow_type(Type, allowed=1):
"""Allow a type and all of its methods and attributes to be used from
restricted code. The argument Type must be a type."""
if type(Type) is not type:
raise ValueError, "%s is not a type" % `Type`
if hasattr(Type, '__roles__'):
raise ValueError, "%s handles its own security" % `Type`
if not (isinstance(allowed, int) or isinstance(allowed, dict)):
raise ValueError, "The 'allowed' argument must be an int or dict."
ContainerAssertions[Type] = allowed
#
# WAAAA!
#
from BTrees.OOBTree import OOBTree, OOBucket, OOSet
from BTrees.OIBTree import OIBTree, OIBucket, OISet
from BTrees.IOBTree import IOBTree, IOBucket, IOSet
from BTrees.IIBTree import IIBTree, IIBucket, IISet
for tree_type, has_values in [(OOBTree, 1),
(OOBucket, 1),
(OOSet, 0),
(OIBTree, 1),
(OIBucket, 1),
(OISet, 0),
(IOBTree, 1),
(IOBucket, 1),
(IOSet, 0),
(IIBTree, 1),
(IIBucket, 1),
(IISet, 0),
]:
tree = tree_type()
key_type = type(tree.keys())
if key_type is not list: # lists have their own declarations
allow_type(key_type)
if has_values:
assert key_type is type(tree.values())
assert key_type is type(tree.items())
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Place to find special users
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
initialization.
"""
nobody = None
system = None
emergency_user = None
# Note: use of the 'super' name is deprecated.
super = None
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Access control package.
"""
# BBB
from .users import BasicUser
from .users import SimpleUser
from .users import SpecialUser
from .users import User
from .users import UnrestrictedUser
from .users import NullUnrestrictedUser
from .users import readUserAccessFile
from .users import emergency_user
from .users import emergency_user as super
from .users import _remote_user_mode
from .users import nobody
from .users import system
from .users import rolejoin
from .users import addr_match
from .users import host_match
from .users import domainSpecMatch
from .users import absattr
from .users import reqattr
from .users import UnrestrictedUser as Super
from zope.deferredimport import deprecated
deprecated("User folders are no longer part of AccessControl, please depend "
"on Zope2 and import from OFS.userfolder or use the new minimal "
"user folder classes from AccessControl.userfolder.",
BasicUserFolder = 'OFS.userfolder:BasicUserFolder',
manage_addUserFolder = 'OFS.userfolder:manage_addUserFolder',
UserFolder = 'OFS.userfolder:UserFolder',
)
#############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
__version__='$Revision: 1.18 $'[11:-2]
import sys
import RestrictedPython
from RestrictedPython.Guards import safe_builtins, full_write_guard
from RestrictedPython.Utilities import utility_builtins
from RestrictedPython.Eval import RestrictionCapableEval
from SecurityManagement import getSecurityManager
from SecurityInfo import secureModule
from SimpleObjectPolicies import Containers, ContainerAssertions
from zExceptions import Unauthorized
_marker = [] # Create a new marker object.
safe_builtins = safe_builtins.copy()
safe_builtins.update(utility_builtins)
# AccessControl.Implementation inserts these names into this module as
# module globals: aq_validate, guarded_getattr
def initialize(impl):
# Called by AccessControl.Implementation.setImplementation()
# whenever the selected implementation changes.
global guarded_getattr
guarded_getattr = impl.guarded_getattr
safe_builtins['getattr'] = guarded_getattr
def guarded_hasattr(object, name):
try:
guarded_getattr(object, name)
except (AttributeError, Unauthorized):
return 0
return 1
safe_builtins['hasattr'] = guarded_hasattr
SliceType = type(slice(0))
def guarded_getitem(object, index):
if type(index) is SliceType:
if index.step is not None:
v = object[index]
else:
start = index.start
stop = index.stop
if start is None:
start = 0
if stop is None:
v = object[start:]
else:
v = object[start:stop]
# We don't guard slices.
return v
v = object[index]
if Containers(type(object)) and Containers(type(v)):
# Simple type. Short circuit.
return v
if getSecurityManager().validate(object, object, None, v):
return v
raise Unauthorized, 'unauthorized access to element %s' % `i`
# Create functions using nested scope to store state
# This is less expensive then instantiating and calling instances
def get_dict_get(d, name):
def guarded_get(key, default=None):
try:
return guarded_getitem(d, key)
except KeyError:
return default
return guarded_get
def get_dict_pop(d, name):
def guarded_pop(key, default=_marker):
try:
v = guarded_getitem(d, key)
except KeyError:
if default is not _marker:
return default
raise
else:
del d[key]
return v
return guarded_pop
def get_iter(c, name):
iter = getattr(c, name)
def guarded_iter():
return SafeIter(iter(), c)
return guarded_iter
def get_list_pop(lst, name):
def guarded_pop(index=-1):
# XXX This is not thread safe, but we don't expect
# XXX thread interactions between python scripts <wink>
v = guarded_getitem(lst, index)
del lst[index]
return v
return guarded_pop
# See comment in SimpleObjectPolicies for an explanation of what the
# dicts below actually mean.
_dict_white_list = {
'clear':1, 'copy':1, 'fromkeys':1, 'get':get_dict_get, 'has_key':1,
'items':1, 'iteritems':1, 'keys':1,
'iterkeys': get_iter, 'itervalues':get_iter,
'pop':get_dict_pop, 'popitem':1, 'setdefault':1, 'update':1, 'values':1}
def _check_dict_access(name, value):
# Check whether value is a dict method
self = getattr(value, '__self__', None)
if self is None: # item
return 1
# Disallow spoofing
if type(self) is not dict:
return 0
if getattr(value, '__name__', None) != name:
return 0
return _dict_white_list.get(name, 0)
ContainerAssertions[type({})] = _check_dict_access
_list_white_list = {
'append':1, 'count':1, 'extend':1, 'index':1, 'insert':1,
'pop':get_list_pop, 'remove':1, 'reverse':1, 'sort':1}
def _check_list_access(name, value):
# Check whether value is a dict method
self = getattr(value, '__self__', None)
if self is None: # item
return 1
# Disallow spoofing
if type(self) is not list:
return 0
if getattr(value, '__name__', None) != name:
return 0
return _list_white_list.get(name, 0)
ContainerAssertions[type([])] = _check_list_access
# This implementation of a "safe" iterator uses a global guard()
# function to implement the actual guard. This check is defined as a
# global so that it can delay imports of some module to avoid circular
# dependencies while also making it possible to use a faster
# implementation once the imports are done (by avoiding the import
# machinery on subsequent calls). Use of a method on the SafeIter
# class is avoided to ensure the best performance of the resulting
# function.
# The NullIter class skips the guard, and can be used to wrap an
# iterator that is known to be safe (as in guarded_enumerate).
class SafeIter(object):
#__slots__ = '_next', 'container'
__allow_access_to_unprotected_subobjects__ = 1
def __init__(self, ob, container=None):
self._next = iter(ob).next
if container is None:
container = ob
self.container = container
def __iter__(self):
return self
def next(self):
ob = self._next()
guard(self.container, ob)
return ob
class NullIter(SafeIter):
def __init__(self, ob):
self._next = ob.next
def next(self):
return self._next()
def _error(index):
raise Unauthorized, 'unauthorized access to element'
def guarded_iter(*args):
if len(args) == 1:
i = args[0]
# Don't double-wrap
if isinstance(i, SafeIter):
return i
if not isinstance(i, xrange):
return SafeIter(i)
# Other call styles / targets don't need to be guarded
return NullIter(iter(*args))
safe_builtins['iter'] = guarded_iter
def guard(container, value, index=None):
if Containers(type(container)) and Containers(type(value)):
# Simple type. Short circuit.
return
if getSecurityManager().validate(container, container, index, value):
return
_error(index)
# More replacement built-ins.
def guarded_filter(f, seq, skip_unauthorized=0):
if type(seq) is type(''):
return filter(f, seq)
if f is None:
def f(x): return x
v = getSecurityManager().validate
result = []
a = result.append
for el in seq:
if v(seq, seq, None, el):
if f(el): a(el)
elif not skip_unauthorized:
raise Unauthorized, 'unauthorized access to element'
return result
safe_builtins['filter'] = guarded_filter
def guarded_reduce(f, seq, initial=_marker):
if initial is _marker:
return reduce(f, guarded_iter(seq))
else:
return reduce(f, guarded_iter(seq), initial)
safe_builtins['reduce'] = guarded_reduce
def guarded_max(item, *items, **kw):
if items:
item = [item]
item.extend(items)
return max(guarded_iter(item), **kw)
safe_builtins['max'] = guarded_max
def guarded_min(item, *items, **kw):
if items:
item = [item]
item.extend(items)
return min(guarded_iter(item), **kw)
safe_builtins['min'] = guarded_min
def guarded_map(f, *seqs):
safe_seqs = []
for seqno in range(len(seqs)):
seq = guarded_getitem(seqs, seqno)
safe_seqs.append(guarded_iter(seq))
return map(f, *safe_seqs)
safe_builtins['map'] = guarded_map
def guarded_zip(*seqs):
safe_seqs = []
for seqno in range(len(seqs)):
seq = guarded_getitem(seqs, seqno)
safe_seqs.append(guarded_iter(seq))
return zip(*safe_seqs)
safe_builtins['zip'] = guarded_zip
def guarded_import(mname, globals=None, locals=None, fromlist=None):
if fromlist is None:
fromlist = ()
if '*' in fromlist:
raise Unauthorized, "'from %s import *' is not allowed"
if globals is None:
globals = {}
if locals is None:
locals = {}
mnameparts = mname.split('.')
firstmname = mnameparts[0]
validate = getSecurityManager().validate
module = load_module(None, None, mnameparts, validate, globals, locals)
if module is None:
raise Unauthorized, "import of '%s' is unauthorized" % mname
if fromlist is None:
fromlist = ()
for name in fromlist:
v = getattr(module, name, None)
if v is None:
v = load_module(module, mname, [name], validate,
globals, locals)
if not validate(module, module, name, v):
raise Unauthorized
else:
return __import__(mname, globals, locals, fromlist)
safe_builtins['__import__'] = guarded_import
class GuardedListType:
def __call__(self, *args, **kwargs):
return list(*args, **kwargs)
if sys.version_info >= (2, 4):
def sorted(self, iterable, cmp=None, key=None, reverse=False):
return list.sorted(iterable, cmp=None, key=None, reverse=False)
safe_builtins['list'] = GuardedListType()
class GuardedDictType:
def __call__(self, *args, **kwargs):
return dict(*args, **kwargs)
def fromkeys(self, S, v=None):
return dict.fromkeys(S,v)
safe_builtins['dict'] = GuardedDictType()
def guarded_enumerate(seq):
return NullIter(enumerate(guarded_iter(seq)))
safe_builtins['enumerate'] = guarded_enumerate
def guarded_sum(sequence, start=0):
return sum(guarded_iter(sequence), start)
safe_builtins['sum'] = guarded_sum
def load_module(module, mname, mnameparts, validate, globals, locals):
modules = sys.modules
while mnameparts:
nextname = mnameparts.pop(0)
if mname is None:
mname = nextname
else:
mname = '%s.%s' % (mname, nextname)
nextmodule = modules.get(mname, None)
if nextmodule is None:
nextmodule = secureModule(mname, globals, locals)
if nextmodule is None:
return
else:
secureModule(mname)
if module and not validate(module, module, nextname, nextmodule):
return
module = nextmodule
return module
# This version of apply is used by restricted Python, which transforms
# extended call syntax into a call of _apply_(), after tucking the callable
# into the first element of args. For example,
# f(3, eggs=1, spam=False)
# is changed to
# _apply_(f, 3, eggs=1, spam=False)
def guarded_apply(func, *args, **kws):
return builtin_guarded_apply(func, args, kws)
# This version is the safe_builtins apply() replacement, so needs to match the
# signature of __builtin__.apply.
def builtin_guarded_apply(func, args=(), kws={}):
# Check the args elements. args may be an arbitrary iterable, and
# iterating over it may consume it, so we also need to save away
# the arguments in a new list to pass on to the real apply().
i, arglist = 0, []
for elt in args:
guard(args, elt, i)
arglist.append(elt)
i += 1
# Check kws similarly. Checking the keys may not be strictly necessary,
# but better safe than sorry. A new argument dict is created just in
# case kws is a hostile user-defined instance that may do horrid things
# as a side-effect of calling items().
argdict = {}
for k, v in kws.items():
guard(kws, k)
guard(kws, v, k)
argdict[k] = v
return func(*arglist, **argdict)
safe_builtins['apply'] = builtin_guarded_apply
# Similar to min and reduce, use guarded_iter on the sequence being
# tested and apply the original function.
if sys.version_info >= (2, 5):
def guarded_any(seq):
return any(guarded_iter(seq))
safe_builtins['any'] = guarded_any
def guarded_all(seq):
return all(guarded_iter(seq))
safe_builtins['all'] = guarded_all
# This metaclass supplies the security declarations that allow all
# attributes of a class and its instances to be read and written.
def _metaclass(name, bases, dict):
for k, v in dict.items():
if k.endswith('__roles__') and k[:len('__roles__')] not in dict:
raise Unauthorized, "Can't override security: %s" % k
ob = type(name, bases, dict)
ob.__allow_access_to_unprotected_subobjects__ = 1
ob._guarded_writes = 1
return ob
try:
valid_inplace_types = list, set
except NameError:
# Python 2.3
valid_inplace_types = list
inplace_slots = {
'+=': '__iadd__',
'-=': '__isub__',
'*=': '__imul__',
'/=': (1/2 == 0) and '__idiv__' or '__itruediv__',
'//=': '__ifloordiv__',
'%=': '__imod__',
'**=': '__ipow__',
'<<=': '__ilshift__',
'>>=': '__irshift__',
'&=': '__iand__',
'^=': '__ixor__',
'|=': '__ior_',
}
def __iadd__(x, y):
x += y
return x
def __isub__(x, y):
x -= y
return x
def __imul__(x, y):
x *= y
return x
def __idiv__(x, y):
x /= y
return x
def __ifloordiv__(x, y):
x //= y
return x
def __imod__(x, y):
x %= y
return x
def __ipow__(x, y):
x **= y
return x
def __ilshift__(x, y):
x <<= y
return x
def __irshift__(x, y):
x >>= y
return x
def __iand__(x, y):
x &= y
return x
def __ixor__(x, y):
x ^= y
return x
def __ior__(x, y):
x |= y
return x
inplace_ops = {
'+=': __iadd__,
'-=': __isub__,
'*=': __imul__,
'/=': __idiv__,
'//=': __ifloordiv__,
'%=': __imod__,
'**=': __ipow__,
'<<=': __ilshift__,
'>>=': __irshift__,
'&=': __iand__,
'^=': __ixor__,
'|=': __ior__,
}
def protected_inplacevar(op, var, expr):
"""Do an inplace operation
If the var has an inplace slot, then disallow the operation
unless the var is a list.
"""
if (hasattr(var, inplace_slots[op])
and not isinstance(var, valid_inplace_types)
):
try:
cls = var.__class__
except AttributeError:
cls = type(var)
raise TypeError(
"Augmented assignment to %s objects is not allowed"
" in untrusted code" % cls.__name__
)
return inplace_ops[op](var, expr)
# AccessControl clients generally need to set up a safe globals dict for
# use by restricted code. The get_safe_globals() function returns such
# a dict, containing '__builtins__' mapped to our safe bulitins, and
# bindings for all the special functions inserted into Python code by
# RestrictionMutator transformations. A client may wish to add more
# bindings to this dict. It's generally safe to do so, as
# get_safe_globals returns a (shallow) copy of a canonical safe globals
# dict.
# Exception: For obscure technical reasons, clients have to import
# guarded_getattr from this module (ZopeGuards) and plug it into the
# dict themselves, with key '_getattr_'.
_safe_globals = {'__builtins__': safe_builtins,
'__metaclass__': _metaclass,
'_apply_': guarded_apply,
'_getitem_': guarded_getitem,
'_getiter_': guarded_iter,
'_print_': RestrictedPython.PrintCollector,
'_write_': full_write_guard,
'_inplacevar_': protected_inplacevar,
# The correct implementation of _getattr_, aka
# guarded_getattr, isn't known until
# AccessControl.Implementation figures that out, then
# stuffs it into *this* module's globals bound to
# 'guarded_getattr'. We can't know what that is at
## '_getattr_': guarded_getattr,
}
get_safe_globals = _safe_globals.copy
RestrictionCapableEval.globals.update(_safe_globals)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Define Zope's default security policy
"""
from types import MethodType
# AccessControl.Implementation inserts:
# ZopeSecurityPolicy, getRoles, rolesForPermissionOn
from AccessControl.SimpleObjectPolicies import _noroles
rolesForPermissionOn = None # XXX: avoid import loop
tuple_or_list = tuple, list
def getRoles(container, name, value, default):
global rolesForPermissionOn # XXX: avoid import loop
if rolesForPermissionOn is None:
from PermissionRole import rolesForPermissionOn
roles = getattr(value, '__roles__', _noroles)
if roles is _noroles:
if not name or not isinstance(name, basestring):
return default
if type(value) is MethodType:
container = value.im_self
cls = getattr(container, '__class__', None)
if cls is None:
return default
roles = getattr(cls, name+'__roles__', _noroles)
if roles is _noroles:
return default
value = container
if roles is None or isinstance(roles, tuple_or_list):
return roles
rolesForPermissionOn = getattr(roles, 'rolesForPermissionOn', None)
if rolesForPermissionOn is not None:
roles = rolesForPermissionOn(value)
return roles
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
# This has to happen early so things get initialized properly
from AccessControl.Implementation import setImplementation
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.SecurityManagement import setSecurityPolicy
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityInfo import ModuleSecurityInfo
from AccessControl.SecurityInfo import ACCESS_PRIVATE
from AccessControl.SecurityInfo import ACCESS_PUBLIC
from AccessControl.SecurityInfo import ACCESS_NONE
from AccessControl.SecurityInfo import secureModule
from AccessControl.SecurityInfo import allow_module
from AccessControl.SecurityInfo import allow_class
from AccessControl.SimpleObjectPolicies import allow_type
from AccessControl.unauthorized import Unauthorized # XXX
from AccessControl.ZopeGuards import full_write_guard
from AccessControl.ZopeGuards import safe_builtins
ModuleSecurityInfo('AccessControl').declarePublic('getSecurityManager')
/*
** cAccessControl.c
**
** Access control acceleration routines
Copyright (c) 2001, Zope Foundation and Contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
#include "ExtensionClass/ExtensionClass.h"
#include "Acquisition/Acquisition.h"
#include <stdio.h>
#include <stdlib.h>
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
typedef int Py_ssize_t;
typedef Py_ssize_t (*lenfunc)(PyObject *);
typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
#define PY_SSIZE_T_MAX INT_MAX
#define PY_SSIZE_T_MIN INT_MIN
#endif
static void
PyVar_Assign(PyObject **v, PyObject *e)
{
Py_XDECREF(*v);
*v=e;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if (!(E))
#define OBJECT(o) ((PyObject *) (o))
static PyObject *
callfunction1(PyObject *function, PyObject *arg)
{
PyObject *t, *r;
t = PyTuple_New(1);
if (t == NULL)
return NULL;
Py_INCREF(arg);
PyTuple_SET_ITEM(t, 0, arg);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callmethod1(PyObject *self, PyObject *name, PyObject *arg)
{
UNLESS(self = PyObject_GetAttr(self,name)) return NULL;
ASSIGN(self, callfunction1(self, arg));
return self;
}
static PyObject *
callfunction2(PyObject *function, PyObject *arg0, PyObject *arg1)
{
PyObject *t, *r;
t = PyTuple_New(2);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction3(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2
)
{
PyObject *t, *r;
t = PyTuple_New(3);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction4(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2, PyObject *arg3
)
{
PyObject *t, *r;
t = PyTuple_New(4);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
Py_INCREF(arg3);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
PyTuple_SET_ITEM(t, 3, arg3);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction5(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2, PyObject *arg3, PyObject *arg4
)
{
PyObject *t, *r;
t = PyTuple_New(5);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
Py_INCREF(arg3);
Py_INCREF(arg4);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
PyTuple_SET_ITEM(t, 3, arg3);
PyTuple_SET_ITEM(t, 4, arg4);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction6(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2, PyObject *arg3,
PyObject *arg4, PyObject *arg5
)
{
PyObject *t, *r;
t = PyTuple_New(6);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
Py_INCREF(arg3);
Py_INCREF(arg4);
Py_INCREF(arg5);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
PyTuple_SET_ITEM(t, 3, arg3);
PyTuple_SET_ITEM(t, 4, arg4);
PyTuple_SET_ITEM(t, 5, arg5);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static int
unpacktuple2(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
return 0;
}
static int
unpacktuple3(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
return 0;
}
static int
unpacktuple4(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2, PyObject **a3)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
if (l > 3) *a3=PyTuple_GET_ITEM(args, 3);
return 0;
}
static int
unpacktuple5(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2,
PyObject **a3, PyObject **a4)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
if (l > 3) *a3=PyTuple_GET_ITEM(args, 3);
if (l > 4) *a4=PyTuple_GET_ITEM(args, 4);
return 0;
}
static int
unpacktuple6(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2,
PyObject **a3, PyObject **a4, PyObject **a5)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
if (l > 3) *a3=PyTuple_GET_ITEM(args, 3);
if (l > 4) *a4=PyTuple_GET_ITEM(args, 4);
if (l > 5) *a5=PyTuple_GET_ITEM(args, 5);
return 0;
}
/*
** Structures
*/
typedef struct {
PyObject_HEAD
} ZopeSecurityPolicy;
typedef struct {
PyObject_HEAD
PyObject *thread_id;
PyObject *context;
PyObject *policy;
PyObject *validate;
PyObject *checkPermission;
} SecurityManager;
typedef struct {
PyObject_HEAD
PyObject *__name__;
PyObject *_p;
PyObject *__roles__;
} PermissionRole;
typedef struct {
PyObject_HEAD
PyObject *_p;
PyObject *_pa;
PyObject *__roles__;
PyObject *_v;
} imPermissionRole;
/*
** Prototypes
*/
static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args);
static void ZopeSecurityPolicy_dealloc(ZopeSecurityPolicy *self);
static PyObject *PermissionRole_init(PermissionRole *self, PyObject *args);
static PyObject *PermissionRole_of(PermissionRole *self, PyObject *parent);
static PyObject *
PermissionRole_rolesForPermissionOn(PermissionRole *self, PyObject *value);
static void PermissionRole_dealloc(PermissionRole *self);
static PyObject *PermissionRole_getattro(PermissionRole *self, PyObject *name);
static PyObject *imPermissionRole_of(imPermissionRole *self, PyObject *parent);
static Py_ssize_t imPermissionRole_length(imPermissionRole *self);
static PyObject *imPermissionRole_get(imPermissionRole *self,
Py_ssize_t item);
static void imPermissionRole_dealloc(imPermissionRole *self);
static PyObject *rolesForPermissionOn(PyObject *self, PyObject *args);
static PyObject *module_guarded_getattr(PyObject *self, PyObject *args);
static PyObject *module_aq_validate(PyObject *self, PyObject *args);
static PyObject *module_setDefaultBehaviors(PyObject *self, PyObject *args);
static PyObject *c_rolesForPermissionOn(PyObject *self, PyObject *perm,
PyObject *object, PyObject *deflt);
static PyObject *permissionName(PyObject *name);
static PyObject *SecurityManager_validate(SecurityManager *self,
PyObject *args);
static PyObject *SecurityManager_DTMLValidate(SecurityManager *self,
PyObject *args);
static PyObject *SecurityManager_checkPermission(SecurityManager *self,
PyObject *args);
static void SecurityManager_dealloc(SecurityManager *self);
static PyObject *SecurityManager_getattro(SecurityManager *self,
PyObject *name);
static int SecurityManager_setattro(SecurityManager *self,
PyObject *name, PyObject *value);
static getattrofunc ExtensionClassGetattro;
/*
** Constants
*/
static PyMethodDef cAccessControl_methods[] = {
{"rolesForPermissionOn",
(PyCFunction)rolesForPermissionOn,
METH_VARARGS,
""
},
{"guarded_getattr",
(PyCFunction)module_guarded_getattr,
METH_VARARGS,
""
},
{"aq_validate",
(PyCFunction)module_aq_validate,
METH_VARARGS,
""
},
{"setDefaultBehaviors",
(PyCFunction)module_setDefaultBehaviors,
METH_VARARGS,
""
},
{ NULL, NULL }
};
static char ZopeSecurityPolicy__doc__[] = "ZopeSecurityPolicy C implementation";
static PyMethodDef ZopeSecurityPolicy_methods[] = {
{"validate",
(PyCFunction)ZopeSecurityPolicy_validate,
METH_VARARGS,
""
},
{ NULL, NULL }
};
static PyExtensionClass ZopeSecurityPolicyType = {
PyObject_HEAD_INIT(NULL) 0,
"ZopeSecurityPolicy", /* tp_name */
sizeof(ZopeSecurityPolicy), /* tp_basicsize */
0, /* tp_itemsize */
/* Standard methods */
(destructor) ZopeSecurityPolicy_dealloc,/* tp_dealloc */
NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
NULL, /* tp_repr */
/* Method suites */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence*/
NULL, /* tp_as_mapping */
/* More standard ops */
NULL, /* tp_hash */
NULL, /* tp_call */
NULL, /* tp_str */
NULL, /* tp_getattro */
NULL, /* tp_setattro */
/* Reserved fields */
0, /* tp_xxx3 */
0, /* tp_xxx4 */
/* Docstring */
ZopeSecurityPolicy__doc__, /* tp_doc */
#ifdef COUNT_ALLOCS
0, /* tp_alloc */
0, /* tp_free */
0, /* tp_maxalloc */
NULL, /* tp_next */
#endif
METHOD_CHAIN(ZopeSecurityPolicy_methods),/* methods */
(void *)(EXTENSIONCLASS_BINDABLE_FLAG), /* flags */
};
static char SecurityManager__doc__[] = "ZopeSecurityPolicy C implementation";
static PyMethodDef SecurityManager_methods[] = {
{"validate",
(PyCFunction)SecurityManager_validate,
METH_VARARGS,
""
},
{"DTMLValidate",
(PyCFunction)SecurityManager_DTMLValidate,
METH_VARARGS,
""
},
{"checkPermission",
(PyCFunction)SecurityManager_checkPermission,
METH_VARARGS,
""
},
{ NULL, NULL }
};
static PyExtensionClass SecurityManagerType = {
PyObject_HEAD_INIT(NULL) 0,
"SecurityManager", /* tp_name */
sizeof(SecurityManager), /* tp_basicsize */
0, /* tp_itemsize */
/* Standard methods */
(destructor) SecurityManager_dealloc,/* tp_dealloc */
NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
NULL, /* tp_repr */
/* Method suites */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence*/
NULL, /* tp_as_mapping */
/* More standard ops */
NULL, /* tp_hash */
NULL, /* tp_call */
NULL, /* tp_str */
(getattrofunc)SecurityManager_getattro, /* tp_getattro */
(setattrofunc)SecurityManager_setattro, /* tp_setattro */
/* Reserved fields */
0, /* tp_xxx3 */
0, /* tp_xxx4 */
/* Docstring */
SecurityManager__doc__, /* tp_doc */
#ifdef COUNT_ALLOCS
0, /* tp_alloc */
0, /* tp_free */
0, /* tp_maxalloc */
NULL, /* tp_next */
#endif
METHOD_CHAIN(SecurityManager_methods), /* methods */
0, /* flags */
};
static char PermissionRole__doc__[] = "PermissionRole C implementation";
static PyMethodDef PermissionRole_methods[] = {
{"__init__",
(PyCFunction)PermissionRole_init,
METH_VARARGS,
""
},
{"__of__",
(PyCFunction)PermissionRole_of,
METH_O,
""
},
{"rolesForPermissionOn",
(PyCFunction)PermissionRole_rolesForPermissionOn,
METH_O,
""
},
{ NULL, NULL }
};
static PyExtensionClass PermissionRoleType = {
PyObject_HEAD_INIT(NULL) 0,
"PermissionRole", /* tp_name */
sizeof(PermissionRole), /* tp_basicsize */
0, /* tp_itemsize */
/* Standard methods */
(destructor) PermissionRole_dealloc, /* tp_dealloc */
NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
NULL, /* tp_repr */
/* Method suites */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence*/
NULL, /* tp_as_mapping */
/* More standard ops */
NULL, /* tp_hash */
NULL, /* tp_call */
NULL, /* tp_str */
(getattrofunc) PermissionRole_getattro, /* tp_getattro */
NULL, /* tp_setattro */
/* Reserved fields */
0, /* tp_xxx3 */
0, /* tp_xxx4 */
/* Docstring */
PermissionRole__doc__, /* tp_doc */
#ifdef COUNT_ALLOCS
0, /* tp_alloc */
0, /* tp_free */
0, /* tp_maxalloc */
NULL, /* tp_next */
#endif
METHOD_CHAIN(PermissionRole_methods), /* methods */
(void *)(EXTENSIONCLASS_BINDABLE_FLAG)/*|
EXTENSIONCLASS_INSTDICT_FLAG*/, /* flags */
NULL, /* Class dict */
0, /* bases */
NULL, /* reserved */
};
static char imPermissionRole__doc__[] = "imPermissionRole C implementation";
static PyMethodDef imPermissionRole_methods[] = {
{"__of__",
(PyCFunction)imPermissionRole_of,
METH_O,
""
},
{"rolesForPermissionOn",
(PyCFunction)imPermissionRole_of,
METH_O,
""
},
{ NULL, NULL }
};
static PySequenceMethods imSequenceMethods = {
(lenfunc) imPermissionRole_length, /* sq_length */
(binaryfunc) NULL, /* sq_concat */
(ssizeargfunc) NULL, /* sq_repeat */
(ssizeargfunc) imPermissionRole_get, /* sq_item */
(ssizessizeargfunc) NULL, /* sq_slice */
(ssizeobjargproc) NULL, /* sq_ass_item */
(ssizessizeobjargproc) NULL, /* sq_ass_slice */
(objobjproc) NULL, /* sq_contains */
(binaryfunc) NULL, /* sq_inplace_concat */
(ssizeargfunc) NULL /* sq_inplace_repeat */
};
static PyExtensionClass imPermissionRoleType = {
PyObject_HEAD_INIT(NULL) 0,
"imPermissionRole", /* tp_name */
sizeof(imPermissionRole), /* tp_basicsize */
0, /* tp_itemsize */
/* Standard methods */
(destructor) imPermissionRole_dealloc, /* tp_dealloc */
NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
NULL, /* tp_repr */
/* Method suites */
NULL, /* tp_as_number */
&imSequenceMethods, /* tp_as_sequence*/
NULL, /* tp_as_mapping */
/* More standard ops */
NULL, /* tp_hash */
NULL, /* tp_call */
NULL, /* tp_str */
NULL, /* tp_getattro */
NULL, /* tp_setattro */
/* Reserved fields */
0, /* tp_xxx3 */
0, /* tp_xxx4 */
/* Docstring */
imPermissionRole__doc__, /* tp_doc */
#ifdef COUNT_ALLOCS
0, /* tp_alloc */
0, /* tp_free */
0, /* tp_maxalloc */
NULL, /* tp_next */
#endif
METHOD_CHAIN(imPermissionRole_methods), /* methods */
(void *)(EXTENSIONCLASS_BINDABLE_FLAG), /* flags */
};
/* --------------------------------------------------------------
** STATIC OBJECTS
** --------------------------------------------------------------
*/
static PyObject *Containers = NULL;
static PyObject *ContainerAssertions = NULL;
static PyObject *Unauthorized = NULL;
static PyObject *warn= NULL;
static PyObject *NoSequenceFormat = NULL;
static PyObject *_what_not_even_god_should_do = NULL;
static PyObject *Anonymous = NULL;
static PyObject *AnonymousTuple = NULL;
static PyObject *ManagerTuple = NULL;
static PyObject *imPermissionRoleObj = NULL;
static PyObject *defaultPermission = NULL;
static PyObject *__roles__ = NULL;
static PyObject *__of__ = NULL;
static PyObject *__allow_access_to_unprotected_subobjects__ = NULL;
static PyObject *stack_str = NULL;
static PyObject *user_str = NULL;
static PyObject *validate_str = NULL;
static PyObject *_proxy_roles_str = NULL;
static PyObject *allowed_str = NULL;
static PyObject *getOwner_str = NULL;
static PyObject *getPhysicalRoot_str = NULL;
static PyObject *checkPermission_str = NULL;
static PyObject *getSecurityManager = NULL;
static PyObject *unrestrictedTraverse_str = NULL;
static PyObject *aq_validate = NULL;
static PyObject *aq_parent_str = NULL;
static PyObject *_check_context_str = NULL;
static PyObject *getRoles = NULL;
static PyObject *getWrappedOwner_str = NULL;
static int ownerous = 1;
static int authenticated = 1;
/* --------------------------------------------------------------
** ZopeSecurityPolicy Methods
** --------------------------------------------------------------
*/
/* ZopeSecurityPolicy_setup
**
** Setup for ZopeSecurityPolicy -- load all necessary objects from
** elsewhere... (e.g. imports)
*/
static int
ZopeSecurityPolicy_setup(void) {
UNLESS (NoSequenceFormat = PyString_FromString(
"'%s' passed as roles"
" during validation of '%s' is not a sequence."
)) return -1;
UNLESS (defaultPermission = Py_BuildValue("(s)", "Manager")) return -1;
UNLESS (_what_not_even_god_should_do = Py_BuildValue("[]")) return -1;
UNLESS (__roles__ = PyString_FromString("__roles__")) return -1;
UNLESS (__of__ = PyString_FromString("__of__")) return -1;
UNLESS (Anonymous = PyString_FromString("Anonymous")) return -1;
UNLESS (AnonymousTuple = Py_BuildValue("(O)", Anonymous)) return -1;
UNLESS (ManagerTuple = Py_BuildValue("(s)", "Manager")) return -1;
UNLESS (stack_str = PyString_FromString("stack")) return -1;
UNLESS (user_str = PyString_FromString("user")) return -1;
UNLESS (validate_str = PyString_FromString("validate")) return -1;
UNLESS (_proxy_roles_str = PyString_FromString("_proxy_roles"))
return -1;
UNLESS (allowed_str = PyString_FromString("allowed")) return -1;
UNLESS (getOwner_str = PyString_FromString("getOwner")) return -1;
UNLESS (getWrappedOwner_str = PyString_FromString("getWrappedOwner"))
return -1;
UNLESS (getPhysicalRoot_str = PyString_FromString("getPhysicalRoot"))
return -1;
UNLESS (aq_parent_str = PyString_FromString("aq_parent")) return -1;
UNLESS (_check_context_str = PyString_FromString("_check_context"))
return -1;
UNLESS (unrestrictedTraverse_str = PyString_FromString(
"unrestrictedTraverse"))
return -1;
UNLESS (checkPermission_str = PyString_FromString("checkPermission"))
return -1;
UNLESS (__allow_access_to_unprotected_subobjects__ =
PyString_FromString(
"__allow_access_to_unprotected_subobjects__"))
return -1;
return 0;
}
/*
** unauthErr
**
** Generate the unauthorized error
*/
static void unauthErr(PyObject *name, PyObject *value) {
PyObject *v;
if ((v=Py_BuildValue("OO", name, value)))
{
PyErr_SetObject(Unauthorized, v);
Py_DECREF(v);
}
}
/*
** ZopeSecurityPolicy_validate
*/
static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
PyObject *accessed = NULL; /* Note: accessed is not used. */
PyObject *container = NULL;
PyObject *name = NULL;
PyObject *value = NULL;
PyObject *context = NULL;
PyObject *roles = NULL;
/* Import from SimpleObject Policy._noroles */
/* Note that _noroles means missing roles, spelled with a NULL in C.
Jim. */
PyObject *containerbase = NULL;
PyObject *accessedbase = NULL;
PyObject *p = NULL;
PyObject *rval = NULL;
PyObject *stack = NULL;
PyObject *user = NULL;
PyObject *method = NULL;
PyObject *tmp = NULL;
int i, l, contains;
PyObject *r;
/*| def validate(self, accessed, container, name, value, context
**| roles=_noroles ...
*/
if (unpacktuple6(args, "validate", 5, &accessed, &container,
&name, &value, &context, &roles) < 0)
return NULL;
/*| # Provide special rules for acquisition attributes
**| if type(name) in (StringType, UnicodeType):
**| if name[:3] == 'aq_' and name not in valid_aq_:
**| raise Unauthorized(name, value)
*/
if (PyString_Check(name) || PyUnicode_Check(name)) {
char *sname = PyString_AsString(name);
/* Conversion to string may have failed, e.g. if name is Unicode
* and can't be bashed into the default encoding. Unclear what
* to do then. It's arguably conservative to raise Unauthorized
* in this case.
*/
if (sname == NULL ||
/* or starts with "aq_" */
(sname[0] == 'a' && sname[1] == 'q' && sname[2] == '_' &&
/* and isn't aq_{parent, inner, explicit} */
strcmp(sname + 3, "parent") &&
strcmp(sname + 3, "inner") &&
strcmp(sname + 3, "explicit")
)
)
{
/* Access control violation */
unauthErr(name, value);
return NULL; /* roles is not owned yet */
}
}
Py_XINCREF(roles); /* Convert the borrowed ref to a real one */
/*| containerbase = aq_base(container)
**| accessedbase = aq_base(accessed)
**| if accessedbase is accessed:
**| # accessed is not a wrapper, so assume that the
**| # value could not have been acquired.
**| accessedbase = container
*/
containerbase = aq_base(container);
if (containerbase == NULL) goto err;
if (aq_isWrapper(accessed))
accessedbase = aq_base(accessed);
else {
Py_INCREF(container);
accessedbase = container;
}
/*| # If roles weren't passed in, we'll try to get them from
**| # the object
**|
**| if roles is _noroles:
**| roles = getRoles(container, name, value, _noroles)
*/
if (roles == NULL) {
roles = callfunction4(getRoles, container, name, value, getRoles);
if (roles == getRoles) {
Py_DECREF(roles);
roles = NULL;
}
if (roles == NULL)
PyErr_Clear();
}
/*| # We still might not have any roles
**|
**| if roles is _noroles:
*/
if (roles == NULL) {
/*| # We have an object without roles and we didn't get
**| # a list of roles passed in. Presumably, the value
**| # is some simple object like a string or a list.
**| # We'll try to get roles from it's container
**|
**| if container is None: raise Unauthorized(name, value)
*/
if (container == Py_None) {
unauthErr(name, value);
goto err;
}
/*| roles = getattr(container, "__roles__", _noroles)
**| if roles is _noroles:
**| if containerbase is container:
**| # Container is not wrapped.
**| if containerbase is not accessedbase:
**| raise Unauthorized(name, value)
**| else:
**| # Try to acquire roles
**| try: roles = container.aq_aquire('__roles__')
**| except AttributeError:
**| if containerbase is not accessedbase:
**| raise Unauthorized(name, value)
*/
roles = PyObject_GetAttr(container, __roles__);
if (roles == NULL) {
PyErr_Clear();
if (!aq_isWrapper(container)) {
if (containerbase != accessedbase) {
unauthErr(name, value);
goto err;
}
}
else {
roles = aq_acquire(container, __roles__);
if (roles == NULL) {
if (PyErr_ExceptionMatches(
PyExc_AttributeError))
{
PyErr_Clear();
if (containerbase != accessedbase) {
unauthErr(name, value);
goto err;
}
}
else
goto err;
}
}
}
/*| # We need to make sure that we are allowed to get
**| # unprotected attributes from the container. We are
**| # allowed for certain simple containers and if the
**| # container says we can. Simple containers may also
**| # impose name restrictions.
**|
**| p = Containers(type(container), None)
**| if p is None:
**| p = getattr(container,
**| "__allow_access_to_unprotected_subobjects__", None)
*/
p = callfunction2(Containers, OBJECT(container->ob_type),
Py_None);
if (p == NULL)
goto err;
if (p == Py_None) {
ASSIGN(p, PyObject_GetAttr(container,
__allow_access_to_unprotected_subobjects__));
if (p == NULL)
PyErr_Clear();
}
/*| if p is not None:
**| tp = type(p)
**| if tp is not IntType:
**| if tp is DictType:
**| if (isinstance(name, StringType) or
**| isinstance(name, UnicodeType)):
**| p=p.get(name, None)
**| else:
**| p = 1
**| else:
**| p = p(name, value)
*/
if (p)
{
if (! PyInt_Check(p))
{
if (PyDict_Check(p))
{
if (PyString_Check(name) || PyUnicode_Check(name))
{
ASSIGN(p, PyObject_GetItem(p, name));
if (p == NULL)
PyErr_Clear();
}
else
{
ASSIGN(p, PyInt_FromLong(1));
if (p == NULL)
goto err;
}
}
else
{
ASSIGN(p, callfunction2(p, name, value));
if (p == NULL)
goto err;
}
}
}
/*| if not p:
**| raise Unauthorized, cleanupName(name, value)
*/
if (p == NULL || ! PyObject_IsTrue(p)) {
Py_XDECREF(p);
unauthErr(name, value);
goto err;
}
else
Py_DECREF(p);
/*| if roles is _noroles: return 1
*/
if (roles == NULL) {
rval = PyInt_FromLong(1);
goto err;
}
/*| # We are going to need a security-aware object to pass
**| # to allowed(). We'll use the container
**|
**| value = container
*/
value = container; /* Both are borrowed references */
} /* if (roles == NULL) */
/*| # Short-circuit tests if we can
**| try:
**| if roles is None or 'Anonymous' in roles: return 1
**| except TypeError:
**| LOG.warn('"%s' passed as roles"
**| " during validation of '%s' is not a sequence." %
**| ('roles', name))
**| raise
*/
if (roles == Py_None) {
rval = PyInt_FromLong(1);
goto err;
}
else
{
int i;
i = PySequence_Contains(roles, Anonymous);
if (i > 0)
{
rval = PyInt_FromLong(1);
goto err;
}
else if (i < 0)
{ /* Error */
PyObject *m, *t, *v, *tb;
if (!PyErr_ExceptionMatches(PyExc_TypeError))
goto err;
PyErr_Fetch(&t, &v, &tb);
m=PyObject_Repr(roles);
if (m) ASSIGN(m, Py_BuildValue("OO", m, name));
if (m) ASSIGN(m, PyString_Format(NoSequenceFormat, m));
if (m) ASSIGN(m, PyObject_CallFunction(warn, "O", m));
Py_XDECREF(m);
PyErr_Restore(t, v, tb);
goto err;
}
}
/*| # Check executable security
**| stack = context.stack
**| if stack:
*/
stack = PyObject_GetAttr(context, stack_str);
if (stack == NULL) goto err;
if (PyObject_IsTrue(stack)) {
PyObject *eo;
PyObject *owner;
PyObject *proxy_roles;
/*| eo = stack[-1]
**| # If the executable had an owner, can it execute?
**| owner = eo.getOwner()
**| if (owner is not None) and not owner.allowed(value, roles)
**| # We don't want someone to acquire if they can't
**| # get an unacquired!
**| raise Unauthorized, ('You are not authorized to'
**| 'access <em>%s</em>.' % cleanupName(name, value))
*/
eo = PySequence_GetItem(stack, -1);
if (eo == NULL) goto err;
if (ownerous) { /* Tabbing not adjusted for diff reasons*/
owner = PyObject_GetAttr(eo, getOwner_str);
if (owner) ASSIGN(owner, PyObject_CallObject(owner, NULL));
if (owner ==NULL)
{
Py_DECREF(eo);
goto err;
}
if (owner != Py_None) {
ASSIGN(owner,PyObject_GetAttr(owner, allowed_str));
if (owner)
ASSIGN(owner, callfunction2(owner, value, roles));
if (owner == NULL)
{
Py_DECREF(eo);
goto err;
}
if (! PyObject_IsTrue(owner))
{
Py_DECREF(owner);
Py_DECREF(eo);
unauthErr(name, value);
goto err;
}
}
Py_DECREF(owner);
} /* End of if ownerous */
/*| # Proxy roles, which are a lot safer now
**| proxy_roles = getattr(eo, "_proxy_roles", None)
**| if proxy_roles:
**| # Verify that the owner actually can state the proxy role
**| # in the context of the accessed item; users in subfolders
**| # should not be able to use proxy roles to access items
**| # above their subfolder!
**| owner = eo.getWrappedOwner()
**|
**| if owner is not None:
**| if container is not containerbase:
**| if not owner._check_context(container):
**| # container is higher up than the owner,
**| # deny access
**| raise Unauthorized(name, value)
**|
**| for r in proxy_roles:
**| if r in roles:
**| return 1
**|
**| raise Unauthorized(name, value)
*/
proxy_roles = PyObject_GetAttr(eo, _proxy_roles_str);
if (proxy_roles == NULL)
{
Py_DECREF(eo);
PyErr_Clear();
}
else if (PyObject_IsTrue(proxy_roles))
{
method = PyObject_GetAttr(eo, getWrappedOwner_str);
if (method == NULL) {
Py_DECREF(eo);
Py_DECREF(proxy_roles);
goto err;
}
owner = PyObject_CallObject(method, NULL);
Py_DECREF(method);
if (owner == NULL) {
Py_DECREF(eo);
Py_DECREF(proxy_roles);
goto err;
}
Py_DECREF(eo);
if (owner != Py_None) {
if (containerbase != container) {
tmp = callmethod1(owner,_check_context_str,
container
);
if (tmp == NULL) {
Py_DECREF(proxy_roles);
Py_DECREF(owner);
goto err;
}
if (!PyObject_IsTrue(tmp)) {
Py_DECREF(proxy_roles);
Py_DECREF(owner);
Py_DECREF(tmp);
unauthErr(name, value);
goto err;
}
Py_DECREF(tmp);
}
Py_DECREF(owner);
}
contains = 0;
if (PyTuple_Check(proxy_roles))
{
l=PyTuple_GET_SIZE(proxy_roles);
for (i=0; i < l; i++)
{
r=PyTuple_GET_ITEM(proxy_roles, i);
if ((contains = PySequence_Contains(roles, r)))
break;
}
}
else
{
l=PySequence_Size(proxy_roles);
if (l < 0) contains = -1;
for (i=0; i < l; i++)
{
if ((r=PySequence_GetItem(proxy_roles, i)))
{
contains = PySequence_Contains(roles, r);
Py_DECREF(r);
}
else
contains = -1;
if (contains < 0)
break;
}
}
Py_DECREF(proxy_roles);
if (contains > 0)
rval = PyInt_FromLong(contains);
else if (contains == 0) {
unauthErr(name, value);
}
goto err;
}
else {
Py_DECREF(eo);
Py_DECREF(proxy_roles);
}
} /* End of stack check */
/*| try:
**| if context.user.allowed(value, roles): return 1
**| except AttributeError: pass
*/
if (authenticated) { /* Authentication skip for public only access */
user = PyObject_GetAttr(context, user_str);
if (user) ASSIGN(user, PyObject_GetAttr(user, allowed_str));
if (user == NULL)
{
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear();
else
goto err;
}
else
{
ASSIGN(user, callfunction2(user, value, roles));
if (user == NULL) goto err;
if (PyObject_IsTrue(user))
{
rval = PyInt_FromLong(1);
Py_DECREF(user);
goto err;
}
Py_DECREF(user);
}
} /* End of authentiction skip for public only access */
/*| raise Unauthorized(name, value)
*/
unauthErr(name, value);
err:
Py_XDECREF(containerbase);
Py_XDECREF(accessedbase);
Py_XDECREF(stack);
Py_XDECREF(roles);
return rval;
}
/*
** ZopeSecurityPolicy_dealloc
**
*/
static void ZopeSecurityPolicy_dealloc(ZopeSecurityPolicy *self) {
Py_DECREF(self->ob_type); /* Extensionclass init incref'd */
PyObject_DEL(self);
}
/* SecurityManager */
#define CHECK_SECURITY_MANAGER_STATE(self, R) \
UNLESS (self->policy) { \
PyErr_SetString(PyExc_AttributeError, "_policy"); return R; } \
UNLESS (self->context) { \
PyErr_SetString(PyExc_AttributeError, "_policy"); return R; }
#define GET_SECURITY_MANAGER_VALIDATE(self, R) \
if (self->validate == NULL && \
((self->validate = PyObject_GetAttr(self->policy, validate_str)) \
== NULL)) return R;
static PyObject *
SecurityManager_validate(SecurityManager *self, PyObject *args)
{
PyObject *accessed=Py_None, *container=Py_None, *name=Py_None,
*value=Py_None, *roles=NULL;
if (unpacktuple5(args, "validate", 0,
&accessed, &container, &name, &value, &roles) < 0)
return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
GET_SECURITY_MANAGER_VALIDATE(self, NULL);
if (roles== NULL)
return callfunction5(self->validate,
accessed, container, name, value, self->context);
return callfunction6(self->validate,
accessed, container, name, value, self->context, roles);
}
static PyObject *
SecurityManager_DTMLValidate(SecurityManager *self, PyObject *args)
{
PyObject *accessed=Py_None, *container=Py_None, *name=Py_None,
*value=Py_None, *md=NULL;
if (unpacktuple5(args, "DTMLValidate", 0,
&accessed, &container, &name, &value, &md) < 0)
return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
GET_SECURITY_MANAGER_VALIDATE(self, NULL);
return callfunction5(self->validate,
accessed, container, name, value, self->context);
}
static PyObject *
SecurityManager_checkPermission(SecurityManager *self, PyObject *args)
{
PyObject *permission, *object;
if (unpacktuple2(args, "checkPermission", 2, &permission, &object) < 0)
return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
if (self->checkPermission == NULL &&
((self->checkPermission = PyObject_GetAttr(self->policy,
checkPermission_str))
== NULL)) return NULL;
return callfunction3(self->checkPermission,
permission, object, self->context);
}
static void
SecurityManager_dealloc(SecurityManager *self)
{
Py_XDECREF(self->thread_id);
Py_XDECREF(self->context);
Py_XDECREF(self->policy);
Py_XDECREF(self->validate);
Py_XDECREF(self->checkPermission);
Py_DECREF(self->ob_type); /* Extensionclass init incref'd */
PyObject_DEL(self);
}
static PyObject *
SecurityManager_getattro(SecurityManager *self, PyObject *name)
{
if (PyString_Check(name) || PyUnicode_Check(name)) {
char *name_s = PyString_AsString(name);
if (name_s == NULL)
return NULL;
if (name_s[0] == '_') {
if (! strcmp(name_s, "_thread_id") && self->thread_id) {
Py_INCREF(self->thread_id);
return self->thread_id;
}
else if (! strcmp(name_s, "_context") && self->context) {
Py_INCREF(self->context);
return self->context;
}
else if (! strcmp(name_s, "_policy") && self->policy) {
Py_INCREF(self->policy);
return self->policy;
}
}
}
return Py_FindAttr(OBJECT(self), name);
}
static int
SecurityManager_setattro(SecurityManager *self, PyObject *name, PyObject *v)
{
if (PyString_Check(name) || PyUnicode_Check(name)) {
char *name_s = PyString_AsString(name);
if (name_s == NULL)
return -1;
if (name_s[0] == '_')
{
if (! strcmp(name_s, "_thread_id"))
{
Py_INCREF(v);
ASSIGN(self->thread_id, v);
return 0;
}
else if (! strcmp(name_s, "_context"))
{
Py_INCREF(v);
ASSIGN(self->context, v);
return 0;
}
else if (! strcmp(name_s, "_policy"))
{
Py_INCREF(v);
ASSIGN(self->policy, v);
if (self->validate)
{
Py_DECREF(self->validate);
self->validate=0;
}
if (self->checkPermission)
{
Py_DECREF(self->checkPermission);
self->checkPermission=0;
}
return 0;
}
}
}
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
}
/*
** PermissionRole_init
**
*/
static PyObject *PermissionRole_init(PermissionRole *self, PyObject *args) {
PyObject *name = NULL;
PyObject *deflt = NULL;
/*|def __init__(self, name, default=('Manager',)):
**| self.__name__ = name
**| self._p = "_" + string.translate(name, name_trans) + "_Permission"
**| self._d = default
*/
if (unpacktuple2(args, "__init__", 1, &name, &deflt) < 0) return NULL;
if (deflt == NULL) deflt = defaultPermission;
UNLESS(self->_p = permissionName(name)) return NULL;
self->__name__ = name;
Py_INCREF(name);
self->__roles__ = deflt;
Py_INCREF(deflt);
Py_INCREF(Py_None);
return Py_None;
}
/*
def __of__(self, parent):
*/
static PyObject *
PermissionRole_of(PermissionRole *self, PyObject *parent) {
imPermissionRole *r = NULL;
PyObject *_p = NULL;
PyObject *result = NULL;
/*| r = imPermissionRole()
*/
r = (imPermissionRole*)PyObject_CallObject(imPermissionRoleObj, NULL);
if (r == NULL) return NULL;
/*| r._p = self._p
*/
r->_p = self->_p;
Py_INCREF(r->_p);
/*| r._pa = parent
*/
r->_pa = parent;
Py_INCREF(parent);
/*| r._d = self._d
*/
r->__roles__ = self->__roles__;
Py_INCREF(r->__roles__);
/*| p = getattr(parent, 'aq_inner', None)
**| if p is not None:
**| return r.__of__(p)
**| else:
**| return r
*/
if (aq_isWrapper(parent)) {
_p = aq_inner(parent);
result = callmethod1(OBJECT(r), __of__, _p);
Py_DECREF(_p);
/* Dont need goto */
} else {
result = OBJECT(r);
Py_INCREF(r);
}
Py_DECREF(r);
return result;
}
/*
def rolesForPermissionOn(self, value):
return rolesForPermissionOn(None, value, self._d, self._p)
*/
static PyObject *
PermissionRole_rolesForPermissionOn(PermissionRole *self, PyObject *value)
{
return c_rolesForPermissionOn(NULL, value, self->__roles__, self->_p);
}
/*
** PermissionRole_dealloc
**
*/
static void PermissionRole_dealloc(PermissionRole *self) {
Py_XDECREF(self->__name__);
Py_XDECREF(self->_p);
Py_XDECREF(self->__roles__);
Py_XDECREF(self->ob_type); /* Extensionclass init incref'd */
PyObject_DEL(self);
}
/* for DocFinder */
/*
** PermissionRole_getattro
**
*/
static PyObject *
PermissionRole_getattro(PermissionRole *self, PyObject *name) {
PyObject *result = NULL;
char *name_s = PyString_AsString(name);
/* see whether we know the attribute */
/* we support both the old "_d" (from the Python implementation)
and the new "__roles__"
*/
if (name_s == NULL)
PyErr_Clear(); /* defer to ExtensionClassGetattro */
else if (name_s[0] == '_') {
if (! strcmp(name_s, "__name__"))
result = self->__name__;
else if (! strcmp(name_s, "__roles__"))
result = self->__roles__;
else if (! strcmp(name_s, "_p"))
result = self->_p;
else if (! strcmp(name_s, "_d"))
result = self->__roles__;
}
if (result) {
Py_INCREF(result);
return result;
}
else
return ExtensionClassGetattro((PyObject *)self, name);
}
/*
def __of__(self, value):
return rolesForPermissionOn(None, value, self._d, self._p)
*/
static PyObject *
imPermissionRole_of(imPermissionRole *self, PyObject *value) {
return c_rolesForPermissionOn(NULL, value, self->__roles__, self->_p);
}
/*
** imPermissionRole_length
*/
static Py_ssize_t imPermissionRole_length(imPermissionRole *self) {
Py_ssize_t l;
PyObject *v;
PyObject *pa;
/*|
**| try:
**| v=self._v
**| except:
**| v = self._v = self.__of__(self._pa)
**| del self._pa
**|
**| return len(v)
*/
v = self->_v;
if (v == NULL) {
pa = self->_pa;
if (pa == NULL) {
PyErr_SetString(PyExc_AttributeError, "_pa");
return -1;
}
v = callmethod1(OBJECT(self), __of__, pa);
if (v == NULL)
return -1;
self->_v = v;
Py_DECREF(pa);
self->_pa = NULL;
}
l = PyObject_Length(v);
return l;
}
/*
** imPermissionRole_get
*/
static PyObject *imPermissionRole_get(imPermissionRole *self,
Py_ssize_t item) {
PyObject *v;
PyObject *pa;
PyObject *result;
/*| try:
**| v = self._v
**| except:
**| v = self._v = self.__of__(self._pa)
**| del self._pa
**| return v[i]
*/
v = self->_v;
if (v == NULL) {
pa = self->_pa;
if (pa == NULL) {
PyErr_SetString(PyExc_AttributeError, "_pa");
return NULL;
}
v = callmethod1(OBJECT(self), __of__, pa);
if (v == NULL)
return NULL;
self->_v = v;
Py_DECREF(pa);
self->_pa = NULL;
}
result = PySequence_GetItem(v, item);
return result;
}
/*
** imPermissionRole_dealloc
**
*/
static void imPermissionRole_dealloc(imPermissionRole *self) {
Py_XDECREF(self->_p);
Py_XDECREF(self->_pa);
Py_XDECREF(self->__roles__);
Py_XDECREF(self->_v);
Py_DECREF(self->ob_type); /* Extensionclass init incref'd */
PyObject_DEL(self);
}
/*
** rolesForPermissionOn
*/
static PyObject *rolesForPermissionOn(PyObject *self, PyObject *args) {
PyObject *perm = NULL;
PyObject *object = NULL;
PyObject *deflt = NULL;
PyObject *n = NULL;
/*|def rolesForPermissionOn(perm, object, default=('Manager',)):
**|
**| """Return the roles that have the permisson on the given object"""
*/
if (unpacktuple4(args, "rolesForPermissionOn", 2,
&perm, &object, &deflt, &n) < 0)
return NULL;
return c_rolesForPermissionOn(perm, object, deflt, n);
}
/*
def rolesForPermissionOn(perm, object, default=_default_roles, n=None):
"""Return the roles that have the given permission on the given object
"""
*/
static PyObject *
c_rolesForPermissionOn(PyObject *perm, PyObject *object,
PyObject *_default_roles, PyObject *n)
{
PyObject *r, *result = NULL;
/*
n = n or '_' + string.translate(perm, name_trans) + "_Permission"
*/
if (n)
Py_INCREF(n);
else
{
n = permissionName(perm);
if (n == NULL)
return NULL;
}
Py_INCREF(object);
/*
r = None
*/
r = Py_None;
Py_INCREF(r);
/*
while 1:
*/
while (1)
{
/*
if hasattr(object, n):
roles = getattr(object, n)
*/
PyObject *roles = PyObject_GetAttr(object, n);
if (roles != NULL)
{
/*
if roles is None:
return 'Anonymous',
*/
if (roles == Py_None)
{
Py_DECREF(roles);
result = AnonymousTuple;
Py_INCREF(result);
goto end;
}
/*
t = type(roles)
*/
/*
if t is tuple:
# If we get a tuple, then we don't acquire
if r is None:
return roles
return r+list(roles)
*/
if (PyTuple_Check(roles))
{
if (r == Py_None)
result = roles;
else
{
PyObject *list_roles = PySequence_List(roles);
Py_DECREF(roles);
if (list_roles == NULL)
goto end;
result = PySequence_Concat(r, list_roles);
Py_DECREF(list_roles);
}
goto end;
}
/*
if t is str:
# We found roles set to a name. Start over
# with the new permission name. If the permission
# name is '', then treat as private!
if roles:
n = roles
else:
return _what_not_even_god_should_do
*/
if (PyString_Check(roles))
{
if (PyString_GET_SIZE(roles))
{
Py_DECREF(n);
n = roles;
}
else
{
Py_DECREF(roles);
result = _what_not_even_god_should_do;
Py_INCREF(result);
goto end;
}
}
/*
elif roles:
if r is None:
r = list(roles)
else: r = r + list(roles)
*/
else
{
int bool = PyObject_IsTrue(roles);
if (bool < 0)
goto end;
if (bool)
{
PyObject *list_roles = PySequence_List(roles);
Py_DECREF(roles);
if (list_roles == NULL)
goto end;
if (r == Py_None)
{
Py_DECREF(r);
r = list_roles;
}
else
{
PyObject *tmp = PySequence_Concat(r, list_roles);
Py_DECREF(list_roles);
if (tmp == NULL)
goto end;
Py_DECREF(r);
r = tmp;
}
}
}
}
else /* roles == NULL */
PyErr_Clear();
/*
object = aq_inner(object)
if object is None:
break
object = aq_parent(object)
*/
{
PyObject *tobj = aq_inner(object);
if (tobj == NULL)
goto end;
Py_DECREF(object);
object = tobj;
if (object == Py_None)
break;
tobj = aq_parent(object);
if (tobj == NULL)
goto end;
Py_DECREF(object);
object = tobj;
}
}
/*
if r is None:
return default
return r
*/
if (r == Py_None)
{
result = _default_roles;
if (result == NULL)
result = ManagerTuple;
Py_INCREF(result);
goto end;
}
Py_INCREF(r);
result = r;
end:
Py_DECREF(n);
Py_DECREF(object);
Py_DECREF(r);
return result;
}
/*
** permissionName
**
** Can silently truncate permission names if they are really long
*/
static PyObject *permissionName(PyObject *name) {
char namebuff[512];
register int len = sizeof(namebuff) - 1;
char *c = namebuff;
char *in;
char r;
*c = '_';
c++;
len--;
in = PyString_AsString(name);
if (in == NULL)
return NULL;
while (len && *in) {
r = *(in++);
if (!isalnum(r)) r='_';
*(c++) = r;
len--;
}
if (len) {
in = "_Permission";
while (len && *in) {
*(c++) = *(in++);
len--;
}
}
*c = '\0'; /* Saved room in len */
return PyString_FromString(namebuff);
}
/* def guarded_getattr(inst, name, default=_marker): */
static PyObject *
guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
PyObject *validate)
{
PyObject *v=0, *t=0;
int i;
/* if name[:1] != '_': */
if (PyString_Check(name) || PyUnicode_Check(name)) {
char *name_s = PyString_AsString(name);
if (name_s == NULL)
return NULL;
if (name_s[0] != '_')
{
/*
# Try to get the attribute normally so that unusual
# exceptions are caught early.
try: v = getattr(inst, name)
except AttributeError:
if default is not _marker:
return default
raise
*/
v=PyObject_GetAttr(inst, name);
if (v==NULL)
{
if (default_ && PyErr_Occurred() == PyExc_AttributeError)
{
PyErr_Clear();
Py_INCREF(default_);
return default_;
}
return NULL;
}
/*
assertion = Containers(type(inst))
*/
t = PyDict_GetItem(ContainerAssertions, OBJECT(inst->ob_type));
if (t != NULL)
{
/*
if isinstance(assertion, dict):
# We got a table that lets us reason about individual
# attrs
assertion = assertion.get(name)
if assertion:
# There's an entry, but it may be a function.
if callable(assertion):
return assertion(inst, name)
# Nope, it's boolean
return v
raise Unauthorized, name
*/
if (PyDict_Check(t))
{
PyObject *attrv;
attrv = PyDict_GetItem(t, name);
if (attrv != NULL)
{
i=PyObject_IsTrue(attrv);
if (i < 0) goto err;
if (i)
{
if (attrv->ob_type->tp_call)
{
Py_DECREF(v);
v = callfunction2(attrv, inst, name);
return v;
}
return v;
}
}
Py_DECREF(v);
goto unauth;
}
/*
if assertion:
if callable(assertion):
factory = assertion(name, v)
if callable(factory):
return factory(inst, name)
assert factory == 1
assert callable == 1
return v
*/
if (PyCallable_Check(t))
{
PyObject *factory;
factory = callfunction2(t, name, v);
if (factory == NULL)
goto err;
if (PyCallable_Check(factory))
{
Py_DECREF(v);
v = callfunction2(factory, inst, name);
}
Py_DECREF(factory);
}
return v;
}
/*
# See if we can get the value doing a filtered acquire.
# aq_acquire will either return the same value as held by
# v or it will return an Unauthorized raised by validate.
validate = SecurityManagement.getSecurityManager().validate
aq_acquire(inst, name, aq_validate, validate)
return v
*/
t = aq_Acquire(inst, name, aq_validate, validate, 1, NULL, 0);
if (t == NULL)
{
Py_DECREF(v);
return NULL;
}
Py_DECREF(t);
return v;
unauthErr(name, v);
err:
Py_DECREF(v);
return NULL;
}
}
unauth:
/* raise Unauthorized, name */
PyErr_SetObject(Unauthorized, name);
return NULL;
}
static PyObject *
module_guarded_getattr(PyObject *ignored, PyObject *args)
{
PyObject *inst, *name, *default_=0, *validate;
if (unpacktuple3(args, "guarded_getattr", 2, &inst, &name, &default_) < 0)
return NULL;
/*
validate = getSecurityManager().validate
*/
validate=PyObject_CallObject(getSecurityManager, NULL);
if (! validate) return NULL;
ASSIGN(validate, PyObject_GetAttr(validate, validate_str));
if (! validate) return NULL;
ASSIGN(validate, guarded_getattr(inst, name, default_, validate));
return validate;
}
/*
def aq_validate(inst, obj, name, v, validate):
return validate(inst, obj, name, v)
*/
static PyObject *
module_aq_validate(PyObject *ignored, PyObject *args)
{
PyObject *inst=NULL, *obj=NULL, *name=NULL, *v=NULL, *validate=NULL;
if (unpacktuple5(args, "validate", 0,
&inst, &obj, &name, &v, &validate) < 0) return NULL;
return callfunction4(validate, inst, obj, name, v);
}
static PyObject *
module_setDefaultBehaviors(PyObject *ignored, PyObject *args)
{
PyObject *result = NULL;
int own, auth, verbose;
if (PyArg_ParseTuple(args, "iii:setDefaultBehaviors", &own, &auth,
&verbose)) {
if (verbose) {
PyErr_SetString(PyExc_NotImplementedError,
"This security policy implementation does not implement "
"the verbose option. To enable verbose security "
"exceptions, add 'security-policy-implementation "
"python' to etc/zope.conf.");
return NULL;
}
ownerous = own;
authenticated = authenticated;
result = Py_None;
Py_INCREF(result);
}
return result;
}
static PyObject *
dtml_guarded_getattr(PyObject *self, PyObject *args)
{
PyObject *ob, *name, *default_=0, *validate;
if (unpacktuple3(args, "guarded_getattr", 2, &ob, &name, &default_) < 0)
return NULL;
UNLESS (validate = PyObject_GetAttr(self, validate_str))
{
/* This section is pure paranoia at this point. It was necessary
while debugging. */
PyErr_Clear();
validate=PyObject_CallObject(getSecurityManager, NULL);
if (! validate) return NULL;
ASSIGN(validate, PyObject_GetAttr(validate, validate_str));
if (! validate) return NULL;
}
ASSIGN(validate, guarded_getattr(ob, name, default_, validate));
return validate;
}
static struct PyMethodDef dtml_methods[] = {
{"guarded_getattr", (PyCFunction)dtml_guarded_getattr,
METH_VARARGS|METH_KEYWORDS, "" },
{NULL, NULL}
};
/* ----------------------------------------------------------------
** Module initialization
** ----------------------------------------------------------------
*/
#define IMPORT(module, name) if ((module = PyImport_ImportModule(name)) == NULL) return;
#define GETATTR(module, name) if ((name = PyObject_GetAttrString(module, #name)) == NULL) return;
void initcAccessControl(void) {
PyObject *module;
PyObject *dict;
PURE_MIXIN_CLASS(RestrictedDTMLMixin,
"A mix-in for derivatives of DT_String.String "
"that adds Zope security."
, dtml_methods);
if (!ExtensionClassImported) return;
if (ZopeSecurityPolicy_setup() < 0) return;
ExtensionClassGetattro= Py_FindAttr;
module = Py_InitModule3("cAccessControl",
cAccessControl_methods,
"cAccessControl.c\n");
aq_init(); /* For Python <= 2.1.1, aq_init() should be after
Py_InitModule(). */
dict = PyModule_GetDict(module);
PyDict_SetItemString(dict, "_what_not_even_god_should_do",
_what_not_even_god_should_do);
PyExtensionClass_Export(dict, "RestrictedDTMLMixin",
RestrictedDTMLMixinType);
PyExtensionClass_Export(dict, "ZopeSecurityPolicy",
ZopeSecurityPolicyType);
PyExtensionClass_Export(dict,"SecurityManager",
SecurityManagerType);
PyExtensionClass_Export(dict, "PermissionRole",
PermissionRoleType);
PyExtensionClass_Export(dict, "imPermissionRole",
imPermissionRoleType);
imPermissionRoleObj = PyMapping_GetItemString(dict,
"imPermissionRole");
aq_validate = PyMapping_GetItemString(dict, "aq_validate");
/*| from SimpleObjectPolicies import Containers
*/
IMPORT(module, "AccessControl.SimpleObjectPolicies");
GETATTR(module, Containers);
GETATTR(module, ContainerAssertions);
Py_DECREF(module);
module = NULL;
/*| from ZopeSecurityPolicy import getRoles
*/
IMPORT(module, "AccessControl.ZopeSecurityPolicy");
GETATTR(module, getRoles);
Py_DECREF(module);
module = NULL;
/*| from unauthorized import Unauthorized
*/
IMPORT(module, "AccessControl.unauthorized");
GETATTR(module, Unauthorized);
Py_DECREF(module);
module = NULL;
/*| from AccessControl.SecurityManagement import getSecurityManager
*/
IMPORT(module, "AccessControl.SecurityManagement");
GETATTR(module, getSecurityManager);
Py_DECREF(module);
module = NULL;
/*| from logger_wrapper import warn
*/
IMPORT(module, "AccessControl.logger_wrapper");
GETATTR(module, warn);
Py_DECREF(module);
module = NULL;
}
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Class initialization.
"""
import logging
from AccessControl.Permission import ApplicationDefaultPermissions # BBB
def InitializeClass(self):
from AccessControl.Permission import registerPermissions
from AccessControl.PermissionRole import PermissionRole
dict=self.__dict__
have=dict.has_key
ft=type(InitializeClass)
dict_items=dict.items()
for name, v in dict_items:
if getattr(v, '_need__name__', 0):
d = v.__dict__
oldname = d.get('__name__', '')
if d.get('_implicit__name__', 0):
# Already supplied a name.
if name != oldname:
# Tried to implicitly assign a different name!
try: classname = '%s.%s' % (
self.__module__, self.__name__)
except AttributeError: classname = `self`
logging.getLogger("Init").warning(
'Ambiguous name for method of %s: %r != %r',
classname, d['__name__'], name)
else:
# Supply a name implicitly so that the method can
# find the security assertions on its container.
v._implicit__name__ = 1
v.__name__ = name
if name=='manage' or name[:7]=='manage_':
name=name+'__roles__'
if not have(name):
setattr(self, name, ('Manager',))
elif name=='manage' or name[:7]=='manage_' and type(v) is ft:
name=name+'__roles__'
if not have(name):
setattr(self, name, ('Manager',))
# Look for a SecurityInfo object on the class. If found, call its
# apply() method to generate __ac_permissions__ for the class. We
# delete the SecurityInfo from the class dict after it has been
# applied out of paranoia.
for key, value in dict_items:
if hasattr(value, '__security_info__'):
security_info=value
security_info.apply(self)
delattr(self, key)
break
if self.__dict__.has_key('__ac_permissions__'):
registerPermissions(self.__ac_permissions__)
for acp in self.__ac_permissions__:
pname, mnames = acp[:2]
if len(acp) > 2:
roles = acp[2]
pr = PermissionRole(pname, roles)
else:
pr = PermissionRole(pname)
for mname in mnames:
setattr(self, mname+'__roles__', pr)
if (mname and mname not in ('context', 'request') and
not hasattr(self, mname)):
# don't complain about context or request, as they are
# frequently not available as class attributes
logging.getLogger("Init").warning(
"Class %s.%s has a security declaration for "
"nonexistent method %r", self.__module__,
self.__name__, mname)
default__class_init__ = InitializeClass # BBB: old name
<configure xmlns="http://namespaces.zope.org/zope">
<include file="permissions.zcml"/>
</configure>
##############################################################################
#
# Copyright (c) 2005 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""AccessControl interfaces.
"""
from AccessControl.SimpleObjectPolicies import _noroles
from zope.interface import Attribute
from zope.interface import Interface
class IOwned(Interface):
def owner_info():
"""Get ownership info for display
"""
def getOwner(info=0):
"""Get the owner
If a true argument is provided, then only the owner path and id are
returned. Otherwise, the owner object is returned.
"""
def getOwnerTuple():
"""Return a tuple, (userdb_path, user_id) for the owner.
o Ownership can be acquired, but only from the containment path.
o If unowned, return None.
"""
def getWrappedOwner():
"""Get the owner, modestly wrapped in the user folder.
o If the object is not owned, return None.
o If the owner's user database doesn't exist, return Nobody.
o If the owner ID does not exist in the user database, return Nobody.
"""
def changeOwnership(user, recursive=0):
"""Change the ownership to the given user.
If 'recursive' is true then also take ownership of all sub-objects,
otherwise sub-objects retain their ownership information.
"""
def userCanTakeOwnership():
"""
"""
def _deleteOwnershipAfterAdd():
"""
"""
def manage_fixupOwnershipAfterAdd():
"""
"""
class IPermissionMappingSupport(Interface):
def manage_getPermissionMapping():
"""Return the permission mapping for the object
This is a list of dictionaries with:
permission_name -- The name of the native object permission
class_permission -- The class permission the permission is
mapped to.
"""
def manage_setPermissionMapping(permission_names=[],
class_permissions=[], REQUEST=None):
"""Change the permission mapping
"""
class IRoleManager(IPermissionMappingSupport):
"""An object that has configurable permissions"""
permissionMappingPossibleValues = Attribute("""Acquired attribute""")
def ac_inherited_permissions(all=0):
"""Get all permissions not defined in ourself that are inherited.
This will be a sequence of tuples with a name as the first item and an
empty tuple as the second.
"""
def permission_settings(permission=None):
"""Return user-role permission settings.
If 'permission' is passed to the method then only the settings for
'permission' is returned.
"""
def manage_role(role_to_manage, permissions=[]):
"""Change the permissions given to the given role.
"""
def manage_acquiredPermissions(permissions=[]):
"""Change the permissions that acquire.
"""
def manage_permission(permission_to_manage, roles=[], acquire=0):
"""Change the settings for the given permission.
If optional arg acquire is true, then the roles for the permission
are acquired, in addition to the ones specified, otherwise the
permissions are restricted to only the designated roles.
"""
def permissionsOfRole(role):
"""Returns a role to permission mapping.
"""
def rolesOfPermission(permission):
"""Returns a permission to role mapping.
"""
def acquiredRolesAreUsedBy(permission):
"""
"""
def has_local_roles():
"""
"""
def get_local_roles():
"""
"""
def users_with_local_role(role):
"""
"""
def get_valid_userids():
"""
"""
def get_local_roles_for_userid(userid):
"""
"""
def manage_addLocalRoles(userid, roles):
"""Set local roles for a user."""
def manage_setLocalRoles(userid, roles):
"""Set local roles for a user."""
def manage_delLocalRoles(userids):
"""Remove all local roles for a user."""
#------------------------------------------------------------
def access_debug_info():
"""Return debug info.
"""
def valid_roles():
"""Return list of valid roles.
"""
def validate_roles(roles):
"""Return true if all given roles are valid.
"""
def userdefined_roles():
"""Return list of user-defined roles.
"""
def possible_permissions():
"""
"""
def manage_getUserRolesAndPermissions(user_id):
""" Used for permission/role reporting for a given user_id.
Returns a dict mapping
'user_defined_in' -> path where the user account is defined
'roles' -> global roles,
'roles_in_context' -> roles in context of the current object,
'allowed_permissions' -> permissions allowed for the user,
'disallowed_permissions' -> all other permissions
"""
class IStandardUserFolder(Interface):
def getUser(name):
"""Get the user object specified by name.
If there is no user named 'name' in the user folder, return None.
"""
def getUsers():
"""Get a sequence of all user objects which reside in the user folder.
"""
def getUserNames():
"""Get a sequence of names of the users which reside in the user folder.
"""
class ISecurityPolicy(Interface):
"""Plug-in policy for checking access to objects within untrusted code.
"""
def validate(accessed, container, name, value, context, roles=_noroles):
"""Check that the current user (from context) has access.
o Raise Unauthorized if access is not allowed; otherwise, return
a true value.
Arguments:
accessed -- the object that was being accessed
container -- the object the value was found in
name -- The name used to access the value
value -- The value retrieved though the access.
context -- the security context (normally supplied by the security
manager).
roles -- The roles of the object if already known.
"""
def checkPermission(permission, object, context):
"""Check whether the current user has a permission w.r.t. an object.
"""
class ISecurityManager(Interface):
"""Check access and manages executable context and policies.
"""
_policy = Attribute(u'Current Security Policy')
def validate(accessed=None,
container=None,
name=None,
value=None,
roles=_noroles,
):
"""Validate access.
Arguments:
accessed -- the object that was being accessed
container -- the object the value was found in
name -- The name used to access the value
value -- The value retrieved though the access.
roles -- The roles of the object if already known.
The arguments may be provided as keyword arguments. Some of these
arguments may be ommitted, however, the policy may reject access
in some cases when arguments are ommitted. It is best to provide
all the values possible.
"""
def DTMLValidate(accessed=None,
container=None,
name=None,
value=None,
md=None,
):
"""Validate access.
* THIS EXISTS FOR DTML COMPATIBILITY *
Arguments:
accessed -- the object that was being accessed
container -- the object the value was found in
name -- The name used to access the value
value -- The value retrieved though the access.
md -- multidict for DTML (ignored)
The arguments may be provided as keyword arguments. Some of these
arguments may be ommitted, however, the policy may reject access
in some cases when arguments are ommitted. It is best to provide
all the values possible.
"""
def checkPermission(permission, object):
"""Check whether the security context allows the given permission on
the given object.
Arguments:
permission -- A permission name
object -- The object being accessed according to the permission
"""
def addContext(anExecutableObject):
"""Add an ExecutableObject to the current security context.
o If it declares a custom security policy, make that policy
"current"; otherwise, make the "default" security policy
current.
"""
def removeContext(anExecutableObject):
"""Remove an ExecutableObject from the current security context.
o Remove all objects from the top of the stack "down" to the
supplied object.
o If the top object on the stack declares a custom security policy,
make that policy "current".
o If the stack is empty, or if the top declares no custom security
policy, restore the 'default" security policy as current.
"""
def getUser():
"""Get the currently authenticated user
"""
def calledByExecutable():
"""Return a boolean value indicating whether this context was called
in the context of an by an executable (i.e., one added via
'addContext').
"""
# A wrapper to replace the usage of the zLOG module in cAccessControl without
# having the need to change the C code significantly.
from logging import getLogger
LOG = getLogger('AccessControl')
warn = LOG.warn
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
<include package="zope.component" file="meta.zcml" />
<include package="zope.security" file="meta.zcml" />
<meta:directives namespace="http://namespaces.zope.org/zope">
<meta:complexDirective
name="class"
schema="zope.security.metadirectives.IClassDirective"
handler=".metaconfigure.ClassDirective"
>
<meta:subdirective
name="implements"
schema="zope.security.metadirectives.IImplementsSubdirective"
/>
<meta:subdirective
name="require"
schema="zope.security.metadirectives.IRequireSubdirective"
/>
<meta:subdirective
name="allow"
schema="zope.security.metadirectives.IAllowSubdirective"
/>
</meta:complexDirective>
<meta:directive
name="securityPolicy"
schema="zope.security.zcml.ISecurityPolicyDirective"
handler="zope.security.zcml.securityPolicy"
/>
</meta:directives>
</configure>
##############################################################################
#
# Copyright (c) 2004, 2005 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import warnings
from zope.security import metaconfigure
from AccessControl.class_init import InitializeClass
from AccessControl.security import protectName
class ClassDirective(metaconfigure.ClassDirective):
def __protectName(self, name, permission_id):
self.__context.action(
discriminator = ('five:protectName', self.__class, name),
callable = protectName,
args = (self.__class, name, permission_id)
)
def __protectSetAttributes(self, names, permission_id):
warnings.warn("The set_attribute option of the <require /> directive "
"is not supported in Zope 2. "
"Ignored for %s" % str(self.__class), stacklevel=3)
def __protectSetSchema(self, schema, permission):
warnings.warn("The set_schema option of the <require /> directive "
"is not supported in Zope 2. "
"Ignored for %s" % str(self.__class), stacklevel=3)
def __mimic(self, _context, class_):
warnings.warn("The like_class option of the <require /> directive "
"is not supported in Zope 2. "
"Ignored for %s" % str(self.__class), stacklevel=3)
def __call__(self):
return self.__context.action(
discriminator = None,
callable = InitializeClass,
args = (self.__class,)
)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Support for owned objects
"""
from Acquisition import aq_base
from Acquisition import aq_get
from Acquisition import aq_inner
from Acquisition import aq_parent
from ExtensionClass import Base
from zope.interface import implements
from AccessControl.class_init import InitializeClass
from AccessControl.interfaces import IOwned
from AccessControl.Permissions import view_management_screens
from AccessControl.Permissions import take_ownership
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
# avoid importing 'emergency_user' / 'nobody' before set
from AccessControl import SpecialUsers as SU
UnownableOwner=[]
def ownableFilter(self):
_owner = aq_get(self, '_owner', None, 1)
return _owner is not UnownableOwner
# Marker to use as a getattr default.
_mark=ownableFilter
class Owned(Base):
implements(IOwned)
security = ClassSecurityInfo()
security.setPermissionDefault(take_ownership, ('Owner', ))
security.declareProtected(view_management_screens, 'owner_info')
def owner_info(self):
"""Get ownership info for display
"""
owner=self.getOwnerTuple()
if owner is None or owner is UnownableOwner:
return owner
d={'path': '/'.join(owner[0]), 'id': owner[1],
'explicit': hasattr(self, '_owner'),
'userCanChangeOwnershipType':
getSecurityManager().checkPermission('Take ownership', self)
}
return d
security.declarePrivate('getOwner')
def getOwner(self, info=0,
aq_get=aq_get,
UnownableOwner=UnownableOwner,
getSecurityManager=getSecurityManager,
):
"""Get the owner
If a true argument is provided, then only the owner path and id are
returned. Otherwise, the owner object is returned.
"""
if info:
import warnings
warnings.warn('Owned.getOwner(1) is deprecated; '
'please use getOwnerTuple() instead.',
DeprecationWarning, stacklevel=2)
owner=aq_get(self, '_owner', None, 1)
if info or (owner is None): return owner
if owner is UnownableOwner: return None
udb, oid = owner
root=self.getPhysicalRoot()
udb=root.unrestrictedTraverse(udb, None)
if udb is None:
user = SU.nobody
else:
user = udb.getUserById(oid, None)
if user is None: user = SU.nobody
return user
security.declarePrivate('getOwnerTuple')
def getOwnerTuple(self):
"""Return a tuple, (userdb_path, user_id) for the owner.
o Ownership can be acquired, but only from the containment path.
o If unowned, return None.
"""
return aq_get(self, '_owner', None, 1)
security.declarePrivate('getWrappedOwner')
def getWrappedOwner(self):
"""Get the owner, modestly wrapped in the user folder.
o If the object is not owned, return None.
o If the owner's user database doesn't exist, return Nobody.
o If the owner ID does not exist in the user database, return Nobody.
"""
owner = self.getOwnerTuple()
if owner is None or owner is UnownableOwner:
return None
udb_path, oid = owner
root = self.getPhysicalRoot()
udb = root.unrestrictedTraverse(udb_path, None)
if udb is None:
return SU.nobody
user = udb.getUserById(oid, None)
if user is None:
return SU.nobody
return user.__of__(udb)
security.declarePrivate('changeOwnership')
def changeOwnership(self, user, recursive=0):
"""Change the ownership to the given user.
If 'recursive' is true then also take ownership of all sub-objects,
otherwise sub-objects retain their ownership information.
"""
new = ownerInfo(user)
if new is None:
return # Special user!
old = self.getOwnerTuple()
if not recursive:
if old == new or old is UnownableOwner:
return
if recursive:
children = getattr( aq_base(self), 'objectValues', lambda :() )()
for child in children:
child.changeOwnership(user, 1)
if old is not UnownableOwner:
self._owner = new
def userCanTakeOwnership(self):
security=getSecurityManager()
user=security.getUser()
info=ownerInfo(user)
if info is None: return 0
owner=self.getOwnerTuple()
if owner == info: return 0
return security.checkPermission('Take ownership', self)
def _deleteOwnershipAfterAdd(self):
# Only delete _owner if it is an instance attribute.
if self.__dict__.get('_owner', _mark) is not _mark:
del self._owner
for object in self.objectValues():
try: s=object._p_changed
except: s=0
try: object._deleteOwnershipAfterAdd()
except: pass
if s is None: object._p_deactivate()
def manage_fixupOwnershipAfterAdd(self):
# Sigh, get the parent's _owner
parent=getattr(self, '__parent__', None)
if parent is not None: _owner=aq_get(parent, '_owner', None, 1)
else: _owner=None
if (_owner is None and
((getattr(self, '__parent__', None) is None) or
(not hasattr(self, 'getPhysicalRoot'))
)
):
# This is a special case. An object is
# being added to an object that hasn't
# been added to the object hierarchy yet.
# We can delay fixing up the ownership until the
# object is actually added.
return None
if _owner is UnownableOwner:
# We want to acquire Unownable ownership!
return self._deleteOwnershipAfterAdd()
else:
# Otherwise change the ownership
user=getSecurityManager().getUser()
if (SU.emergency_user and aq_base(user) is SU.emergency_user):
__creatable_by_emergency_user__=getattr(
self,'__creatable_by_emergency_user__', None)
if (__creatable_by_emergency_user__ is None or
(not __creatable_by_emergency_user__())):
raise EmergencyUserCannotOwn(
"Objects cannot be owned by the emergency user")
self.changeOwnership(user)
# Force all subs to acquire ownership!
for object in self.objectValues():
try: s=object._p_changed
except: s=0
try: object._deleteOwnershipAfterAdd()
except: pass
if s is None: object._p_deactivate()
InitializeClass(Owned)
class EmergencyUserCannotOwn(Exception):
"The emergency user cannot own anything"
class EditUnowned(Exception):
"Can't edit unowned executables"
def absattr(attr):
if callable(attr): return attr()
return attr
def ownerInfo(user, getattr=getattr):
if user is None:
return None
uid=user.getId()
if uid is None: return uid
db=aq_parent(aq_inner(user))
path=[absattr(db.id)]
root=db.getPhysicalRoot()
while 1:
db=getattr(db,'aq_inner', None)
if db is None: break
db=aq_parent(db)
if db is root: break
id=db.id
if not isinstance(id, str):
try: id=id()
except: id=str(id)
path.append(id)
path.reverse()
return path, uid
<configure xmlns="http://namespaces.zope.org/zope"
i18n_domain="Zope2">
<!-- Create permissions declared in ZCML if they don't exist already -->
<subscriber
for="zope.security.interfaces.IPermission
zope.component.interfaces.IRegistered"
handler=".security.create_permission_from_permission_directive"
/>
<permission
id="zope2.Public"
title="Public, everyone can access"
/>
<permission
id="zope2.Private"
title="Private, only accessible from trusted code"
/>
<permission
id="zope2.AccessContentsInformation"
title="Access contents information"
/>
<permission
id="zope2.ChangeImagesFiles"
title="Change Images and Files"
/>
<permission
id="zope2.ChangeConfig"
title="Change configuration"
/>
<permission
id="zope2.ChangePermissions"
title="Change permissions"
/>
<permission
id="zope2.CopyOrMove"
title="Copy or Move"
/>
<permission
id="zope2.DefinePermissions"
title="Define permissions"
/>
<permission
id="zope2.DeleteObjects"
title="Delete objects"
/>
<permission
id="zope2.FTPAccess"
title="FTP access"
/>
<permission
id="zope2.ImportExport"
title="Import/Export objects"
/>
<permission
id="zope2.ManageProperties"
title="Manage properties"
/>
<permission
id="zope2.ManageUsers"
title="Manage users"
/>
<permission
id="zope2.Undo"
title="Undo changes"
/>
<permission
id="zope2.View"
title="View"
/>
<permission
id="zope2.ViewHistory"
title="View History"
/>
<permission
id="zope2.ViewManagementScreens"
title="View management screens"
/>
<permission
id="zope2.WebDAVLock"
title="WebDAV Lock items"
/>
<permission
id="zope2.WebDAVUnlock"
title="WebDAV Unlock items"
/>
<permission
id="zope2.WebDAVAccess"
title="WebDAV access"
/>
</configure>
#############################################################################
#
# Copyright (c) 2007 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import inspect
from zExceptions import Forbidden
from zope.publisher.interfaces.browser import IBrowserRequest
_default = []
def _buildFacade(name, spec, docstring):
"""Build a facade function, matching the decorated method in signature.
Note that defaults are replaced by _default, and _curried will reconstruct
these to preserve mutable defaults.
"""
args = inspect.formatargspec(formatvalue=lambda v: '=_default', *spec)
callargs = inspect.formatargspec(formatvalue=lambda v: '', *spec)
return 'def %s%s:\n """%s"""\n return _curried%s' % (
name, args, docstring, callargs)
def requestmethod(*methods):
"""Create a request method specific decorator"""
methods = map(lambda m: m.upper(), methods)
if len(methods) > 1:
methodsstr = ', '.join(methods[:-1])
methodsstr += ' or ' + methods[-1]
else:
methodsstr = methods[0]
def _methodtest(callable):
"""Only allow callable when request method is %s.""" % methodsstr
spec = inspect.getargspec(callable)
args, defaults = spec[0], spec[3]
try:
r_index = args.index('REQUEST')
except ValueError:
raise ValueError('No REQUEST parameter in callable signature')
arglen = len(args)
if defaults is not None:
defaults = zip(args[arglen - len(defaults):], defaults)
arglen -= len(defaults)
def _curried(*args, **kw):
request = args[r_index]
if IBrowserRequest.providedBy(request):
if request.method not in methods:
raise Forbidden('Request must be %s' % methodsstr)
# Reconstruct keyword arguments
if defaults is not None:
args, kwparams = args[:arglen], args[arglen:]
for positional, (key, default) in zip(kwparams, defaults):
if positional is _default:
kw[key] = default
else:
kw[key] = positional
return callable(*args, **kw)
# Build a facade, with a reference to our locally-scoped _curried
name = callable.__name__
facade_globs = dict(_curried=_curried, _default=_default)
exec _buildFacade(name, spec, callable.__doc__) in facade_globs
return facade_globs[name]
return _methodtest
# For Zope versions 2.8 - 2.10
postonly = requestmethod('POST')
__all__ = ('requestmethod', 'postonly')
Request method decorators
=========================
Using request method decorators, you can limit functions or methods to only
be callable when the HTTP request was made using a particular method.
To limit access to a function or method to POST requests, use the requestmethod
decorator factory::
>>> from AccessControl.requestmethod import requestmethod
>>> @requestmethod('POST')
... def foo(bar, REQUEST):
... return bar
When this method is accessed through a request that does not use POST, the
Forbidden exception will be raised::
>>> foo('spam', GET)
Traceback (most recent call last):
...
Forbidden: Request must be POST
Only when the request was made using POST, will the call succeed::
>>> foo('spam', POST)
'spam'
It doesn't matter if REQUEST is a positional or a keyword parameter::
>>> @requestmethod('POST')
... def foo(bar, REQUEST=None):
... return bar
>>> foo('spam', REQUEST=GET)
Traceback (most recent call last):
...
Forbidden: Request must be POST
*Not* passing an optional REQUEST always succeeds::
>>> foo('spam')
'spam'
Note that the REQUEST parameter is a requirement for the decorator to operate,
not including it in the callable signature results in an error::
>>> @requestmethod('POST')
... def foo(bar):
... return bar
Traceback (most recent call last):
...
ValueError: No REQUEST parameter in callable signature
Because the Zope Publisher uses introspection to match REQUEST variables
against callable signatures, the result of the decorator must match the
original closely, and keyword parameter defaults must be preserved::
>>> import inspect
>>> mutabledefault = dict()
>>> @requestmethod('POST')
... def foo(bar, baz=mutabledefault, egg=mutabledefault, REQUEST=None, *args):
... return bar, baz is mutabledefault, egg is None, REQUEST
>>> inspect.getargspec(foo)[:3]
(['bar', 'baz', 'egg', 'REQUEST'], 'args', None)
>>> foo('spam', egg=None)
('spam', True, True, None)
>>> foo(monty='python')
Traceback (most recent call last):
...
TypeError: foo() got an unexpected keyword argument 'monty'
The requestmethod decorator factory can be used for any request method, simply
pass in the desired request method::
>>> @requestmethod('PUT')
... def foo(bar, REQUEST=None):
... return bar
>>> foo('spam', GET)
Traceback (most recent call last):
...
Forbidden: Request must be PUT
You can pass in multiple request methods allow access by any of them::
>>> @requestmethod('GET', 'HEAD', 'PROPFIND')
... def foo(bar, REQUEST=None):
... return bar
>>> foo('spam', GET)
'spam'
>>> foo('spam', POST)
Traceback (most recent call last):
...
Forbidden: Request must be GET, HEAD or PROPFIND
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Access control support
"""
from cgi import escape
from Acquisition import Acquired
from Acquisition import aq_base
from Acquisition import aq_get
from ExtensionClass import Base
from zope.interface import implements
from AccessControl import ClassSecurityInfo
from AccessControl.class_init import InitializeClass
from AccessControl.interfaces import IRoleManager
from AccessControl.Permission import getPermissions
from AccessControl.Permission import Permission
from AccessControl.PermissionMapping import RoleManager
from AccessControl.Permissions import change_permissions
from AccessControl.SecurityManagement import newSecurityManager
DEFAULTMAXLISTUSERS = 250
def _isBeingUsedAsAMethod(self):
return aq_get(self, '_isBeingUsedAsAMethod_', 0)
def _isNotBeingUsedAsAMethod(self):
return not aq_get(self, '_isBeingUsedAsAMethod_', 0)
class RoleManager(Base, RoleManager):
"""An object that has configurable permissions"""
implements(IRoleManager)
permissionMappingPossibleValues=Acquired
security = ClassSecurityInfo()
__ac_roles__ = ('Manager', 'Owner', 'Anonymous', 'Authenticated')
__ac_local_roles__ = None
security.declareProtected(change_permissions, 'ac_inherited_permissions')
def ac_inherited_permissions(self, all=0):
# Get all permissions not defined in ourself that are inherited
# This will be a sequence of tuples with a name as the first item and
# an empty tuple as the second.
d = {}
perms = self.__ac_permissions__
for p in perms:
d[p[0]] = None
r = gather_permissions(self.__class__, [], d)
if all:
if hasattr(self, '_subobject_permissions'):
for p in self._subobject_permissions():
pname=p[0]
if not pname in d:
d[pname] = 1
r.append(p)
r = list(perms) + r
r.sort()
return tuple(r)
security.declareProtected(change_permissions, 'permission_settings')
def permission_settings(self, permission=None):
"""Return user-role permission settings.
If 'permission' is passed to the method then only the settings for
'permission' is returned.
"""
result=[]
valid=self.valid_roles()
indexes=range(len(valid))
ip=0
permissions = self.ac_inherited_permissions(1)
# Filter permissions
if permission:
permissions = [p for p in permissions if p[0] == permission]
for p in permissions:
name, value = p[:2]
p=Permission(name, value, self)
roles = p.getRoles(default=[])
d={'name': name,
'acquire': isinstance(roles, list) and 'CHECKED' or '',
'roles': map(
lambda ir, roles=roles, valid=valid, ip=ip:
{
'name': "p%dr%d" % (ip, ir),
'checked': (valid[ir] in roles) and 'CHECKED' or '',
},
indexes)
}
ip = ip + 1
result.append(d)
return result
security.declareProtected(change_permissions, 'manage_role')
def manage_role(self, role_to_manage, permissions=[]):
"""Change the permissions given to the given role.
"""
for p in self.ac_inherited_permissions(1):
name, value = p[:2]
p=Permission(name, value, self)
p.setRole(role_to_manage, name in permissions)
security.declareProtected(change_permissions, 'manage_acquiredPermissions')
def manage_acquiredPermissions(self, permissions=[]):
"""Change the permissions that acquire.
"""
for p in self.ac_inherited_permissions(1):
name, value = p[:2]
p = Permission(name, value, self)
roles = p.getRoles()
if roles is None:
continue
if name in permissions:
p.setRoles(list(roles))
else:
p.setRoles(tuple(roles))
def manage_getUserRolesAndPermissions(self, user_id):
""" Used for permission/role reporting for a given user_id.
Returns a dict mapping
'user_defined_in' -> path where the user account is defined
'roles' -> global roles,
'roles_in_context' -> roles in context of the current object,
'allowed_permissions' -> permissions allowed for the user,
'disallowed_permissions' -> all other permissions
"""
d = {}
current = self
while 1:
try:
uf = current.acl_users
except AttributeError:
raise ValueError('User %s could not be found' % user_id)
userObj = uf.getUser(user_id)
if userObj:
break
else:
current = current.__parent__
newSecurityManager(None, userObj) # necessary?
userObj = userObj.__of__(uf)
d = {'user_defined_in': '/' + uf.absolute_url(1)}
# roles
roles = list(userObj.getRoles())
roles.sort()
d['roles'] = roles
# roles in context
roles = list(userObj.getRolesInContext(self))
roles.sort()
d['roles_in_context'] = roles
# permissions
allowed = []
disallowed = []
permMap = self.manage_getPermissionMapping()
for item in permMap:
p = item['permission_name']
if userObj.has_permission(p, self):
allowed.append(p)
else:
disallowed.append(p)
d['allowed_permissions'] = allowed
d['disallowed_permissions'] = disallowed
return d
security.declareProtected(change_permissions, 'manage_permission')
def manage_permission(self, permission_to_manage, roles=[], acquire=0):
"""Change the settings for the given permission.
If optional arg acquire is true, then the roles for the permission
are acquired, in addition to the ones specified, otherwise the
permissions are restricted to only the designated roles.
"""
for p in self.ac_inherited_permissions(1):
name, value = p[:2]
if name == permission_to_manage:
p = Permission(name, value, self)
if acquire:
roles=list(roles)
else:
roles=tuple(roles)
p.setRoles(roles)
return
raise ValueError(
"The permission <em>%s</em> is invalid." %
escape(permission_to_manage))
security.declareProtected(change_permissions, 'permissionsOfRole')
def permissionsOfRole(self, role):
"""Returns a role to permission mapping.
"""
r = []
for p in self.ac_inherited_permissions(1):
name, value = p[:2]
p = Permission(name, value, self)
roles = p.getRoles()
r.append({'name': name,
'selected': role in roles and 'SELECTED' or '',
})
return r
security.declareProtected(change_permissions, 'rolesOfPermission')
def rolesOfPermission(self, permission):
"""Returns a permission to role mapping.
"""
valid_roles = self.valid_roles()
for p in self.ac_inherited_permissions(1):
name, value = p[:2]
if name==permission:
p = Permission(name, value, self)
roles = p.getRoles()
return map(
lambda role, roles=roles:
{'name': role,
'selected': role in roles and 'SELECTED' or '',
},
valid_roles)
raise ValueError(
"The permission <em>%s</em> is invalid." % escape(permission))
security.declareProtected(change_permissions, 'acquiredRolesAreUsedBy')
def acquiredRolesAreUsedBy(self, permission):
"""
"""
for p in self.ac_inherited_permissions(1):
name, value = p[:2]
if name==permission:
p=Permission(name, value, self)
roles = p.getRoles()
return isinstance(roles, list) and 'CHECKED' or ''
raise ValueError(
"The permission <em>%s</em> is invalid." % escape(permission))
# Local roles support
# -------------------
#
# Local roles allow a user to be given extra roles in the context
# of a particular object (and its children). When a user is given
# extra roles in a particular object, an entry for that user is made
# in the __ac_local_roles__ dict containing the extra roles.
def has_local_roles(self):
dict=self.__ac_local_roles__ or {}
return len(dict)
def get_local_roles(self):
dict=self.__ac_local_roles__ or {}
keys=dict.keys()
keys.sort()
info=[]
for key in keys:
value=tuple(dict[key])
info.append((key, value))
return tuple(info)
def users_with_local_role(self, role):
got = {}
for user, roles in self.get_local_roles():
if role in roles:
got[user] = 1
return got.keys()
def get_valid_userids(self):
item=self
dict={}
_notfound = []
while 1:
aclu = getattr(aq_base(item), '__allow_groups__', _notfound)
if aclu is not _notfound:
mlu = getattr(aclu, 'maxlistusers', _notfound)
if not isinstance(mlu, int):
mlu = DEFAULTMAXLISTUSERS
if mlu < 0:
raise OverflowError
un = getattr(aclu, 'user_names', _notfound)
if un is not _notfound:
un = aclu.__of__(item).user_names # rewrap
unl = un()
# maxlistusers of 0 is list all
if len(unl) > mlu and mlu != 0:
raise OverflowError
for name in unl:
dict[name]=1
item = getattr(item, '__parent__', _notfound)
if item is _notfound:
break
keys=dict.keys()
keys.sort()
return tuple(keys)
def get_local_roles_for_userid(self, userid):
dict=self.__ac_local_roles__ or {}
return tuple(dict.get(userid, []))
security.declareProtected(change_permissions, 'manage_addLocalRoles')
def manage_addLocalRoles(self, userid, roles):
"""Set local roles for a user."""
if not roles:
raise ValueError('One or more roles must be given!')
dict = self.__ac_local_roles__
if dict is None:
self.__ac_local_roles__ = dict = {}
local_roles = list(dict.get(userid, []))
for r in roles:
if r not in local_roles:
local_roles.append(r)
dict[userid] = local_roles
self._p_changed=True
security.declareProtected(change_permissions, 'manage_setLocalRoles')
def manage_setLocalRoles(self, userid, roles):
"""Set local roles for a user."""
if not roles:
raise ValueError('One or more roles must be given!')
dict = self.__ac_local_roles__
if dict is None:
self.__ac_local_roles__ = dict = {}
dict[userid]=roles
self._p_changed = True
security.declareProtected(change_permissions, 'manage_delLocalRoles')
def manage_delLocalRoles(self, userids):
"""Remove all local roles for a user."""
dict = self.__ac_local_roles__
if dict is None:
self.__ac_local_roles__ = dict = {}
for userid in userids:
if userid in dict:
del dict[userid]
self._p_changed=True
#------------------------------------------------------------
security.declarePrivate('access_debug_info')
def access_debug_info(self):
"""Return debug info.
"""
clas=class_attrs(self)
inst=instance_attrs(self)
data=[]
_add=data.append
for key, value in inst.items():
if key.find('__roles__') >= 0:
_add({'name': key, 'value': value, 'class': 0})
if hasattr(value, '__roles__'):
_add({'name': '%s.__roles__' % key, 'value': value.__roles__,
'class': 0})
for key, value in clas.items():
if key.find('__roles__') >= 0:
_add({'name': key, 'value': value, 'class': 1})
if hasattr(value, '__roles__'):
_add({'name': '%s.__roles__' % key, 'value': value.__roles__,
'class': 1})
return data
def valid_roles(self):
"""Return list of valid roles.
"""
obj=self
dict={}
dup =dict.has_key
x=0
while x < 100:
if hasattr(obj, '__ac_roles__'):
roles=obj.__ac_roles__
for role in roles:
if not dup(role):
dict[role]=1
if getattr(obj, '__parent__', None) is None:
break
obj=obj.__parent__
x=x+1
roles=dict.keys()
roles.sort()
return tuple(roles)
def validate_roles(self, roles):
"""Return true if all given roles are valid.
"""
valid=self.valid_roles()
for role in roles:
if role not in valid:
return 0
return 1
security.declareProtected(change_permissions, 'userdefined_roles')
def userdefined_roles(self):
"""Return list of user-defined roles.
"""
roles = list(self.__ac_roles__)
for role in classattr(self.__class__, '__ac_roles__'):
try:
roles.remove(role)
except:
pass
return tuple(roles)
def possible_permissions(self):
d = {}
permissions = getPermissions()
for p in permissions:
d[p[0]] = 1
for p in self.ac_inherited_permissions(1):
d[p[0]] = 1
d = d.keys()
d.sort()
return d
InitializeClass(RoleManager)
def reqattr(request, attr):
try:
return request[attr]
except:
return None
def classattr(cls, attr):
if hasattr(cls, attr):
return getattr(cls, attr)
try:
bases = cls.__bases__
except:
bases = ()
for base in bases:
if classattr(base, attr):
return attr
return None
def instance_dict(inst):
try:
return inst.__dict__
except:
return {}
def class_dict(_class):
try:
return _class.__dict__
except:
return {}
def instance_attrs(inst):
return instance_dict(inst)
def class_attrs(inst, _class=None, data=None):
if _class is None:
_class=inst.__class__
data={}
clas_dict=class_dict(_class)
inst_dict=instance_dict(inst)
inst_attr=inst_dict.has_key
for key, value in clas_dict.items():
if not inst_attr(key):
data[key]=value
for base in _class.__bases__:
data=class_attrs(inst, base, data)
return data
def gather_permissions(klass, result, seen):
for base in klass.__bases__:
if '__ac_permissions__' in base.__dict__:
for p in base.__ac_permissions__:
name=p[0]
if name in seen:
continue
result.append((name, ()))
seen[name] = None
gather_permissions(base, result, seen)
return result
##############################################################################
#
# Copyright (c) 2004-2009 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Security handling
"""
from zope.component import getUtility
from zope.component import queryUtility
from zope.interface import classProvides
from zope.interface import implements
from zope.security.checker import CheckerPublic
from zope.security.interfaces import IInteraction
from zope.security.interfaces import ISecurityPolicy
from zope.security.interfaces import IPermission
from zope.security.management import thread_local
from zope.security.simplepolicies import ParanoidSecurityPolicy
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.Permission import addPermission
CheckerPublicId = 'zope.Public'
CheckerPrivateId = 'zope2.Private'
def getSecurityInfo(klass):
sec = {}
info = vars(klass)
if info.has_key('__ac_permissions__'):
sec['__ac_permissions__'] = info['__ac_permissions__']
for k, v in info.items():
if k.endswith('__roles__'):
sec[k] = v
return sec
def clearSecurityInfo(klass):
info = vars(klass)
if info.has_key('__ac_permissions__'):
delattr(klass, '__ac_permissions__')
for k, v in info.items():
if k.endswith('__roles__'):
delattr(klass, k)
def checkPermission(permission, object, interaction=None):
"""Return whether security policy allows permission on object.
Arguments:
permission -- A permission name
object -- The object being accessed according to the permission
interaction -- This zope.security concept has no equivalent in Zope 2,
and is ignored.
checkPermission is guaranteed to return True if permission is
CheckerPublic or None.
"""
if (permission in ('zope.Public', 'zope2.Public') or
permission is None or permission is CheckerPublic):
return True
if isinstance(permission, basestring):
permission = queryUtility(IPermission, unicode(permission))
if permission is None:
return False
if getSecurityManager().checkPermission(permission.title, object):
return True
return False
class SecurityPolicy(ParanoidSecurityPolicy):
"""Security policy that bridges between zope.security security mechanisms
and Zope 2's security policy.
Don't let the name of the base class fool you... This really just
delegates to Zope 2's security manager."""
classProvides(ISecurityPolicy)
implements(IInteraction)
def checkPermission(self, permission, object):
return checkPermission(permission, object)
def newInteraction():
"""Con zope.security to use Zope 2's checkPermission.
zope.security when it does a checkPermission will turn around and
ask the thread local interaction for the checkPermission method.
By making the interaction *be* Zope 2's security manager, we can
con zope.security into using Zope 2's checker...
"""
if getattr(thread_local, 'interaction', None) is None:
thread_local.interaction = SecurityPolicy()
def _getSecurity(klass):
# a Zope 2 class can contain some attribute that is an instance
# of ClassSecurityInfo. Zope 2 scans through things looking for
# an attribute that has the name __security_info__ first
info = vars(klass)
for k, v in info.items():
if hasattr(v, '__security_info__'):
return v
# we stuff the name ourselves as __security__, not security, as this
# could theoretically lead to name clashes, and doesn't matter for
# zope 2 anyway.
security = ClassSecurityInfo()
setattr(klass, '__security__', security)
return security
def protectName(klass, name, permission_id):
"""Protect the attribute 'name' on 'klass' using the given
permission"""
security = _getSecurity(klass)
# Zope 2 uses string, not unicode yet
name = str(name)
if permission_id == CheckerPublicId or permission_id is CheckerPublic:
# Sometimes, we already get a processed permission id, which
# can mean that 'zope.Public' has been interchanged for the
# CheckerPublic object
security.declarePublic(name)
elif permission_id == CheckerPrivateId:
security.declarePrivate(name)
else:
permission = getUtility(IPermission, name=permission_id)
# Zope 2 uses string, not unicode yet
perm = str(permission.title)
security.declareProtected(perm, name)
def protectClass(klass, permission_id):
"""Protect the whole class with the given permission"""
security = _getSecurity(klass)
if permission_id == CheckerPublicId or permission_id is CheckerPublic:
# Sometimes, we already get a processed permission id, which
# can mean that 'zope.Public' has been interchanged for the
# CheckerPublic object
security.declareObjectPublic()
elif permission_id == CheckerPrivateId:
security.declareObjectPrivate()
else:
permission = getUtility(IPermission, name=permission_id)
# Zope 2 uses string, not unicode yet
perm = str(permission.title)
security.declareObjectProtected(perm)
def create_permission_from_permission_directive(permission, event):
"""When a new IPermission utility is registered (via the <permission />
directive), create the equivalent Zope2 style permission.
"""
# Zope 2 uses string, not unicode yet
zope2_permission = str(permission.title)
addPermission(zope2_permission)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" TaintedString implementation.
TaintedStrings hold potentially dangerous untrusted data; anything that could
possibly hold HTML is considered dangerous. DTML code will use the quoted
value of this string, and raised exceptions in Zope will use the repr()
conversion.
"""
from cgi import escape
class TaintedString:
def __init__(self, value):
self._value = value
def __str__(self):
return self._value
def __repr__(self):
return repr(self.quoted())
def __cmp__(self, o):
return cmp(self._value, o)
def __hash__(self):
return hash(self._value)
def __len__(self):
return len(self._value)
def __getitem__(self, index):
v = self._value[index]
if '<' in v:
v = self.__class__(v)
return v
def __getslice__(self, i, j):
i = max(i, 0)
j = max(j, 0)
v = self._value[i:j]
if '<' in v:
v = self.__class__(v)
return v
def __add__(self, o):
return self.__class__(self._value + o)
def __radd__(self, o):
return self.__class__(o + self._value)
def __mul__(self, o):
return self.__class__(self._value * o)
def __rmul__(self, o):
return self.__class__(o * self._value)
def __mod__(self, o):
return self.__class__(self._value % o)
def __int__(self):
return int(self._value)
def __float__(self):
return float(self._value)
def __long__(self):
return long(self._value)
def __getstate__(self):
# If an object tries to store a TaintedString, it obviously wasn't
# aware that it was playing with untrusted data. Complain acordingly.
raise SystemError("A TaintedString cannot be pickled. Code that "
"caused this TaintedString to be stored should be more careful "
"with untrusted data from the REQUEST.")
def __getattr__(self, a):
# for string methods support other than those defined below
return getattr(self._value, a)
# Python 2.2 only.
def decode(self, *args):
return self.__class__(self._value.decode(*args))
def encode(self, *args):
return self.__class__(self._value.encode(*args))
def expandtabs(self, *args):
return self.__class__(self._value.expandtabs(*args))
def replace(self, *args):
v = self._value.replace(*args)
if '<' in v:
v = self.__class__(v)
return v
def split(self, *args):
r = self._value.split(*args)
return map(lambda v, c=self.__class__: '<' in v and c(v) or v, r)
def splitlines(self, *args):
r = self._value.splitlines(*args)
return map(lambda v, c=self.__class__: '<' in v and c(v) or v, r)
def translate(self, *args):
v = self._value.translate(*args)
if '<' in v:
v = self.__class__(v)
return v
def quoted(self):
return escape(self._value, 1)
# As called by cDocumentTemplate
__untaint__ = quoted
def createSimpleWrapper(func):
return lambda s, f=func: s.__class__(getattr(s._value, f)())
def createOneArgWrapper(func):
return lambda s, a, f=func: s.__class__(getattr(s._value, f)(a))
def createOneOptArgWrapper(func):
return lambda s, a=None, f=func: s.__class__(getattr(s._value, f)(a))
simpleWrappedMethods = ["capitalize", "lower", "swapcase", "title", "upper"]
oneArgWrappedMethods = ["center", "join", "ljust", "rjust"]
oneOptArgWrappedMethods = ["lstrip", "rstrip", "strip"]
for f in simpleWrappedMethods:
setattr(TaintedString, f, createSimpleWrapper(f))
for f in oneArgWrappedMethods:
setattr(TaintedString, f, createOneArgWrapper(f))
for f in oneOptArgWrappedMethods:
setattr(TaintedString, f, createOneOptArgWrapper(f))
# The code in this file is executed after being compiled as restricted code,
# and given a globals() dict with our idea of safe builtins, and the
# Zope production implementations of the special restricted-Python functions
# (like _getitem_ and _getiter_, etc).
#
# This isn't trying to provoke security problems, it's just trying to verify
# that Python code continues to work as intended after all the transformations,
# and with all the special wrappers we supply.
def f1():
next = iter(xrange(3)).next
assert next() == 0
assert next() == 1
assert next() == 2
try:
next()
except StopIteration:
pass
else:
assert 0, "expected StopIteration"
f1()
def f2():
assert map(lambda x: x+1, range(3)) == range(1, 4)
f2()
def f3():
assert filter(None, range(10)) == range(1, 10)
f3()
def f4():
assert [i+1 for i in range(3)] == range(*(1, 4))
f4()
def f5():
x = range(5)
def add(a, b):
return a+b
assert sum(x) == reduce(add, x, 0)
f5()
def f6():
class C:
def display(self):
return str(self.value)
c1 = C()
c2 = C()
c1.value = 12
assert getattr(c1, 'value') == 12
assert c1.display() == '12'
assert not hasattr(c2, 'value')
setattr(c2, 'value', 34)
assert c2.value == 34
assert hasattr(c2, 'value')
del c2.value
assert not hasattr(c2, 'value')
# OK, if we can't set new attributes, at least verify that we can't.
#try:
# c1.value = 12
#except TypeError:
# pass
#else:
# assert 0, "expected direct attribute creation to fail"
#try:
# setattr(c1, 'value', 12)
#except TypeError:
# pass
#else:
# assert 0, "expected indirect attribute creation to fail"
assert getattr(C, "display", None) == getattr(C, "display")
delattr(C, "display")
#try:
# setattr(C, "display", lambda self: "replaced")
#except TypeError:
# pass
#else:
# assert 0, "expected setattr() attribute replacement to fail"
#try:
# delattr(C, "display")
#except TypeError:
# pass
#else:
# assert 0, "expected delattr() attribute deletion to fail"
f6()
def f7():
d = apply(dict, [((1, 2), (3, 4))]) # {1: 2, 3: 4}
expected = {'k': [1, 3],
'v': [2, 4],
'i': [(1, 2), (3, 4)]}
for meth, kind in [('iterkeys', 'k'),
('iteritems', 'i'),
('itervalues', 'v'),
('keys', 'k'),
('items', 'i'),
('values', 'v')]:
access = getattr(d, meth)
result = list(access())
result.sort()
assert result == expected[kind], (meth, kind, result, expected[kind])
f7()
def f8():
import math
ceil = getattr(math, 'ceil')
smallest = 1e100
smallest_index = None
largest = -1e100
largest_index = None
all = []
for i, x in enumerate((2.2, 1.1, 3.3, 5.5, 4.4)):
all.append(x)
effective = ceil(x)
if effective < smallest:
assert min(effective, smallest) == effective
smallest = effective
smallest_index = i
if effective > largest:
assert max(effective, largest) == effective
largest = effective
largest_index = i
assert smallest == 2
assert smallest_index == 1
assert largest == 6
assert largest_index == 3
assert min([ceil(x) for x in all]) == smallest
assert max(map(ceil, all)) == largest
f8()
# After all the above, these wrappers were still untouched:
# ['DateTime', '_print_', 'reorder', 'same_type', 'test']
# So do something to touch them.
def f9():
d = DateTime()
print d # this one provoked _print_
# Funky. This probably isn't an intended use of reorder, but I'm
# not sure why it exists.
assert reorder('edcbaxyz', 'abcdef', 'c') == zip('abde', 'abde')
assert test(0, 'a', 0, 'b', 1, 'c', 0, 'd') == 'c'
assert test(0, 'a', 0, 'b', 0, 'c', 0, 'd', 'e') == 'e'
# Unclear that the next one is *intended* to return None (it falls off
# the end of test's implementation without explicitly returning anything).
assert test(0, 'a', 0, 'b', 0, 'c', 0, 'd') == None
assert same_type(3, 2, 1), 'expected same type'
assert not same_type(3, 2, 'a'), 'expected not same type'
f9()
def f10():
assert iter(enumerate(iter(iter(range(9))))).next() == (0, 0)
f10()
def f11():
x = 1
x += 1
f11()
def f12():
try:
all
except NameError:
pass # Python < 2.5
else:
assert all([True, True, True]) == True
assert all([True, False, True]) == False
f12()
def f13():
try:
any
except NameError:
pass # Python < 2.5
else:
assert any([True, True, True]) == True
assert any([True, False, True]) == True
assert any([False, False, False]) == False
f13()
# test module, partially private
def priv():
pass
def pub():
pass
# test module, all private
def priv():
pass
# test module, public
from Acquisition import aq_base # Foil the old ZopeSecurityPolicy
def pub():
pass
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
""" Unit tests for ClassSecurityInfo.
"""
import unittest
class ClassSecurityInfoTests(unittest.TestCase):
def _getTargetClass(self):
from AccessControl.SecurityInfo import ClassSecurityInfo
return ClassSecurityInfo
def test_SetPermissionDefault(self):
# Test setting default roles for permissions.
from AccessControl.class_init import InitializeClass
from ExtensionClass import Base
ClassSecurityInfo = self._getTargetClass()
# Setup a test class with default role -> permission decls.
class Test(Base):
"""Test class
"""
__ac_roles__ = ('Role A', 'Role B', 'Role C')
meta_type = "Test"
security = ClassSecurityInfo()
security.setPermissionDefault('Make food', ('Chef',))
security.setPermissionDefault(
'Test permission',
('Manager', 'Role A', 'Role B', 'Role C')
)
security.declareProtected('Test permission', 'foo')
def foo(self, REQUEST=None):
""" """
pass
# Do class initialization.
InitializeClass(Test)
# Now check the resulting class to see if the mapping was made
# correctly. Note that this uses carnal knowledge of the internal
# structures used to store this information!
object = Test()
imPermissionRole = [r for r in object.foo__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)
# Make sure that a permission defined without accompanying method
# is still reflected in __ac_permissions__
self.assertEquals([t for t in Test.__ac_permissions__ if not t[1]],
[('Make food', (), ('Chef',))])
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ClassSecurityInfoTests))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test of the implementation selection support."""
import unittest
from AccessControl.Implementation import getImplementationName
from AccessControl.Implementation import setImplementation
class AccessControlImplementationTest(unittest.TestCase):
have_cAccessControl = None
def setUp(self):
if self.have_cAccessControl is None:
try:
import AccessControl.cAccessControl
except ImportError:
v = False
else:
v = True
self.__class__.have_cAccessControl = v
self.original = getImplementationName()
def tearDown(self):
setImplementation(self.original)
## Note - this test is disabled because the intent for 2.7 was *not*
## to support the ability to arbitrarily switch the security policy
## at any time (which would currently be nearly impossible to do in
## a way that would be sane for 3rd party apps that may already have
## imported parts of the security machinery), but just to make sure
## that the config file could be used to initially set the implementation
## to be used. The policy setting is 'initialize once' - setImplementation
## should not be called either by user code or unit tests, as the
## effects are officially undefined.
## def test_setImplemenationC(self):
## setImplementation("C")
## name = getImplementationName()
## if self.have_cAccessControl:
## self.assertEqual(name, "C")
## else:
## self.assertEqual(name, "PYTHON")
## def test_setImplemenationPython(self):
## setImplementation("Python")
## self.assertEqual(getImplementationName(), "PYTHON")
def test_suite():
return unittest.makeSuite(AccessControlImplementationTest)
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")
##############################################################################
#
# Copyright (c) 2008 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import unittest
class ModuleSecurityTests(unittest.TestCase):
def setUp(self):
from AccessControl import ModuleSecurityInfo as MSI
MSI('AccessControl.tests.mixed_module').declarePublic('pub')
MSI('AccessControl.tests.public_module').declarePublic('pub')
MSI('AccessControl.tests.public_module.submodule').declarePublic('pub')
def tearDown(self):
import sys
for module in ('AccessControl.tests.public_module',
'AccessControl.tests.public_module.submodule',
'AccessControl.tests.mixed_module',
'AccessControl.tests.mixed_module.submodule',
'AccessControl.tests.private_module',
'AccessControl.tests.private_module.submodule',
):
if module in sys.modules:
del sys.modules[module]
def assertUnauth(self, module, fromlist):
from zExceptions import Unauthorized
from AccessControl.ZopeGuards import guarded_import
self.assertRaises(Unauthorized,
guarded_import, module, fromlist=fromlist)
def assertAuth(self, module, fromlist):
from AccessControl.ZopeGuards import guarded_import
guarded_import(module, fromlist=fromlist)
def testPrivateModule(self):
self.assertUnauth('AccessControl.tests.private_module', ())
self.assertUnauth('AccessControl.tests.private_module', ('priv',))
self.assertUnauth('AccessControl.tests.private_module.submodule', ())
self.assertUnauth('AccessControl.tests.private_module.submodule',
('priv',))
def testMixedModule(self):
self.assertAuth('AccessControl.tests.mixed_module', ())
self.assertAuth('AccessControl.tests.mixed_module', ('pub',))
self.assertUnauth('AccessControl.tests.mixed_module', ('priv',))
self.assertUnauth('AccessControl.tests.mixed_module.submodule', ())
def testPublicModule(self):
self.assertAuth('AccessControl.tests.public_module', ())
self.assertAuth('AccessControl.tests.public_module', ('pub',))
self.assertAuth('AccessControl.tests.public_module.submodule', ())
self.assertAuth('AccessControl.tests.public_module.submodule',
('pub',))
def test_public_module_asterisk_not_allowed(self):
self.assertUnauth('AccessControl.tests.public_module', ('*',))
def test_failed_import_keeps_MSI(self):
# LP #281156
from AccessControl import ModuleSecurityInfo as MSI
from AccessControl.SecurityInfo import _moduleSecurity as MS
from AccessControl.ZopeGuards import guarded_import
MSI('AccessControl.tests.nonesuch').declarePublic('pub')
self.failUnless('AccessControl.tests.nonesuch' in MS)
self.assertRaises(ImportError,
guarded_import, 'AccessControl.tests.nonesuch', ())
self.failUnless('AccessControl.tests.nonesuch' in MS)
def test_suite():
return unittest.makeSuite(ModuleSecurityTests)
"""Unit tests for AccessControl.Owned
"""
import unittest
from persistent import Persistent
from Acquisition import Implicit, aq_inner
from AccessControl.owner import Owned
class FauxUser(Implicit):
def __init__(self, id):
self._id = id
def getId(self):
return self._id
class FauxUserFolder(Implicit):
def getUserById(self, id, default):
return FauxUser(id)
class FauxRoot(Implicit):
def getPhysicalRoot(self):
return aq_inner(self)
def unrestrictedTraverse(self, path, default=None):
if type(path) is type(''):
path = path.split('/')
if not path[0]:
path = path[1:]
obj = self
try:
while path:
next, path = path[0], path[1:]
obj = getattr(obj, next)
except AttributeError:
obj = default
return obj
class Folder(Implicit, Persistent, Owned):
def __init__(self, id):
self.id = id
self.names = set()
def _setObject(self, name, value):
setattr(self, name, value)
self.names.add(name)
def objectValues(self):
result = []
for name in self.names:
result.append(getattr(self, name))
return result
class OwnedTests(unittest.TestCase):
def _getTargetClass(self):
return Owned
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
def _makeDummy(self, *args, **kw):
class Dummy(Implicit, Owned):
pass
return Dummy(*args, **kw)
def test_interfaces(self):
from AccessControl.interfaces import IOwned
from zope.interface.verify import verifyClass
verifyClass(IOwned, Owned)
def test_getOwnerTuple_unowned(self):
owned = self._makeOne()
owner_tuple = owned.getOwnerTuple()
self.assertEqual(owner_tuple, None)
def test_getOwnerTuple_simple(self):
owned = self._makeOne()
owned._owner = ('/foobar', 'baz')
owner_tuple = owned.getOwnerTuple()
self.assertEqual(len(owner_tuple), 2)
self.assertEqual(owner_tuple[0], '/foobar')
self.assertEqual(owner_tuple[1], 'baz')
def test_getOwnerTuple_acquired(self):
root = FauxRoot()
root._owner = ('/foobar', 'baz')
owned = self._makeDummy().__of__(root)
owner_tuple = owned.getOwnerTuple()
self.assertEqual(len(owner_tuple), 2)
self.assertEqual(owner_tuple[0], '/foobar')
self.assertEqual(owner_tuple[1], 'baz')
def test_getOwnerTuple_acquired_no_tricks(self):
# Ensure that we acquire ownership only through containment.
root = FauxRoot()
root._owner = ('/foobar', 'baz')
owned = self._makeDummy().__of__(root)
owner_tuple = owned.getOwnerTuple()
tricky = self._makeDummy()
tricky._owner = ('/bambam', 'qux')
tricky = tricky.__of__(root)
not_tricked = owned.__of__(tricky)
owner_tuple = not_tricked.getOwnerTuple()
self.assertEqual(len(owner_tuple), 2)
self.assertEqual(owner_tuple[0], '/foobar')
self.assertEqual(owner_tuple[1], 'baz')
def test_getWrappedOwner_unowned(self):
owned = self._makeOne()
wrapped_owner = owned.getWrappedOwner()
self.assertEqual(wrapped_owner, None)
def test_getWrappedOwner_unownable(self):
from AccessControl.owner import UnownableOwner
owned = self._makeOne()
owned._owner = UnownableOwner
wrapped_owner = owned.getWrappedOwner()
self.assertEqual(wrapped_owner, None)
def test_getWrappedOwner_simple(self):
root = FauxRoot()
root.acl_users = FauxUserFolder()
owned = self._makeDummy().__of__(root)
owned._owner = ('/acl_users', 'user')
wrapped_owner = owned.getWrappedOwner()
self.assertEqual(wrapped_owner.getId(), 'user')
def test_getWrappedOwner_acquired(self):
root = FauxRoot()
root._owner = ('/acl_users', 'user')
root.acl_users = FauxUserFolder()
owned = self._makeDummy().__of__(root)
wrapped_owner = owned.getWrappedOwner()
self.assertEqual(wrapped_owner.getId(), 'user')
def test_getWrappedOwner_acquired_no_tricks(self):
root = FauxRoot()
root._owner = ('/acl_users', 'user')
root.acl_users = FauxUserFolder()
owned = self._makeDummy().__of__(root)
tricky = self._makeDummy()
tricky._owner = ('/acl_users', 'black_hat')
tricky = tricky.__of__(root)
not_tricked = owned.__of__(tricky)
wrapped_owner = not_tricked.getWrappedOwner()
self.assertEqual(wrapped_owner.getId(), 'user')
class OwnershipChangeTests(unittest.TestCase):
def setUp(self):
from AccessControl.owner import UnownableOwner
from AccessControl.userfolder import UserFolder
super(OwnershipChangeTests, self).setUp()
self.root = FauxRoot()
self.root.acl_users = UserFolder()
self.uf = self.root.acl_users
self.uf._doAddUser('user1', 'xxx', ['role1'], [])
self.uf._doAddUser('user2', 'xxx', ['role1'], [])
self.root.unownable = Folder('unownable')
self.root.unownable._owner = UnownableOwner
self.root.parent = Folder('parent')
parent = self.root.parent
parent._owner = (['acl_users'], 'user1')
parent._setObject('child', Folder('child'))
parent.child._owner = (['acl_users'], 'user1')
parent.child._setObject('grandchild', Folder('grandchild'))
parent.child.grandchild._owner = (['acl_users'], 'user1')
def test_changeOwnership_bad_owner(self):
from AccessControl.User import nobody
previous = self.root.parent._owner
self.root.parent.changeOwnership(nobody)
self.assertEquals(self.root.parent._owner, previous)
def test_changeOwnership_same_owner(self):
previous = self.root.parent._owner
sameuser = self.uf.getUser('user1').__of__(self.uf)
self.root.parent.changeOwnership(sameuser)
self.assertEquals(self.root.parent._owner, previous)
def test_changeOwnership_unownable_owner(self):
previous = self.root.unownable._owner
newuser = self.uf.getUser('user1').__of__(self.uf)
self.root.unownable.changeOwnership(newuser)
self.assertEquals(self.root.unownable._owner, previous)
def test_changeOwnership_nonrecursive(self):
previous_parent_owner = self.root.parent._owner
previous_child_owner = self.root.parent.child._owner
previous_grandchild_owner = self.root.parent.child.grandchild._owner
newuser = self.uf.getUser('user2').__of__(self.uf)
self.root.parent.changeOwnership(newuser)
self.assertNotEquals(self.root.parent._owner, previous_parent_owner)
self.assertEquals(self.root.parent._owner, (['acl_users'], 'user2'))
self.assertEquals(self.root.parent.child._owner, previous_child_owner)
self.assertEquals( self.root.parent.child.grandchild._owner
, previous_grandchild_owner
)
def test_changeOwnership_recursive(self):
previous_parent_owner = self.root.parent._owner
previous_child_owner = self.root.parent.child._owner
previous_grandchild_owner = self.root.parent.child.grandchild._owner
newuser = self.uf.getUser('user2').__of__(self.uf)
self.root.parent.changeOwnership(newuser, recursive=True)
self.assertNotEquals(self.root.parent._owner, previous_parent_owner)
self.assertEquals(self.root.parent._owner, (['acl_users'], 'user2'))
self.assertNotEquals(self.root.parent.child._owner, previous_child_owner)
self.assertEquals( self.root.parent.child._owner
, (['acl_users'], 'user2')
)
self.assertNotEquals( self.root.parent.child.grandchild._owner
, previous_grandchild_owner
)
self.assertEquals( self.root.parent.child.grandchild._owner
, (['acl_users'], 'user2')
)
def test_changeOwnership_recursive_objectValues_acquisition(self):
# See https://bugs.launchpad.net/bugs/143403
from AccessControl.owner import Owned
class FauxContent(Implicit, Owned):
pass
previous_parent_owner = self.root.parent._owner
previous_child_owner = self.root.parent.child._owner
previous_grandchild_owner = self.root.parent.child.grandchild._owner
newuser = self.uf.getUser('user2').__of__(self.uf)
self.root.parent.bad = FauxContent()
self.root.parent.bad.changeOwnership(newuser, recursive=True)
self.assertEquals(self.root.parent._owner, previous_parent_owner)
self.assertEquals(self.root.parent.child._owner, previous_child_owner)
self.assertEquals( self.root.parent.child.grandchild._owner
, previous_grandchild_owner
)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(OwnedTests),
unittest.makeSuite(OwnershipChangeTests),
))
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Test of AuthEncoding
"""
import unittest
from AccessControl import AuthEncoding
class PasswordDigestTests (unittest.TestCase):
def testGoodPassword(self):
pw = 'good_password'
assert len(AuthEncoding.listSchemes()) > 0 # At least one must exist!
for id in AuthEncoding.listSchemes():
enc = AuthEncoding.pw_encrypt(pw, id)
assert enc != pw
assert AuthEncoding.pw_validate(enc, pw)
assert AuthEncoding.is_encrypted(enc)
assert not AuthEncoding.is_encrypted(pw)
def testBadPasword(self):
pw = 'OK_pa55w0rd \n'
for id in AuthEncoding.listSchemes():
enc = AuthEncoding.pw_encrypt(pw, id)
assert enc != pw
assert not AuthEncoding.pw_validate(enc, 'xxx')
assert not AuthEncoding.pw_validate(enc, enc)
if id != 'CRYPT':
# crypt truncates passwords and would fail this test.
assert not AuthEncoding.pw_validate(enc, pw[:-1])
assert not AuthEncoding.pw_validate(enc, pw[1:])
assert AuthEncoding.pw_validate(enc, pw)
def testShortPassword(self):
pw = '1'
for id in AuthEncoding.listSchemes():
enc = AuthEncoding.pw_encrypt(pw, id)
assert enc != pw
assert AuthEncoding.pw_validate(enc, pw)
assert not AuthEncoding.pw_validate(enc, enc)
assert not AuthEncoding.pw_validate(enc, 'xxx')
def testLongPassword(self):
pw = 'Pw' * 2000
for id in AuthEncoding.listSchemes():
enc = AuthEncoding.pw_encrypt(pw, id)
assert enc != pw
assert AuthEncoding.pw_validate(enc, pw)
assert not AuthEncoding.pw_validate(enc, enc)
assert not AuthEncoding.pw_validate(enc, 'xxx')
if id != 'CRYPT':
# crypt truncates passwords and would fail these tests.
assert not AuthEncoding.pw_validate(enc, pw[:-2])
assert not AuthEncoding.pw_validate(enc, pw[2:])
def testBlankPassword(self):
pw = ''
for id in AuthEncoding.listSchemes():
enc = AuthEncoding.pw_encrypt(pw, id)
assert enc != pw
assert AuthEncoding.pw_validate(enc, pw)
assert not AuthEncoding.pw_validate(enc, enc)
assert not AuthEncoding.pw_validate(enc, 'xxx')
def testUnencryptedPassword(self):
# Sanity check
pw = 'my-password'
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()
import unittest
class TestRoleManager(unittest.TestCase):
def test_interfaces(self):
from AccessControl.interfaces import IPermissionMappingSupport
from AccessControl.PermissionMapping import RoleManager
from zope.interface.verify import verifyClass
verifyClass(IPermissionMappingSupport, RoleManager)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestRoleManager),
))
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Tests of PermissionRole
"""
import unittest
from AccessControl.PermissionRole import PermissionRole
from Acquisition import Implicit, Explicit, aq_base
ViewPermission = 'View'
EditThingsPermission = 'Edit Things!'
DeletePermission = 'Delete'
class AppRoot(Explicit):
_View_Permission = None
_Edit_Things__Permission = ('Manager', 'Owner')
# No default for delete permission.
class ImplicitContainer(Implicit):
pass
class ExplicitContainer(Explicit):
pass
class RestrictiveObject(Implicit):
_View_Permission = ('Manager',)
_Delete_Permission = () # Nobody
class PermissiveObject(Explicit):
_Edit_Things__Permission = ['Anonymous']
def assertPRoles(ob, permission, expect):
"""
Asserts that in the context of ob, the given permission maps to
the given roles.
"""
pr = PermissionRole(permission)
roles = pr.__of__(ob)
roles2 = aq_base(pr).__of__(ob)
assert roles == roles2 or tuple(roles) == tuple(roles2), (
'Different methods of checking roles computed unequal results')
same = 0
if roles:
# When verbose security is enabled, permission names are
# embedded in the computed roles. Remove the permission
# names.
roles = [r for r in roles if not r.endswith('_Permission')]
if roles is None or expect is None:
if (roles is None or tuple(roles) == ('Anonymous',)) and (
expect is None or tuple(expect) == ('Anonymous',)):
same = 1
else:
got = {}
for r in roles: got[r] = 1
expected = {}
for r in expect: expected[r] = 1
if got == expected: # Dict compare does the Right Thing.
same = 1
assert same, 'Expected roles: %s, got: %s' % (`expect`, `roles`)
class PermissionRoleTests (unittest.TestCase):
def testRestrictive(self, explicit=0):
app = AppRoot()
if explicit:
app.c = ExplicitContainer()
else:
app.c = ImplicitContainer()
app.c.o = RestrictiveObject()
o = app.c.o
assertPRoles(o, ViewPermission, ('Manager',))
assertPRoles(o, EditThingsPermission, ('Manager','Owner',))
assertPRoles(o, DeletePermission, ())
def testPermissive(self, explicit=0):
app = AppRoot()
if explicit:
app.c = ExplicitContainer()
else:
app.c = ImplicitContainer()
app.c.o = PermissiveObject()
o = app.c.o
assertPRoles(o, ViewPermission, ('Anonymous',))
assertPRoles(o, EditThingsPermission, ('Anonymous','Manager','Owner',))
assertPRoles(o, DeletePermission, ('Manager',))
def testExplicit(self):
self.testRestrictive(1)
self.testPermissive(1)
def testAppDefaults(self):
o = AppRoot()
assertPRoles(o, ViewPermission, ('Anonymous',))
assertPRoles(o, EditThingsPermission, ('Manager','Owner',))
assertPRoles(o, DeletePermission, ('Manager',))
def testPermissionRoleSupportsGetattr(self):
a = PermissionRole('a')
self.failUnless(getattr(a, '__roles__') == ('Manager',))
self.failUnless(getattr(a, '_d') == ('Manager',))
self.failUnless(getattr(a, '__name__') == 'a')
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
class TestRoleManager(unittest.TestCase):
def test_interfaces(self):
from AccessControl.interfaces import IRoleManager
from AccessControl.rolemanager import RoleManager
from zope.interface.verify import verifyClass
verifyClass(IRoleManager, RoleManager)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestRoleManager),
))
##############################################################################
#
# Copyright (c) 2005 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Tests for the SecurityManager implementations
"""
import unittest
_THREAD_ID = 123
class DummyContext:
def __init__(self):
self.user = object()
self.stack = []
class DummyPolicy:
CHECK_PERMISSION_ARGS = None
CHECK_PERMISSION_RESULT = object()
VALIDATE_ARGS = None
def checkPermission(self, *args):
self.CHECK_PERMISSION_ARGS = args
return self.CHECK_PERMISSION_RESULT
def validate(self, *args):
self.VALIDATE_ARGS = args
return True
class ExecutableObject:
def __init__(self, new_policy):
self._new_policy = new_policy
def _customSecurityPolicy(self):
return self._new_policy
class ISecurityManagerConformance:
def test_conforms_to_ISecurityManager(self):
from AccessControl.interfaces import ISecurityManager
from zope.interface.verify import verifyClass
verifyClass(ISecurityManager, self._getTargetClass())
class SecurityManagerTestBase(unittest.TestCase):
def _makeOne(self, thread_id, context):
return self._getTargetClass()(thread_id, context)
def test_getUser(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
self.failUnless(mgr.getUser() is context.user)
def test_calledByExecutable_no_stack(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
self.failIf(mgr.calledByExecutable())
def test_calledByExecutable_with_stack(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
executableObject = object()
mgr.addContext(executableObject)
self.failUnless(mgr.calledByExecutable())
def test_addContext_no_custom_policy(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
original_policy = mgr._policy
executableObject = object()
mgr.addContext(executableObject)
self.failUnless(mgr._policy is original_policy)
def test_addContext_with_custom_policy(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
new_policy = DummyPolicy()
executableObject = ExecutableObject(new_policy)
mgr.addContext(executableObject)
self.failUnless(mgr._policy is new_policy)
def test_addContext_with_custom_policy_then_none(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
original_policy = mgr._policy
new_policy = DummyPolicy()
executableObject = ExecutableObject(new_policy)
mgr.addContext(executableObject)
mgr.addContext(object())
self.failUnless(mgr._policy is original_policy)
def test_removeContext_pops_items_above_EO(self):
context = DummyContext()
ALPHA, BETA, GAMMA, DELTA = object(), object(), object(), object()
context.stack.append(ALPHA)
context.stack.append(BETA)
context.stack.append(GAMMA)
context.stack.append(DELTA)
mgr = self._makeOne(_THREAD_ID, context)
mgr.removeContext(GAMMA)
self.assertEqual(len(context.stack), 2)
self.failUnless(context.stack[0] is ALPHA)
self.failUnless(context.stack[1] is BETA)
def test_removeContext_last_EO_restores_default_policy(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
original_policy = mgr._policy
new_policy = mgr._policy = DummyPolicy()
top = object()
context.stack.append(top)
mgr.removeContext(top)
self.failUnless(mgr._policy is original_policy)
def test_removeContext_with_top_having_custom_policy(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
new_policy = DummyPolicy()
context.stack.append(ExecutableObject(new_policy))
top = object()
context.stack.append(top)
mgr.removeContext(top)
self.failUnless(mgr._policy is new_policy)
def test_removeContext_with_top_having_no_custom_policy(self):
context = DummyContext()
mgr = self._makeOne(_THREAD_ID, context)
original_policy = mgr._policy
new_policy = DummyPolicy()
executableObject = ExecutableObject(new_policy)
context.stack.append(executableObject)
top = object()
context.stack.append(top)
mgr.removeContext(executableObject)
self.failUnless(mgr._policy is original_policy)
def test_checkPermission_delegates_to_policy(self):
context = DummyContext()
PERMISSION = 'PERMISSION'
TARGET = object()
mgr = self._makeOne(_THREAD_ID, context)
new_policy = mgr._policy = DummyPolicy()
result = mgr.checkPermission(PERMISSION, TARGET)
self.failUnless(result is DummyPolicy.CHECK_PERMISSION_RESULT)
self.failUnless(new_policy.CHECK_PERMISSION_ARGS[0] is PERMISSION)
self.failUnless(new_policy.CHECK_PERMISSION_ARGS[1] is TARGET)
self.failUnless(new_policy.CHECK_PERMISSION_ARGS[2] is context)
def test_validate_without_roles_delegates_to_policy(self):
from AccessControl.SimpleObjectPolicies import _noroles
context = DummyContext()
ACCESSED = object()
CONTAINER = object()
NAME = 'NAME'
VALUE = object()
mgr = self._makeOne(_THREAD_ID, context)
new_policy = mgr._policy = DummyPolicy()
result = mgr.validate(ACCESSED,
CONTAINER,
NAME,
VALUE,
)
self.failUnless(result)
self.assertEqual(len(new_policy.VALIDATE_ARGS), 5)
self.failUnless(new_policy.VALIDATE_ARGS[0] is ACCESSED)
self.failUnless(new_policy.VALIDATE_ARGS[1] is CONTAINER)
self.assertEqual(new_policy.VALIDATE_ARGS[2], NAME)
self.failUnless(new_policy.VALIDATE_ARGS[3] is VALUE)
self.failUnless(new_policy.VALIDATE_ARGS[4] is context)
def test_validate_with_roles_delegates_to_policy(self):
from AccessControl.SimpleObjectPolicies import _noroles
context = DummyContext()
ACCESSED = object()
CONTAINER = object()
NAME = 'NAME'
VALUE = object()
ROLES = ('Hamlet', 'Othello')
mgr = self._makeOne(_THREAD_ID, context)
new_policy = mgr._policy = DummyPolicy()
result = mgr.validate(ACCESSED,
CONTAINER,
NAME,
VALUE,
ROLES,
)
self.failUnless(result)
self.assertEqual(len(new_policy.VALIDATE_ARGS), 6)
self.failUnless(new_policy.VALIDATE_ARGS[0] is ACCESSED)
self.failUnless(new_policy.VALIDATE_ARGS[1] is CONTAINER)
self.assertEqual(new_policy.VALIDATE_ARGS[2], NAME)
self.failUnless(new_policy.VALIDATE_ARGS[3] is VALUE)
self.failUnless(new_policy.VALIDATE_ARGS[4] is context)
self.assertEqual(new_policy.VALIDATE_ARGS[5], ROLES)
def test_DTMLValidate_delegates_to_policy_validate(self):
from AccessControl.SimpleObjectPolicies import _noroles
context = DummyContext()
ACCESSED = object()
CONTAINER = object()
NAME = 'NAME'
VALUE = object()
MD = {}
mgr = self._makeOne(_THREAD_ID, context)
new_policy = mgr._policy = DummyPolicy()
result = mgr.DTMLValidate(ACCESSED,
CONTAINER,
NAME,
VALUE,
MD,
)
self.failUnless(result)
self.assertEqual(len(new_policy.VALIDATE_ARGS), 5)
self.failUnless(new_policy.VALIDATE_ARGS[0] is ACCESSED)
self.failUnless(new_policy.VALIDATE_ARGS[1] is CONTAINER)
self.assertEqual(new_policy.VALIDATE_ARGS[2], NAME)
self.failUnless(new_policy.VALIDATE_ARGS[3] is VALUE)
self.failUnless(new_policy.VALIDATE_ARGS[4] is context)
class PythonSecurityManagerTests(SecurityManagerTestBase,
ISecurityManagerConformance,
):
def _getTargetClass(self):
from AccessControl.ImplPython import SecurityManager
return SecurityManager
# N.B.: The C version mixes in the Python version, which is why we
# can test for conformance to ISecurityManager.
class C_SecurityManagerTests(SecurityManagerTestBase,
ISecurityManagerConformance,
):
def _getTargetClass(self):
from AccessControl.ImplC import SecurityManager
return SecurityManager
def test_suite():
suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite( PythonSecurityManagerTests ) )
suite.addTest( unittest.makeSuite( C_SecurityManagerTests ) )
return suite
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
##############################################################################
#
# Copyright (c) 2004, 2005 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test security induced by ZCML
"""
from zope.interface import implements
from zope.interface import Interface
from zope.schema import TextLine
from AccessControl.SecurityInfo import ClassSecurityInfo
class ISuperDummy(Interface):
"""
"""
def superMethod():
"""
"""
class IDummy(ISuperDummy):
"""Just a marker interface"""
def foo():
"""
"""
class Dummy1:
implements(IDummy)
def foo(self): pass
def bar(self): pass
def baz(self): pass
def keg(self): pass
def wot(self): pass
def superMethod(self): pass
class Dummy2(Dummy1):
security = ClassSecurityInfo()
security.declarePublic('foo')
security.declareProtected('View management screens', 'bar')
security.declarePrivate('baz')
security.declareProtected('View management screens', 'keg')
class IDummy3(Interface):
attr = TextLine(title=u"Attribute")
class Dummy3:
implements(IDummy3)
attr = None
class Dummy4:
foo = None
class Dummy5:
pass
def test_security_equivalence():
"""This test demonstrates that the traditional declarative security of
Zope 2 can be replaced by ZCML statements without any loss of
information.
>>> from zope.component.testing import setUp, tearDown
>>> setUp()
We start out with two classes, ``Dummy1`` and ``Dummy2``. They
are identical in every way, except that ``Dummy2`` has security
declarations and ``Dummy1`` does not. Before we do anything, none
of them have security access controls:
>>> from AccessControl.tests.testZCML import Dummy1, Dummy2
>>> hasattr(Dummy1, '__ac_permissions__')
False
>>> hasattr(Dummy2, '__ac_permissions__')
False
Before we can make security declarations through ZCML, we need to
register the directive and the permission:
>>> import AccessControl
>>> from zope.configuration.xmlconfig import XMLConfig
>>> XMLConfig('meta.zcml', AccessControl)()
>>> XMLConfig('permissions.zcml', AccessControl)()
Now we initialize the security for ``Dummy2`` and provide some
ZCML declarations for ``Dummy1``:
>>> from StringIO import StringIO
>>> configure_zcml = StringIO('''
... <configure xmlns="http://namespaces.zope.org/zope">
... <class class="AccessControl.tests.testZCML.Dummy1">
... <allow attributes="foo" />
... <!--deny attributes="baz" /--> <!-- XXX not yet supported -->
... </class>
... <class class="AccessControl.tests.testZCML.Dummy1">
... <require attributes="bar keg"
... permission="zope2.ViewManagementScreens"
... />
... </class>
... </configure>
... ''')
>>> from zope.configuration.xmlconfig import xmlconfig
>>> xmlconfig(configure_zcml)
>>> from AccessControl.class_init import InitializeClass
>>> InitializeClass(Dummy2)
Now we compare their access controls:
>>> ac1 = getattr(Dummy1, '__ac_permissions__')
>>> ac2 = getattr(Dummy2, '__ac_permissions__')
>>> ac1 == ac2
True
Now we look at the individual permissions:
>>> from AccessControl.ZopeSecurityPolicy import getRoles
>>> from AccessControl import ACCESS_PUBLIC
>>> from AccessControl import ACCESS_PRIVATE
>>> dummy1 = Dummy1()
>>> getRoles(dummy1, 'bar', dummy1.bar, ('Def',))
('Manager',)
>>> getRoles(dummy1, 'keg', dummy1.keg, ('Def',))
('Manager',)
>>> getRoles(dummy1, 'foo', dummy1.foo, ('Def',)) is ACCESS_PUBLIC
True
#>>> getRoles(dummy1, 'baz', dummy1.baz, ('Def',)) is ACCESS_PRIVATE
#True XXX Not yet supported.
>>> dummy2 = Dummy2()
>>> getRoles(dummy2, 'bar', dummy2.bar, ('Def',))
('Manager',)
>>> getRoles(dummy2, 'keg', dummy2.keg, ('Def',))
('Manager',)
>>> getRoles(dummy2, 'foo', dummy2.foo, ('Def',)) is ACCESS_PUBLIC
True
>>> getRoles(dummy2, 'baz', dummy2.baz, ('Def',)) is ACCESS_PRIVATE
True
Before we end we should clean up after ourselves:
>>> from AccessControl.security import clearSecurityInfo
>>> clearSecurityInfo(Dummy1)
>>> clearSecurityInfo(Dummy2)
>>> tearDown()
"""
def test_set_warnings():
"""This test demonstrates that set_attributes and set_schema will result
in warnings, not errors. This type of protection doesn't make sense in
Zope 2, but we want to be able to re-use Zope Toolkit packages that use
them without error.
>>> from zope.component.testing import setUp, tearDown
>>> setUp()
Before we can make security declarations through ZCML, we need to
register the directive and the permission:
>>> import AccessControl
>>> from zope.configuration.xmlconfig import XMLConfig
>>> XMLConfig('meta.zcml', AccessControl)()
>>> XMLConfig('permissions.zcml', AccessControl)()
Now we provide some ZCML declarations for ``Dummy1``:
>>> from StringIO import StringIO
>>> configure_zcml = StringIO('''
... <configure xmlns="http://namespaces.zope.org/zope">
...
... <class class="AccessControl.tests.testZCML.Dummy3">
... <require
... permission="zope2.View"
... interface="AccessControl.tests.testZCML.IDummy3"
... />
... <require
... permission="zope2.ChangeConfig"
... set_schema="AccessControl.tests.testZCML.IDummy3"
... />
... </class>
...
... <class class="AccessControl.tests.testZCML.Dummy4">
... <require
... permission="zope2.ChangeConfig"
... set_attributes="foo"
... />
... </class>
...
... </configure>
... ''')
Running this should not throw an exception (but will print a warning to
stderr)
>>> from warnings import catch_warnings
>>> from zope.configuration.xmlconfig import xmlconfig
>>> warned = []
>>> with catch_warnings(record=True) as trapped:
... xmlconfig(configure_zcml)
... warned.extend(list(trapped))
>>> len(warned)
2
>>> str(warned[0].message)
'The set_schema option...'
>>> str(warned[1].message)
'The set_attribute option...'
>>> tearDown()
"""
def test_checkPermission():
"""
Test checkPermission
>>> from zope.component.testing import setUp, tearDown
>>> setUp()
>>> from zope.component import eventtesting
>>> eventtesting.setUp()
zope.security has a function zope.security.checkPermission which provides
an easy way of checking whether the currently authenticated user
has the permission to access an object. The function delegates to
the security policy's checkPermission() method.
Zope2 has the same function, AccessControl.security.checkPermission,
but in a Zope2-compatible implementation. It too uses the currently
active security policy of Zope 2 for the actual permission
checking.
>>> import AccessControl
>>> from zope.configuration.xmlconfig import XMLConfig
>>> XMLConfig('meta.zcml', AccessControl)()
>>> XMLConfig('permissions.zcml', AccessControl)()
>>> from AccessControl.tests.testZCML import Dummy5
>>> dummy = Dummy5()
In the following we want to test AccessControl's checkPermission function.
What we want to assure is that checkPermission translates the Zope 2
permissions correctly, especially the edge cases:
a) zope2.Public (which should always be available to everyone)
>>> from AccessControl.security import checkPermission
>>> checkPermission('zope2.Public', dummy)
True
b) zope2.Private (which should never available to anyone)
>>> checkPermission('zope.Private', dummy)
False
>>> checkPermission('zope2.Private', dummy)
False
Any other standard Zope 2 permission will also resolve correctly:
>>> checkPermission('zope2.ViewManagementScreens', dummy)
False
Invalid permissions will obviously result in a negative response:
>>> checkPermission('notapermission', dummy)
False
In addition to using AccessControl's ``checkPermission`` function
directly, we also expect the same behaviour when we use zope.security's
checkPermission function. Code from within other Zope packages will use
that and therefore it should work transparently.
For that to work, a new AccessControl "interaction" needs to be started
(the old one from placelesssetup needs to be ended first):
>>> from zope.security.management import endInteraction
>>> endInteraction()
>>> from AccessControl.security import newInteraction
>>> newInteraction()
a) zope2.Public (which should always be available to everyone)
>>> from zope.security import checkPermission
>>> checkPermission('zope2.Public', dummy)
True
b) zope2.Private (which should never available to anyone)
>>> checkPermission('zope.Private', dummy)
False
>>> checkPermission('zope2.Private', dummy)
False
Any other standard Zope 2 permission will also resolve correctly:
>>> checkPermission('zope2.ViewManagementScreens', dummy)
False
Invalid permissions will obviously result in a negative response:
>>> checkPermission('notapermission', dummy)
False
Clean up:
>>> tearDown()
"""
def test_register_permission():
"""This test demonstrates that if the <permission /> directive is used
to create a permission that does not already exist, it is created on
startup, with roles defaulting to Manager.
>>> from zope.component.testing import setUp, tearDown
>>> setUp()
>>> from zope.component import eventtesting
>>> eventtesting.setUp()
First, we need to configure the relevant parts of AccessControl:
>>> import AccessControl
>>> from zope.configuration.xmlconfig import XMLConfig
>>> XMLConfig('meta.zcml', AccessControl)()
>>> XMLConfig('permissions.zcml', AccessControl)()
We can now register a permission in ZCML:
>>> from StringIO import StringIO
>>> configure_zcml = StringIO('''
... <configure xmlns="http://namespaces.zope.org/zope"
... i18n_domain="test">
...
... <permission
... id="AccessControl.tests.DummyPermission"
... title="AccessControl: Dummy permission"
... />
...
... </configure>
... ''')
>>> from zope.configuration.xmlconfig import xmlconfig
>>> xmlconfig(configure_zcml)
The permission will be made available globally, with default role set
of ('Manager',).
>>> from AccessControl.Permission import getPermissions
>>> permissions = getPermissions()
>>> [p[2] for p in permissions
... if p[0] == 'AccessControl: Dummy permission']
[('Manager',)]
Let's also ensure that permissions are not overwritten if they exist
already:
>>> from AccessControl.Permission import addPermission
>>> addPermission('Dummy: Other dummy', ('Anonymous', ))
>>> from StringIO import StringIO
>>> configure_zcml = StringIO('''
... <configure xmlns="http://namespaces.zope.org/zope"
... i18n_domain="test">
...
... <permission
... id="AccessControl.tests.OtherDummy"
... title="Dummy: Other dummy"
... />
...
... </configure>
... ''')
>>> from zope.configuration.xmlconfig import xmlconfig
>>> xmlconfig(configure_zcml)
>>> permissions = getPermissions()
>>> [p[2] for p in permissions if p[0] == 'Dummy: Other dummy']
[('Anonymous',)]
>>> tearDown()
"""
def test_suite():
import doctest
return doctest.DocTestSuite(optionflags=doctest.ELLIPSIS)
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test Zope Guards
"""
import doctest
import unittest
import os
import operator
import sys
if sys.version_info >= (2, 5):
from AccessControl.ZopeGuards import guarded_any, guarded_all
MIN_MAX_TAKE_KEY = True
else:
MIN_MAX_TAKE_KEY = False
try:
__file__
except NameError:
__file__ = os.path.abspath(sys.argv[1])
_FILEPATH = os.path.abspath( __file__ )
_HERE = os.path.dirname( _FILEPATH )
class SecurityManager:
def __init__(self, reject=0):
self.calls = []
self.reject = reject
def validate(self, *args):
from AccessControl import Unauthorized
self.calls.append(('validate', args))
if self.reject:
raise Unauthorized
return 1
def validateValue(self, *args):
from AccessControl import Unauthorized
self.calls.append(('validateValue', args))
if self.reject:
raise Unauthorized
return 1
def checkPermission(self, *args):
self.calls.append(('checkPermission', args))
return not self.reject
class GuardTestCase(unittest.TestCase):
def setSecurityManager(self, manager):
from AccessControl.SecurityManagement import get_ident
from AccessControl.SecurityManagement import _managers
key = get_ident()
old = _managers.get(key)
if manager is None:
del _managers[key]
else:
_managers[key] = manager
return old
class Method:
def __init__(self, *args):
self.args = args
class TestGuardedGetattr(GuardTestCase):
def setUp(self):
self.__sm = SecurityManager()
self.__old = self.setSecurityManager(self.__sm)
def tearDown(self):
self.setSecurityManager(self.__old)
def test_unauthorized(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_getattr
obj, name = Method(), 'args'
value = getattr(obj, name)
rc = sys.getrefcount(value)
self.__sm.reject = True
self.assertRaises(Unauthorized, guarded_getattr, obj, name)
self.assert_(self.__sm.calls)
del self.__sm.calls[:]
self.assertEqual(rc, sys.getrefcount(value))
def test_calls_validate_for_unknown_type(self):
from AccessControl.ZopeGuards import guarded_getattr
guarded_getattr(self, 'test_calls_validate_for_unknown_type')
self.assert_(self.__sm.calls)
def test_attr_handler_table(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_getattr
from AccessControl.SimpleObjectPolicies import ContainerAssertions
d = {}
_dict = type(d)
old = ContainerAssertions.get(_dict)
mytable = {'keys': 1,
'values': Method,
}
ContainerAssertions[_dict] = mytable
try:
guarded_getattr(d, 'keys')
self.assertEqual(len(self.__sm.calls), 0)
values = guarded_getattr(d, 'values')
self.assertEqual(values.__class__, Method)
self.assertEqual(values.args, (d, 'values'))
self.assertRaises(Unauthorized, guarded_getattr, d, 'items')
finally:
ContainerAssertions[_dict] = old
class TestDictGuards(GuardTestCase):
def test_get_simple(self):
from AccessControl.ZopeGuards import get_dict_get
get = get_dict_get({'foo': 'bar'}, 'get')
self.assertEqual(get('foo'), 'bar')
def test_get_default(self):
from AccessControl.ZopeGuards import get_dict_get
get = get_dict_get({'foo': 'bar'}, 'get')
self.failUnless(get('baz') is None)
self.assertEqual(get('baz', 'splat'), 'splat')
def test_get_validates(self):
from AccessControl.ZopeGuards import get_dict_get
sm = SecurityManager()
old = self.setSecurityManager(sm)
get = get_dict_get({'foo':GuardTestCase}, 'get')
try:
get('foo')
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
def test_pop_simple(self):
from AccessControl.ZopeGuards import get_dict_pop
pop = get_dict_pop({'foo': 'bar'}, 'pop')
self.assertEqual(pop('foo'), 'bar')
def test_pop_raises(self):
from AccessControl.ZopeGuards import get_dict_pop
pop = get_dict_pop({'foo': 'bar'}, 'pop')
self.assertRaises(KeyError, pop, 'baz')
def test_pop_default(self):
from AccessControl.ZopeGuards import get_dict_pop
pop = get_dict_pop({'foo': 'bar'}, 'pop')
self.assertEqual(pop('baz', 'splat'), 'splat')
def test_pop_validates(self):
from AccessControl.ZopeGuards import get_dict_get
sm = SecurityManager()
old = self.setSecurityManager(sm)
pop = get_dict_get({'foo':GuardTestCase}, 'pop')
try:
pop('foo')
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
if sys.version_info >= (2, 2):
def test_iterkeys_simple(self):
from AccessControl.ZopeGuards import get_iter
d = {'foo':1, 'bar':2, 'baz':3}
iterkeys = get_iter(d, 'iterkeys')
keys = d.keys()
keys.sort()
ikeys = list(iterkeys())
ikeys.sort()
self.assertEqual(keys, ikeys)
def test_iterkeys_empty(self):
from AccessControl.ZopeGuards import get_iter
iterkeys = get_iter({}, 'iterkeys')
self.assertEqual(list(iterkeys()), [])
def test_iterkeys_validates(self):
from AccessControl.ZopeGuards import get_iter
sm = SecurityManager()
old = self.setSecurityManager(sm)
iterkeys = get_iter({GuardTestCase: 1}, 'iterkeys')
try:
iterkeys().next()
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
def test_itervalues_simple(self):
from AccessControl.ZopeGuards import get_iter
d = {'foo':1, 'bar':2, 'baz':3}
itervalues = get_iter(d, 'itervalues')
values = d.values()
values.sort()
ivalues = list(itervalues())
ivalues.sort()
self.assertEqual(values, ivalues)
def test_itervalues_empty(self):
from AccessControl.ZopeGuards import get_iter
itervalues = get_iter({}, 'itervalues')
self.assertEqual(list(itervalues()), [])
def test_itervalues_validates(self):
from AccessControl.ZopeGuards import get_iter
sm = SecurityManager()
old = self.setSecurityManager(sm)
itervalues = get_iter({GuardTestCase: 1}, 'itervalues')
try:
itervalues().next()
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
class TestListGuards(GuardTestCase):
def test_pop_simple(self):
from AccessControl.ZopeGuards import get_list_pop
pop = get_list_pop(['foo', 'bar', 'baz'], 'pop')
self.assertEqual(pop(), 'baz')
self.assertEqual(pop(0), 'foo')
def test_pop_raises(self):
from AccessControl.ZopeGuards import get_list_pop
pop = get_list_pop([], 'pop')
self.assertRaises(IndexError, pop)
def test_pop_validates(self):
from AccessControl.ZopeGuards import get_list_pop
sm = SecurityManager()
old = self.setSecurityManager(sm)
pop = get_list_pop([GuardTestCase], 'pop')
try:
pop()
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
class TestBuiltinFunctionGuards(GuardTestCase):
def test_zip_fails(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_zip
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_zip, [1,2,3], [3,2,1])
self.assertRaises(Unauthorized, guarded_zip, [1,2,3], [1])
self.setSecurityManager(old)
def test_map_fails(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_map
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_map, str,
[1,2,3])
self.assertRaises(Unauthorized, guarded_map, lambda x,y: x+y,
[1,2,3], [3,2,1])
self.setSecurityManager(old)
if sys.version_info >= (2, 5):
def test_all_fails(self):
from AccessControl import Unauthorized
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_all, [True,True,False])
self.setSecurityManager(old)
def test_any_fails(self):
from AccessControl import Unauthorized
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_any, [True,True,False])
self.setSecurityManager(old)
def test_min_fails(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_min
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_min, [1,2,3])
self.assertRaises(Unauthorized, guarded_min, 1,2,3)
if MIN_MAX_TAKE_KEY:
class MyDict(dict): # guard() skips 'dict' values
pass
self.assertRaises(Unauthorized, guarded_min,
MyDict(x=1), MyDict(x=2),
key=operator.itemgetter('x'))
self.setSecurityManager(old)
def test_max_fails(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_max
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_max, [1,2,3])
self.assertRaises(Unauthorized, guarded_max, 1,2,3)
if MIN_MAX_TAKE_KEY:
class MyDict(dict): # guard() skips 'dict' values
pass
self.assertRaises(Unauthorized, guarded_max,
MyDict(x=1), MyDict(x=2),
key=operator.itemgetter('x'))
self.setSecurityManager(old)
def test_enumerate_fails(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_enumerate
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
enum = guarded_enumerate([1,2,3])
self.assertRaises(Unauthorized, enum.next)
self.setSecurityManager(old)
def test_sum_fails(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_sum
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_sum, [1,2,3])
self.setSecurityManager(old)
def test_zip_succeeds(self):
from AccessControl.ZopeGuards import guarded_zip
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_zip([1,2,3], [3,2,1]), [(1,3),(2,2),(3,1)])
self.assertEqual(guarded_zip([1,2,3], [1]), [(1,1)])
self.setSecurityManager(old)
def test_map_succeeds(self):
from AccessControl.ZopeGuards import guarded_map
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_map(str, [1,2,3]), ['1','2','3'])
self.assertEqual(guarded_map(lambda x,y: x+y, [1,2,3], [3,2,1]),
[4,4,4])
self.setSecurityManager(old)
if sys.version_info >= (2, 5):
def test_all_succeeds(self):
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_all([True,True,False]), False)
self.setSecurityManager(old)
def test_any_succeeds(self):
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEquals(guarded_any([True,True,False]), True)
self.setSecurityManager(old)
def test_min_succeeds(self):
from AccessControl.ZopeGuards import guarded_min
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_min([1,2,3]), 1)
self.assertEqual(guarded_min(1,2,3), 1)
if MIN_MAX_TAKE_KEY:
class MyDict(dict): # guard() skips 'dict' values
pass
self.assertEqual(guarded_min(MyDict(x=1), MyDict(x=2),
key=operator.itemgetter('x')),
{'x':1})
self.setSecurityManager(old)
def test_max_succeeds(self):
from AccessControl.ZopeGuards import guarded_max
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_max([1,2,3]), 3)
self.assertEqual(guarded_max(1,2,3), 3)
if MIN_MAX_TAKE_KEY:
class MyDict(dict): # guard() skips 'dict' values
pass
self.assertEqual(guarded_max(MyDict(x=1), MyDict(x=2),
key=operator.itemgetter('x')),
{'x':2})
self.setSecurityManager(old)
def test_enumerate_succeeds(self):
from AccessControl.ZopeGuards import guarded_enumerate
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
enum = guarded_enumerate([1,2,3])
self.assertEqual(enum.next(), (0,1))
self.assertEqual(enum.next(), (1,2))
self.assertEqual(enum.next(), (2,3))
self.assertRaises(StopIteration, enum.next)
self.setSecurityManager(old)
def test_sum_succeeds(self):
from AccessControl.ZopeGuards import guarded_sum
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_sum([1,2,3]), 6)
self.assertEqual(guarded_sum([1,2,3], start=36), 42)
self.setSecurityManager(old)
def test_apply(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import safe_builtins
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
gapply = safe_builtins['apply']
def f(a=1, b=2):
return a+b
# This one actually succeeds, because apply isn't given anything
# to unpack.
self.assertEqual(gapply(f), 3)
# Likewise, because the things passed are empty.
self.assertEqual(gapply(f, (), {}), 3)
self.assertRaises(Unauthorized, gapply, f, [1])
self.assertRaises(Unauthorized, gapply, f, (), {'a': 2})
self.assertRaises(Unauthorized, gapply, f, [1], {'a': 2})
sm = SecurityManager(0) # accepts
self.setSecurityManager(sm)
self.assertEqual(gapply(f), 3)
self.assertEqual(gapply(f, (), {}), 3)
self.assertEqual(gapply(f, [0]), 2)
self.assertEqual(gapply(f, [], {'b': 18}), 19)
self.assertEqual(gapply(f, [10], {'b': 1}), 11)
self.setSecurityManager(old)
class TestGuardedDictListTypes(unittest.TestCase):
def testDictCreation(self):
from AccessControl.ZopeGuards import safe_builtins
d = safe_builtins['dict']
self.assertEquals(d(), {})
self.assertEquals(d({1:2}), {1:2})
self.assertEquals(d(((1,2),)), {1:2})
self.assertEquals(d(foo=1), {"foo":1})
self.assertEquals(d.fromkeys((1,2,3)), {1:None, 2:None, 3:None})
self.assertEquals(d.fromkeys((1,2,3), 'f'), {1:'f', 2:'f', 3:'f'})
def testListCreation(self):
from AccessControl.ZopeGuards import safe_builtins
l = safe_builtins['list']
self.assertEquals(l(), [])
self.assertEquals(l([1,2,3]), [1,2,3])
x = [3,2,1]
self.assertEquals(l(x), [3,2,1])
if sys.version_info >= (2, 4):
self.assertEquals(sorted(x), [1,2,3])
class TestRestrictedPythonApply(GuardTestCase):
def test_apply(self):
from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_apply
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
gapply = guarded_apply
def f(a=1, b=2):
return a+b
# This one actually succeeds, because apply isn't given anything
# to unpack.
self.assertEqual(gapply(*(f,)), 3)
# Likewise, because the things passed are empty.
self.assertEqual(gapply(*(f,), **{}), 3)
self.assertRaises(Unauthorized, gapply, *(f, 1))
self.assertRaises(Unauthorized, gapply, *(f,), **{'a': 2})
self.assertRaises(Unauthorized, gapply, *(f, 1), **{'a': 2})
sm = SecurityManager(0) # accepts
self.setSecurityManager(sm)
self.assertEqual(gapply(*(f,)), 3)
self.assertEqual(gapply(*(f,), **{}), 3)
self.assertEqual(gapply(*(f, 0)), 2)
self.assertEqual(gapply(*(f,), **{'b': 18}), 19)
self.assertEqual(gapply(*(f, 10), **{'b': 1}), 11)
self.setSecurityManager(old)
# Map function name to the # of times it's been called.
wrapper_count = {}
class FuncWrapper:
def __init__(self, funcname, func):
self.funcname = funcname
wrapper_count[funcname] = 0
self.func = func
def __call__(self, *args, **kws):
wrapper_count[self.funcname] += 1
return self.func(*args, **kws)
def __repr__(self):
return "<FuncWrapper around %r>" % self.func
# Given the high wall between AccessControl and RestrictedPython, I suppose
# the next one could be called an integration test. But we're simply
# trying to run restricted Python with the *intended* implementations of
# the special wrappers here, so no apologies.
_ProtectedBase = None
class TestActualPython(GuardTestCase):
_old_mgr = _old_policy = _marker = []
def setUp(self):
self._wrapped_dicts = []
def tearDown( self ):
self._restorePolicyAndManager()
for munged, orig in self._wrapped_dicts:
munged.update(orig)
del self._wrapped_dicts
def _initPolicyAndManager(self, manager=None):
from AccessControl.SecurityManagement import get_ident
from AccessControl.SecurityManagement import _managers
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManager import setSecurityPolicy
from AccessControl.ZopeSecurityPolicy import ZopeSecurityPolicy
class UnderprivilegedUser:
""" Anonymous USer for unit testing purposes.
"""
def getId(self):
return 'Underprivileged User'
getUserName = getId
def allowed(self, object, object_roles=None):
return 0
def getRoles(self):
return ()
self._policy = ZopeSecurityPolicy()
self._old_policy = setSecurityPolicy(self._policy)
if manager is None:
thread_id = get_ident()
self._old_mgr = manager=_managers.get(thread_id, self._marker)
newSecurityManager(None, UnderprivilegedUser())
else:
self._old_mgr = self.setSecurityManager(manager)
def _restorePolicyAndManager(self):
from AccessControl.SecurityManagement import noSecurityManager
from AccessControl.SecurityManager import setSecurityPolicy
if self._old_mgr is not self._marker:
self.setSecurityManager(self._old_mgr)
else:
noSecurityManager()
if self._old_policy is not self._marker:
setSecurityPolicy(self._old_policy)
def _getProtectedBaseClass(self):
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from ExtensionClass import Base
global _ProtectedBase
if _ProtectedBase is None:
class ProtectedBase(Base):
security = ClassSecurityInfo()
security.declarePrivate('private_method')
def private_method(self):
return 'private_method called'
InitializeClass(ProtectedBase)
_ProtectedBase = ProtectedBase
return _ProtectedBase
def testPython(self):
from RestrictedPython.tests import verify
code, its_globals = self._compile("actual_python.py")
verify.verify(code)
# Fiddle the global and safe-builtins dicts to count how many times
# the special functions are called.
self._wrap_replaced_dict_callables(its_globals)
self._wrap_replaced_dict_callables(its_globals['__builtins__'])
sm = SecurityManager()
old = self.setSecurityManager(sm)
try:
exec code in its_globals
finally:
self.setSecurityManager(old)
# Use wrapper_count to determine coverage.
## print wrapper_count # uncomment to see wrapper names & counts
untouched = [k for k, v in wrapper_count.items() if v == 0]
if untouched:
untouched.sort()
self.fail("Unexercised wrappers: %r" % untouched)
def testPythonRealAC(self):
code, its_globals = self._compile("actual_python.py")
exec code in its_globals
def test_derived_class_normal(self):
from AccessControl import Unauthorized
from RestrictedPython.tests import verify
NORMAL_SCRIPT = """
class Normal(ProtectedBase):
pass
normal = Normal()
print normal.private_method()
"""
code, its_globals = self._compile_str(NORMAL_SCRIPT, 'normal_script')
its_globals['ProtectedBase'] = self._getProtectedBaseClass()
verify.verify(code)
self._initPolicyAndManager()
try:
exec code in its_globals
except Unauthorized:
pass
else:
self.fail("Didn't raise Unauthorized: \n%s" %
its_globals['_print']())
def test_derived_class_sneaky_en_suite(self):
# Disallow declaration of security-affecting names in classes
# defined in restricted code (compile-time check).
from RestrictedPython.tests import verify
SNEAKY_SCRIPT = """
class Sneaky(ProtectedBase):
private_method__roles__ = None
sneaky = Sneaky()
print sneaky.private_method()
"""
try:
code, its_globals = self._compile_str(SNEAKY_SCRIPT,
'sneaky_script')
except SyntaxError:
pass
else:
self.fail("Didn't raise SyntaxError!")
def test_derived_sneaky_post_facto(self):
# Assignment to a class outside its suite fails at
# compile time with a SyntaxError.
from RestrictedPython.tests import verify
SNEAKY_SCRIPT = """
class Sneaky(ProtectedBase):
pass
Sneaky.private_method__roles__ = None
sneaky = Sneaky()
print sneaky.private_method()
"""
try:
code, its_globals = self._compile_str(SNEAKY_SCRIPT, 'sneaky_script')
except SyntaxError:
pass
else:
self.fail("Didn't raise SyntaxError!")
def test_derived_sneaky_instance(self):
# Assignment of security-sensitive names to an instance
# fails at compile time with a SyntaxError.
from RestrictedPython.tests import verify
SNEAKY_SCRIPT = """
class Sneaky(ProtectedBase):
pass
sneaky = Sneaky()
sneaky.private_method__roles__ = None
print sneaky.private_method()
"""
try:
code, its_globals = self._compile_str(SNEAKY_SCRIPT,
'sneaky_script')
except SyntaxError:
pass
else:
self.fail("Didn't raise SyntaxError!")
def test_dict_access(self):
from RestrictedPython.tests import verify
SIMPLE_DICT_ACCESS_SCRIPT = """
def foo(text):
return text
kw = {'text':'baz'}
print foo(**kw)
kw = {'text':True}
print foo(**kw)
"""
code, its_globals = self._compile_str(SIMPLE_DICT_ACCESS_SCRIPT, 'x')
verify.verify(code)
sm = SecurityManager()
old = self.setSecurityManager(sm)
try:
exec code in its_globals
finally:
self.setSecurityManager(old)
self.assertEqual(its_globals['_print'](),
'baz\nTrue\n')
def _compile_str(self, text, name):
from RestrictedPython import compile_restricted
from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr
code = compile_restricted(text, name, 'exec')
g = get_safe_globals()
g['_getattr_'] = guarded_getattr
g['__debug__'] = 1 # so assert statements are active
g['__name__'] = __name__ # so classes can be defined in the script
return code, g
def testPythonRealAC(self):
code, its_globals = self._compile("actual_python.py")
exec code in its_globals
# Compile code in fname, as restricted Python. Return the
# compiled code, and a safe globals dict for running it in.
# fname is the string name of a Python file; it must be found
# in the same directory as this file.
def _compile(self, fname):
from RestrictedPython import compile_restricted
from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr
fn = os.path.join( _HERE, fname)
text = open(fn).read()
return self._compile_str(text, fn)
# d is a dict, the globals for execution or our safe builtins.
# The callable values which aren't the same as the corresponding
# entries in __builtin__ are wrapped in a FuncWrapper, so we can
# tell whether they're executed.
def _wrap_replaced_dict_callables(self, d):
import __builtin__
orig = d.copy()
self._wrapped_dicts.append((d, orig))
for k, v in d.items():
if callable(v) and v is not getattr(__builtin__, k, None):
d[k] = FuncWrapper(k, v)
def test_inplacevar():
"""
Verify the correct behavior of protected_inplacevar.
>>> from AccessControl.ZopeGuards import protected_inplacevar
Basic operations on objects without inplace slots work as expected:
>>> protected_inplacevar('+=', 1, 2)
3
>>> protected_inplacevar('-=', 5, 2)
3
>>> protected_inplacevar('*=', 5, 2)
10
>>> protected_inplacevar('/=', 6, 2)
3
>>> protected_inplacevar('%=', 5, 2)
1
>>> protected_inplacevar('**=', 5, 2)
25
>>> protected_inplacevar('<<=', 5, 2)
20
>>> protected_inplacevar('>>=', 5, 2)
1
>>> protected_inplacevar('&=', 5, 2)
0
>>> protected_inplacevar('^=', 7, 2)
5
>>> protected_inplacevar('|=', 5, 2)
7
Inplace operations are allowed on lists:
>>> protected_inplacevar('+=', [1], [2])
[1, 2]
>>> protected_inplacevar('*=', [1], 2)
[1, 1]
But not on custom objects:
>>> class C:
... def __iadd__(self, other):
... return 42
>>> protected_inplacevar('+=', C(), 2) # doctest: +NORMALIZE_WHITESPACE
Traceback (most recent call last):
...
TypeError: Augmented assignment to C objects is not allowed in
untrusted code
"""
if sys.version_info[:2] >= (2, 4):
def test_inplacevar_for_py24():
"""
protected_inplacevar allows inplce ops on sets:
>>> from AccessControl.ZopeGuards import protected_inplacevar
>>> s = set((1,2,3,4))
>>> sorted(protected_inplacevar('-=', s, set((1, 3))))
[2, 4]
>>> sorted(s)
[2, 4]
>>> sorted(protected_inplacevar('|=', s, set((1, 3, 9))))
[1, 2, 3, 4, 9]
>>> sorted(s)
[1, 2, 3, 4, 9]
>>> sorted(protected_inplacevar('&=', s, set((1, 2, 3, 9))))
[1, 2, 3, 9]
>>> sorted(s)
[1, 2, 3, 9]
>>> sorted(protected_inplacevar('^=', s, set((1, 3, 7, 8))))
[2, 7, 8, 9]
>>> sorted(s)
[2, 7, 8, 9]
"""
def test_suite():
suite = unittest.TestSuite([
doctest.DocTestSuite(),
])
for cls in (TestGuardedGetattr,
TestDictGuards,
TestBuiltinFunctionGuards,
TestListGuards,
TestGuardedDictListTypes,
TestRestrictedPythonApply,
TestActualPython,
):
suite.addTest(unittest.makeSuite(cls))
return suite
if __name__ == '__main__':
unittest.main()
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Tests of ZopeSecurityPolicy
"""
import sys
import unittest
from Acquisition import Implicit, Explicit
from MethodObject import Method
from zExceptions import Unauthorized
from AccessControl.userfolder import UserFolder
from AccessControl.SecurityManagement import SecurityContext
user_roles = ('RoleOfUser',)
eo_roles = ('RoleOfExecutableOwner',)
sysadmin_roles = ('RoleOfSysAdmin',)
class App(Explicit):
def unrestrictedTraverse(self, path):
ob = self
for el in path:
ob = getattr(ob, el)
return ob
class PublicMethod (Method):
def getOwner(self):
return None
def __call__(*args, **kw):
return args, kw
def getWrappedOwner(self):
return None
__roles__ = None
class ProtectedMethod (PublicMethod):
__roles__ = user_roles
class OwnedMethod (PublicMethod):
__roles__ = eo_roles
def getOwner(self):
return self.aq_parent.aq_parent.acl_users.getUserById('theowner')
def getWrappedOwner(self):
acl_users = self.aq_parent.aq_parent.acl_users
user = acl_users.getUserById('theowner')
return user.__of__(acl_users)
class setuidMethod (PublicMethod):
_proxy_roles = sysadmin_roles
class OwnedSetuidMethod(Implicit):
__roles__ = eo_roles
_proxy_roles = sysadmin_roles
def getOwner(self, info=0):
if info:
return (('subobject', 'acl_users'), 'theowner')
else:
return self.aq_parent.aq_parent.acl_users.getUserById('theowner')
def getWrappedOwner(self):
acl_users = self.aq_parent.aq_parent.acl_users
user = acl_users.getUserById('theowner')
return user.__of__(acl_users)
class DangerousMethod (PublicMethod):
# Only accessible to sysadmin or people who use proxy roles
__roles__ = sysadmin_roles
class SimpleItemish (Implicit):
public_m = PublicMethod()
protected_m = ProtectedMethod()
owned_m = OwnedMethod()
setuid_m = setuidMethod()
dangerous_m = DangerousMethod()
public_prop = 'Public Value'
private_prop = 'Private Value'
class ImplictAcqObject(Implicit):
pass
class UnprotectedSimpleItem (SimpleItemish):
__allow_access_to_unprotected_subobjects__ = 1
class UnprotectedSimpleItemBool (SimpleItemish):
__allow_access_to_unprotected_subobjects__ = True
class OwnedSimpleItem(UnprotectedSimpleItem):
def getOwner(self, info=0):
if info:
return (('subobject', 'acl_users'), 'theowner')
else:
return self.aq_parent.acl_users.getuserById('theowner')
class RestrictedSimpleItem (SimpleItemish):
__allow_access_to_unprotected_subobjects__ = 0
_Foo_Permission = user_roles + eo_roles
_Kill_Permission = sysadmin_roles
_View_Permission = eo_roles
class PartlyProtectedSimpleItem1 (SimpleItemish):
__allow_access_to_unprotected_subobjects__ = {'public_prop': 1,}
class PartlyProtectedSimpleItem2 (SimpleItemish):
def __allow_access_to_unprotected_subobjects__(self, name, value):
if name == 'public_prop':
return 1
return 0
class PartlyProtectedSimpleItem3 (PartlyProtectedSimpleItem1):
# Set the roles of objects that are accessible because of
# __allow_access_to_unprotected_subobjects__ .
__roles__ = sysadmin_roles
class SimpleClass:
attr = 1
class ZopeSecurityPolicyTestBase(unittest.TestCase):
def setUp(self):
a = App()
self.a = a
a.item = UnprotectedSimpleItem()
a.itemb = UnprotectedSimpleItemBool()
self.item = a.item
a.r_item = RestrictedSimpleItem()
a.item1 = PartlyProtectedSimpleItem1()
a.item2 = PartlyProtectedSimpleItem2()
a.item3 = PartlyProtectedSimpleItem3()
uf = UserFolder()
a.acl_users = uf
self.uf = a.acl_users
uf._doAddUser('joe', 'password', user_roles, ())
uf._doAddUser('theowner', 'password', eo_roles, ())
user = uf.getUserById('joe')
self.user = user
context = SecurityContext(user)
self.context = context
self.policy = self._makeOne()
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
def assertPolicyAllows(self, ob, attrname):
res = self.policy.validate(ob, ob, attrname, getattr(ob, attrname),
self.context)
if not res:
self.fail('Policy quietly denied %s' % attrname)
def assertPolicyDenies(self, ob, attrname):
try:
res = self.policy.validate(ob, ob, attrname, getattr(ob, attrname),
self.context)
except Unauthorized:
# Passed the test.
pass
else:
if res:
self.fail('Policy quietly allowed %s' % attrname)
else:
self.fail('Policy denied %s, but did not '
'throw an exception.' % attrname)
def testUserAccess(self):
item = self.item
self.assertPolicyAllows(item, 'public_m')
self.assertPolicyAllows(item, 'protected_m')
self.assertPolicyDenies(item, 'owned_m')
self.assertPolicyAllows(item, 'setuid_m')
self.assertPolicyDenies(item, 'dangerous_m')
def testOwnerAccess(self):
self.context = SecurityContext(self.uf.getUserById('theowner'))
item = self.item
self.assertPolicyAllows(item, 'public_m')
self.assertPolicyDenies(item, 'protected_m')
self.assertPolicyAllows(item, 'owned_m')
self.assertPolicyAllows(item, 'setuid_m')
self.assertPolicyDenies(item, 'dangerous_m')
def testProxyAccess(self):
item = self.item
self.context.stack.append(item.setuid_m)
self.assertPolicyAllows(item, 'public_m')
self.assertPolicyDenies(item, 'protected_m')
self.assertPolicyDenies(item, 'owned_m')
self.assertPolicyAllows(item, 'setuid_m')
self.assertPolicyAllows(item, 'dangerous_m')
def testIdentityProxy(self):
eo = ImplictAcqObject()
eo.getOwner = lambda: None
self.context.stack.append(eo)
rc = sys.getrefcount(eo)
self.testUserAccess()
self.assertEqual(rc, sys.getrefcount(eo))
eo._proxy_roles = ()
self.testUserAccess()
self.assertEqual(rc, sys.getrefcount(eo))
def testAccessToUnprotectedSubobjects(self):
item = self.item
itemb = self.a.itemb
r_item = self.a.r_item
item1 = self.a.item1
item2 = self.a.item2
item3 = self.a.item3
self.assertPolicyAllows(item, 'public_prop')
self.assertPolicyAllows(itemb, 'public_prop')
self.assertPolicyDenies(r_item,'public_prop')
self.assertPolicyAllows(item1, 'public_prop')
self.assertPolicyAllows(item2, 'public_prop')
self.assertPolicyDenies(item3,'public_prop')
self.assertPolicyAllows(item, 'private_prop')
self.assertPolicyDenies(r_item,'private_prop')
self.assertPolicyDenies(item1, 'private_prop')
self.assertPolicyDenies(item2, 'private_prop')
self.assertPolicyDenies(item3, 'private_prop')
def testAccessToSimpleContainer(self):
self.assertPolicyAllows({}, 'keys')
self.assertPolicyAllows([], 'append')
self.assertPolicyDenies(SimpleClass, 'attr')
self.assertPolicyDenies(SimpleClass(), 'attr')
c = SimpleClass()
c.attr = PublicMethod()
self.assertPolicyAllows(c, 'attr')
def testUnicodeAttributeLookups(self):
item = self.item
r_item = self.a.r_item
self.assertPolicyAllows(item, u'public_prop')
self.assertPolicyDenies(r_item, u'private_prop')
self.assertPolicyAllows(item, u'public_m')
self.assertPolicyDenies(item, u'dangerous_m')
def testRolesForPermission(self):
# Test of policy.checkPermission().
r_item = self.a.r_item
context = self.context
v = self.policy.checkPermission('View', r_item, context)
self.assert_(not v, '_View_Permission should deny access to user')
o_context = SecurityContext(self.uf.getUserById('theowner'))
v = self.policy.checkPermission('View', r_item, o_context)
self.assert_(v, '_View_Permission should grant access to theowner')
def test_checkPermission_respects_proxy_roles(self):
r_item = self.a.r_item
context = self.context
self.failIf(self.policy.checkPermission('View', r_item, context))
o_context = SecurityContext(self.uf.getUserById('joe'))
# Push an executable with proxy roles on the stack
eo = OwnedSetuidMethod().__of__(r_item)
eo._proxy_roles = eo_roles
context.stack.append(eo)
self.failUnless(self.policy.checkPermission('View', r_item, context))
def test_checkPermission_proxy_roles_limit_access(self):
r_item = self.a.r_item
context = self.context
self.failUnless(self.policy.checkPermission('Foo', r_item, context))
o_context = SecurityContext(self.uf.getUserById('joe'))
# Push an executable with proxy roles on the stack
eo = OwnedSetuidMethod().__of__(r_item)
eo._proxy_roles = sysadmin_roles
context.stack.append(eo)
self.failIf(self.policy.checkPermission('Foo', r_item, context))
def test_checkPermission_proxy_role_scope(self):
self.a.subobject = ImplictAcqObject()
subobject = self.a.subobject
subobject.acl_users = UserFolder()
subobject.acl_users._doAddUser('theowner', 'password',
eo_roles + sysadmin_roles, ())
subobject.r_item = RestrictedSimpleItem()
r_subitem = subobject.r_item
r_subitem.owned_setuid_m = OwnedSetuidMethod()
r_subitem.getPhysicalRoot = lambda root=self.a: root
r_item = self.a.r_item
r_item.getPhysicalRoot = lambda root=self.a: root
context = self.context
context.stack.append(r_subitem.owned_setuid_m.__of__(r_subitem))
# Out of owner context
self.failIf(self.policy.checkPermission('View', r_item, context))
self.failIf(self.policy.checkPermission('Kill', r_item, context))
# Inside owner context
self.failIf(self.policy.checkPermission('View', r_subitem, context))
self.failUnless(self.policy.checkPermission('Kill', r_subitem, context))
def testUnicodeRolesForPermission(self):
r_item = self.a.r_item
context = self.context
v = self.policy.checkPermission(u'View', r_item, context)
self.assert_(not v, '_View_Permission should deny access to user')
o_context = SecurityContext(self.uf.getUserById('theowner'))
v = self.policy.checkPermission(u'View', r_item, o_context)
self.assert_(v, '_View_Permission should grant access to theowner')
def testAqNames(self):
policy = self.policy
names = {
'aq_self': 0, 'aq_base': 0,
'aq_parent': 1, 'aq_explicit': 1, 'aq_inner': 1
}
for name, allowed in names.items():
if not allowed:
self.assertRaises(Unauthorized, policy.validate,
'', '', name, '', None)
else:
policy.validate('', '', name, '', None)
def testProxyRoleScope(self):
self.a.subobject = ImplictAcqObject()
subobject = self.a.subobject
subobject.acl_users = UserFolder()
subobject.acl_users._doAddUser('theowner', 'password',
eo_roles + sysadmin_roles, ())
subobject.item = UnprotectedSimpleItem()
subitem = subobject.item
subitem.owned_setuid_m = OwnedSetuidMethod()
subitem.getPhysicalRoot = lambda root=self.a: root
item = self.a.item
item.getPhysicalRoot = lambda root=self.a: root
self.context.stack.append(subitem.owned_setuid_m.__of__(subitem))
# Out of owner context
self.assertPolicyAllows(item, 'public_m')
self.assertPolicyDenies(item, 'protected_m')
self.assertPolicyDenies(item, 'owned_m')
self.assertPolicyAllows(item, 'setuid_m')
self.assertPolicyDenies(item, 'dangerous_m')
# Inside owner context
self.assertPolicyAllows(subitem, 'public_m')
self.assertPolicyDenies(subitem, 'protected_m')
self.assertPolicyDenies(subitem, 'owned_m')
self.assertPolicyAllows(subitem, 'setuid_m')
self.assertPolicyAllows(subitem, 'dangerous_m')
def testUnicodeName(self):
policy = self.policy
assert policy.validate('', '', u'foo', '', None)
if 0:
# This test purposely generates a log entry.
# Enable it if you don't mind it adding to the log.
def testInsaneRoles(self):
# Makes sure the policy doesn't blow up on bad input.
c = SimpleClass()
m = PublicMethod()
c.m = m
# Test good roles
self.assertPolicyAllows(c, 'm')
# Test bad roles
m.__roles__ = 1950
try:
self.assertPolicyAllows(c, 'm')
except TypeError:
pass
else:
self.fail('Policy accepted bad __roles__')
class ISecurityPolicyConformance:
def test_conforms_to_ISecurityPolicy(self):
from AccessControl.interfaces import ISecurityPolicy
from zope.interface.verify import verifyClass
verifyClass(ISecurityPolicy, self._getTargetClass())
class Python_ZSPTests(ZopeSecurityPolicyTestBase,
ISecurityPolicyConformance,
):
def _getTargetClass(self):
from AccessControl.ImplPython import ZopeSecurityPolicy
return ZopeSecurityPolicy
class C_ZSPTests(ZopeSecurityPolicyTestBase,
ISecurityPolicyConformance,
):
def _getTargetClass(self):
from AccessControl.ImplC import ZopeSecurityPolicy
return ZopeSecurityPolicy
def test_getRoles():
"""
>>> from AccessControl.ZopeSecurityPolicy import getRoles
>>> class C:
... x = 'CRole'
>>> class V:
... x = 'VRole'
>>> c = C()
>>> c.v = V()
>>> getRoles(c, None, c.v, 42)
42
>>> getRoles(c, 'inabox', c.v, 42)
42
>>> c.v.__roles__ = ['spam', 'eggs']
>>> getRoles(c, None, c.v, 42)
['spam', 'eggs']
>>> getRoles(c, 'withafox', c.v, 42)
['spam', 'eggs']
>>> del c.v.__roles__
>>> V.__roles__ = ('Manager', )
>>> getRoles(c, None, c.v, 42)
('Manager',)
>>> getRoles(c, 'withafox', c.v, 42)
('Manager',)
>>> del V.__roles__
>>> c.foo__roles__ = ('Foo', )
>>> getRoles(c, None, c.v, 42)
42
>>> getRoles(c, 'foo', c.v, 42)
42
>>> C.foo__roles__ = ('Editor', )
>>> getRoles(c, None, c.v, 42)
42
>>> getRoles(c, 'foo', c.v, 42)
('Editor',)
>>> del C.foo__roles__
>>> class ComputedRoles:
... def __init__(self, roles):
... self.roles = roles
... def rolesForPermissionOn(self, ob):
... return [ob.x] + self.roles
>>> c.v.__roles__ = ComputedRoles(['Member'])
>>> getRoles(c, None, c.v, 42)
['VRole', 'Member']
>>> getRoles(c, 'foo', c.v, 42)
['VRole', 'Member']
>>> c.foo__roles__ = ComputedRoles(['Admin'])
>>> getRoles(c, None, c.v, 42)
['VRole', 'Member']
>>> getRoles(c, 'foo', c.v, 42)
['VRole', 'Member']
>>> del c.v.__roles__
>>> getRoles(c, None, c.v, 42)
42
>>> getRoles(c, 'foo', c.v, 42)
42
>>> C.foo__roles__ = ComputedRoles(['Guest'])
>>> getRoles(c, None, c.v, 42)
42
>>> getRoles(c, 'foo', c.v, 42)
['CRole', 'Guest']
>>> V.__roles__ = ComputedRoles(['Member'])
>>> getRoles(c, None, c.v, 42)
['VRole', 'Member']
>>> getRoles(c, 'foo', c.v, 42)
['VRole', 'Member']
"""
def test_zsp_gets_right_roles_for_methods():
"""
>>> from AccessControl.ZopeSecurityPolicy import ZopeSecurityPolicy
>>> zsp = ZopeSecurityPolicy()
>>> from ExtensionClass import Base
>>> class C(Base):
... def foo(self):
... pass
... foo__roles__ = ['greeneggs', 'ham']
... def bar(self):
... pass
>>> class User:
... def __init__(self, roles):
... self.roles = roles
... def allowed(self, value, roles):
... for role in roles:
... if role in self.roles:
... return True
... return False
>>> class Context:
... stack = ()
... def __init__(self, user):
... self.user = user
>>> c = C()
>>> bool(zsp.validate(c, c, 'foo', c.foo, Context(User(['greeneggs']))))
True
>>> zsp.validate(c, c, 'foo', c.foo, Context(User(['spam'])))
Traceback (most recent call last):
...
Unauthorized: You are not allowed to access 'foo' in this context
>>> c.__roles__ = ['spam']
>>> zsp.validate(c, c, 'foo', c.foo, Context(User(['spam'])))
Traceback (most recent call last):
...
Unauthorized: You are not allowed to access 'foo' in this context
>>> zsp.validate(c, c, 'bar', c.bar, Context(User(['spam'])))
Traceback (most recent call last):
...
Unauthorized: You are not allowed to access 'bar' in this context
>>> c.__allow_access_to_unprotected_subobjects__ = 1
>>> bool(zsp.validate(c, c, 'bar', c.bar, Context(User(['spam']))))
True
"""
from doctest import DocTestSuite
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(Python_ZSPTests, 'test'))
suite.addTest(unittest.makeSuite(C_ZSPTests, 'test'))
suite.addTest(DocTestSuite())
return suite
#############################################################################
#
# Copyright (c) 2007 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
from zope.interface import implements
from zope.publisher.interfaces.browser import IBrowserRequest
class DummyRequest:
implements(IBrowserRequest)
def __init__(self, method):
self.method = method
def test_suite():
from doctest import DocFileSuite
return DocFileSuite('../requestmethod.txt',
globs=dict(GET=DummyRequest('GET'),
POST=DummyRequest('POST')))
if __name__ == '__main__':
import unittest
unittest.main(defaultTest='test_suite')
##############################################################################
#
# Copyright (c) 2003 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Tests for the guarded iterartor.
"""
import unittest
# Persistence system must be initialized.
import ZODB
from AccessControl import ZopeGuards
class SafeIterTestCase(unittest.TestCase):
# XXX these tests replace the global guard() function in
# AccessControl.ZopeGuards; this is not the nicest way to check
# that things work, but avoids making the SafeIter unit tests from
# testing things other than the guarded iterator itself. In
# particular, it avoids testing the actual guard checks, which
# should be tested separately.
def setUp(self):
self.original_guard = ZopeGuards.guard
ZopeGuards.guard = self.guard
self.checks = []
def tearDown(self):
ZopeGuards.guard = self.original_guard
def guard(self, container, value, index=None):
self.checks.append((id(container), value))
def test_iteration(self):
seq = [1, 2, 3]
seqid = id(seq)
it = ZopeGuards.SafeIter(seq)
self.assertEqual(list(it), seq)
self.assertEqual(self.checks, [(seqid, 1),
(seqid, 2),
(seqid, 3)])
def test_iteration_with_container(self):
seq = [1, 2, 3]
container = object()
contid = id(container)
it = ZopeGuards.SafeIter(seq, container)
self.assertEqual(list(it), seq)
self.assertEqual(self.checks, [(contid, 1),
(contid, 2),
(contid, 3)])
def test_suite():
return unittest.makeSuite(SafeIterTestCase)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" TaintedString tests.
"""
import unittest
class TestTaintedString(unittest.TestCase):
def setUp(self):
self.unquoted = '<test attr="&">'
self.quoted = '&lt;test attr=&quot;&amp;&quot;&gt;'
self.tainted = self._getClass()(self.unquoted)
def _getClass(self):
from AccessControl.tainted import TaintedString
return TaintedString
def testStr(self):
self.assertEquals(str(self.tainted), self.unquoted)
def testRepr(self):
self.assertEquals(repr(self.tainted), repr(self.quoted))
def testCmp(self):
self.assertEquals(cmp(self.tainted, self.unquoted), 0)
self.assertEquals(cmp(self.tainted, 'a'), -1)
self.assertEquals(cmp(self.tainted, '.'), 1)
def testHash(self):
hash = {}
hash[self.tainted] = self.quoted
hash[self.unquoted] = self.unquoted
self.assertEquals(hash[self.tainted], self.unquoted)
def testLen(self):
self.assertEquals(len(self.tainted), len(self.unquoted))
def testGetItem(self):
self.assert_(isinstance(self.tainted[0], self._getClass()))
self.assertEquals(self.tainted[0], '<')
self.failIf(isinstance(self.tainted[-1], self._getClass()))
self.assertEquals(self.tainted[-1], '>')
def testGetSlice(self):
self.assert_(isinstance(self.tainted[0:1], self._getClass()))
self.assertEquals(self.tainted[0:1], '<')
self.failIf(isinstance(self.tainted[1:], self._getClass()))
self.assertEquals(self.tainted[1:], self.unquoted[1:])
def testConcat(self):
self.assert_(isinstance(self.tainted + 'test', self._getClass()))
self.assertEquals(self.tainted + 'test', self.unquoted + 'test')
self.assert_(isinstance('test' + self.tainted, self._getClass()))
self.assertEquals('test' + self.tainted, 'test' + self.unquoted)
def testMultiply(self):
self.assert_(isinstance(2 * self.tainted, self._getClass()))
self.assertEquals(2 * self.tainted, 2 * self.unquoted)
self.assert_(isinstance(self.tainted * 2, self._getClass()))
self.assertEquals(self.tainted * 2, self.unquoted * 2)
def testInterpolate(self):
tainted = self._getClass()('<%s>')
self.assert_(isinstance(tainted % 'foo', self._getClass()))
self.assertEquals(tainted % 'foo', '<foo>')
tainted = self._getClass()('<%s attr="%s">')
self.assert_(isinstance(tainted % ('foo', 'bar'), self._getClass()))
self.assertEquals(tainted % ('foo', 'bar'), '<foo attr="bar">')
def testStringMethods(self):
simple = "capitalize isalpha isdigit islower isspace istitle isupper" \
" lower lstrip rstrip strip swapcase upper".split()
returnsTainted = "capitalize lower lstrip rstrip strip swapcase upper"
returnsTainted = returnsTainted.split()
unquoted = '\tThis is a test '
tainted = self._getClass()(unquoted)
for f in simple:
v = getattr(tainted, f)()
self.assertEquals(v, getattr(unquoted, f)())
if f in returnsTainted:
self.assert_(isinstance(v, self._getClass()))
else:
self.failIf(isinstance(v, self._getClass()))
optArg = "lstrip rstrip strip".split()
for f in optArg:
v = getattr(tainted, f)(" ")
self.assertEquals(v, getattr(unquoted, f)(" "))
self.assert_(isinstance(v, self._getClass()))
justify = "center ljust rjust".split()
for f in justify:
v = getattr(tainted, f)(30)
self.assertEquals(v, getattr(unquoted, f)(30))
self.assert_(isinstance(v, self._getClass()))
searches = "find index rfind rindex endswith startswith".split()
searchraises = "index rindex".split()
for f in searches:
v = getattr(tainted, f)('test')
self.assertEquals(v, getattr(unquoted, f)('test'))
if f in searchraises:
self.assertRaises(ValueError, getattr(tainted, f), 'nada')
self.assertEquals(tainted.count('test', 1, -1),
unquoted.count('test', 1, -1))
self.assertEquals(tainted.encode(), unquoted.encode())
self.assert_(isinstance(tainted.encode(), self._getClass()))
self.assertEquals(tainted.expandtabs(10),
unquoted.expandtabs(10))
self.assert_(isinstance(tainted.expandtabs(), self._getClass()))
self.assertEquals(tainted.replace('test', 'spam'),
unquoted.replace('test', 'spam'))
self.assert_(isinstance(tainted.replace('test', '<'), self._getClass()))
self.failIf(isinstance(tainted.replace('test', 'spam'),
self._getClass()))
self.assertEquals(tainted.split(), unquoted.split())
for part in self._getClass()('< < <').split():
self.assert_(isinstance(part, self._getClass()))
for part in tainted.split():
self.failIf(isinstance(part, self._getClass()))
multiline = 'test\n<tainted>'
lines = self._getClass()(multiline).split()
self.assertEquals(lines, multiline.split())
self.assert_(isinstance(lines[1], self._getClass()))
self.failIf(isinstance(lines[0], self._getClass()))
transtable = ''.join(map(chr, range(256)))
self.assertEquals(tainted.translate(transtable),
unquoted.translate(transtable))
self.assert_(isinstance(self._getClass()('<').translate(transtable),
self._getClass()))
self.failIf(isinstance(self._getClass()('<').translate(transtable, '<'),
self._getClass()))
def testQuoted(self):
self.assertEquals(self.tainted.quoted(), self.quoted)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestTaintedString))
return suite
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" Unit tests for AccessControl.User
"""
import unittest
# TODO class Test_readUserAccessFile(unittest.TestCase)
# TODO class BasicUserFoldertests(unittest.TestCase)
class UserFolderTests(unittest.TestCase):
def setUp(self):
import transaction
transaction.begin()
def tearDown(self):
import transaction
from AccessControl.SecurityManagement import noSecurityManager
noSecurityManager()
transaction.abort()
def _getTargetClass(self):
from AccessControl.userfolder import UserFolder
return UserFolder
def _makeOne(self):
uf = self._getTargetClass()()
uf._doAddUser('user1', 'secret', ['role1'], [])
return uf
def _makeBasicAuthToken(self, creds='user1:secret'):
import base64
return 'Basic %s' % base64.encodestring(creds)
def _login(self, uf, name):
from AccessControl.SecurityManagement import newSecurityManager
user = uf.getUserById(name)
user = user.__of__(uf)
newSecurityManager(None, user)
def test_class_conforms_to_IStandardUserFolder(self):
from AccessControl.interfaces import IStandardUserFolder
from zope.interface.verify import verifyClass
verifyClass(IStandardUserFolder, self._getTargetClass())
def testGetUser(self):
uf = self._makeOne()
self.failIfEqual(uf.getUser('user1'), None)
def testGetBadUser(self):
uf = self._makeOne()
self.assertEqual(uf.getUser('user2'), None)
def testGetUserById(self):
uf = self._makeOne()
self.failIfEqual(uf.getUserById('user1'), None)
def testGetBadUserById(self):
uf = self._makeOne()
self.assertEqual(uf.getUserById('user2'), None)
def testGetUsers(self):
uf = self._makeOne()
users = uf.getUsers()
self.failUnless(users)
self.assertEqual(users[0].getUserName(), 'user1')
def testGetUserNames(self):
uf = self._makeOne()
names = uf.getUserNames()
self.failUnless(names)
self.assertEqual(names[0], 'user1')
def testIdentify(self):
uf = self._makeOne()
name, password = uf.identify(self._makeBasicAuthToken())
self.assertEqual(name, 'user1')
self.assertEqual(password, 'secret')
def testGetRoles(self):
uf = self._makeOne()
user = uf.getUser('user1')
self.failUnless('role1' in user.getRoles())
def testMaxListUsers(self):
# create a folder-ish thing which contains a roleManager,
# then put an acl_users object into the folde-ish thing
from AccessControl.userfolder import BasicUserFolder
class Folderish(BasicUserFolder):
def __init__(self, size, count):
self.maxlistusers = size
self.users = []
self.acl_users = self
self.__allow_groups__ = self
for i in xrange(count):
self.users.append("Nobody")
def getUsers(self):
return self.users
def user_names(self):
return self.getUsers()
tinyFolderOver = Folderish(15, 20)
tinyFolderUnder = Folderish(15, 10)
assert tinyFolderOver.maxlistusers == 15
assert tinyFolderUnder.maxlistusers == 15
assert len(tinyFolderOver.user_names()) == 20
assert len(tinyFolderUnder.user_names()) == 10
try:
list = tinyFolderOver.get_valid_userids()
assert 0, "Did not raise overflow error"
except OverflowError:
pass
try:
list = tinyFolderUnder.get_valid_userids()
pass
except OverflowError:
assert 0, "Raised overflow error erroneously"
def test__doAddUser_with_not_yet_encrypted_passwords(self):
# See collector #1869 && #1926
from AccessControl.AuthEncoding import pw_validate
USER_ID = 'not_yet_encrypted'
PASSWORD = 'password'
uf = self._makeOne()
uf.encrypt_passwords = True
self.failIf(uf._isPasswordEncrypted(PASSWORD))
uf._doAddUser(USER_ID, PASSWORD, [], [])
user = uf.getUserById(USER_ID)
self.failUnless(uf._isPasswordEncrypted(user.__))
self.failUnless(pw_validate(user.__, PASSWORD))
def test__doAddUser_with_preencrypted_passwords(self):
# See collector #1869 && #1926
from AccessControl.AuthEncoding import pw_validate
USER_ID = 'already_encrypted'
PASSWORD = 'password'
uf = self._makeOne()
uf.encrypt_passwords = True
ENCRYPTED = uf._encryptPassword(PASSWORD)
uf._doAddUser(USER_ID, ENCRYPTED, [], [])
user = uf.getUserById(USER_ID)
self.assertEqual(user.__, ENCRYPTED)
self.failUnless(uf._isPasswordEncrypted(user.__))
self.failUnless(pw_validate(user.__, PASSWORD))
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(UserFolderTests))
return suite
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" Unit tests for AccessControl.User
"""
import unittest
class BasicUserTests(unittest.TestCase):
def _getTargetClass(self):
from AccessControl.users import BasicUser
return BasicUser
def _makeOne(self, name, password, roles, domains):
return self._getTargetClass()(name, password, roles, domains)
def _makeDerived(self, **kw):
class Derived(self._getTargetClass()):
def __init__(self, **kw):
self.name = 'name'
self.password = 'password'
self.roles = ['Manager']
self.domains = []
self.__dict__.update(kw)
return Derived(**kw)
def test_ctor_is_abstract(self):
# Subclasses must override __init__, and mustn't call the base version.
self.assertRaises(NotImplementedError,
self._makeOne, 'name', 'password', ['Manager'], [])
def test_abstract_methods(self):
# Subclasses must override these methods.
derived = self._makeDerived()
self.assertRaises(NotImplementedError, derived.getUserName)
self.assertRaises(NotImplementedError, derived.getId)
self.assertRaises(NotImplementedError, derived._getPassword)
self.assertRaises(NotImplementedError, derived.getRoles)
self.assertRaises(NotImplementedError, derived.getDomains)
# TODO: def test_getRolesInContext (w/wo local, callable, aq)
# TODO: def test_authenticate (w/wo domains)
# TODO: def test_allowed (...)
# TODO: def test_has_role (w/wo str, context)
# TODO: def test_has_permission (w/wo str)
def test___len__(self):
derived = self._makeDerived()
self.assertEqual(len(derived), 1)
def test___str__(self):
derived = self._makeDerived(getUserName=lambda: 'phred')
self.assertEqual(str(derived), 'phred')
def test___repr__(self):
derived = self._makeDerived(getUserName=lambda: 'phred')
self.assertEqual(repr(derived), "<Derived 'phred'>")
class SimpleUserTests(unittest.TestCase):
def _getTargetClass(self):
from AccessControl.users import SimpleUser
return SimpleUser
def _makeOne(self, name='admin', password='123', roles=None, domains=None):
if roles is None:
roles = ['Manager']
if domains is None:
domains = []
return self._getTargetClass()(name, password, roles, domains)
def test_overrides(self):
simple = self._makeOne()
self.assertEqual(simple.getUserName(), 'admin')
self.assertEqual(simple.getId(), 'admin')
self.assertEqual(simple._getPassword(), '123')
self.assertEqual(simple.getDomains(), ())
def test_getRoles_anonymous(self):
simple = self._makeOne('Anonymous User', roles=())
self.assertEqual(simple.getRoles(), ())
def test_getRoles_non_anonymous(self):
simple = self._makeOne('phred', roles=())
self.assertEqual(simple.getRoles(), ('Authenticated',))
def test___repr__(self):
special = self._makeOne()
self.assertEqual(repr(special), "<SimpleUser 'admin'>")
class SpecialUserTests(unittest.TestCase):
def _getTargetClass(self):
from AccessControl.users import SpecialUser
return SpecialUser
def _makeOne(self, name='admin', password='123', roles=None, domains=None):
if roles is None:
roles = ['Manager']
if domains is None:
domains = []
return self._getTargetClass()(name, password, roles, domains)
def test_overrides(self):
special = self._makeOne()
self.assertEqual(special.getUserName(), 'admin')
self.assertEqual(special.getId(), None)
self.assertEqual(special._getPassword(), '123')
self.assertEqual(special.getDomains(), ())
def test___repr__(self):
special = self._makeOne()
self.assertEqual(repr(special), "<SpecialUser 'admin'>")
class UnrestrictedUserTests(unittest.TestCase):
def _getTargetClass(self):
from AccessControl.users import UnrestrictedUser
return UnrestrictedUser
def _makeOne(self, name='admin', password='123', roles=None, domains=None):
if roles is None:
roles = ['Manager']
if domains is None:
domains = []
return self._getTargetClass()(name, password, roles, domains)
def test_allowed__what_not_even_god_should_do(self):
from AccessControl.PermissionRole import _what_not_even_god_should_do
unrestricted = self._makeOne()
self.failIf(unrestricted.allowed(self, _what_not_even_god_should_do))
def test_allowed_empty(self):
unrestricted = self._makeOne()
self.failUnless(unrestricted.allowed(self, ()))
def test_allowed_other(self):
unrestricted = self._makeOne()
self.failUnless(unrestricted.allowed(self, ('Manager',)))
def test_has_role_empty_no_object(self):
unrestricted = self._makeOne()
self.failUnless(unrestricted.has_role(()))
def test_has_role_empty_w_object(self):
unrestricted = self._makeOne()
self.failUnless(unrestricted.has_role((), self))
def test_has_role_other_no_object(self):
unrestricted = self._makeOne()
self.failUnless(unrestricted.has_role(('Manager',)))
def test_has_role_other_w_object(self):
unrestricted = self._makeOne()
self.failUnless(unrestricted.has_role(('Manager',), self))
def test___repr__(self):
unrestricted = self._makeOne()
self.assertEqual(repr(unrestricted),
"<UnrestrictedUser 'admin'>")
class NullUnrestrictedUserTests(unittest.TestCase):
def _getTargetClass(self):
from AccessControl.users import NullUnrestrictedUser
return NullUnrestrictedUser
def _makeOne(self):
return self._getTargetClass()()
def test_overrides(self):
simple = self._makeOne()
self.assertEqual(simple.getUserName(), (None, None))
self.assertEqual(simple.getId(), None)
self.assertEqual(simple._getPassword(), (None, None))
self.assertEqual(simple.getRoles(), ())
self.assertEqual(simple.getDomains(), ())
def test_getRolesInContext(self):
null = self._makeOne()
self.assertEqual(null.getRolesInContext(self), ())
def test_authenticate(self):
null = self._makeOne()
self.failIf(null.authenticate('password', {}))
def test_allowed(self):
null = self._makeOne()
self.failIf(null.allowed(self, ()))
def test_has_role(self):
null = self._makeOne()
self.failIf(null.has_role('Authenticated'))
def test_has_role_w_object(self):
null = self._makeOne()
self.failIf(null.has_role('Authenticated', self))
def test_has_permission(self):
null = self._makeOne()
self.failIf(null.has_permission('View', self))
def test___repr__(self):
null = self._makeOne()
self.assertEqual(repr(null), "<NullUnrestrictedUser (None, None)>")
def test___str__(self):
# See https://bugs.launchpad.net/zope2/+bug/142563
null = self._makeOne()
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
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Access control exceptions
"""
import zExceptions
class Unauthorized(zExceptions.Unauthorized):
def getValueName(self):
v=self.value
n=getattr(v, 'getId', v)
if n is v: n=getattr(v, 'id', v)
if n is v: n=getattr(v, '__name__', v)
if n is not v:
if callable(n):
try: n = n()
except TypeError: pass
return n
c = getattr(v, '__class__', type(v))
c = getattr(c, '__name__', 'object')
return "a particular %s" % c
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""User folders.
"""
from base64 import decodestring
from Acquisition import aq_base
from Acquisition import aq_parent
from Acquisition import Implicit
from Persistence import Persistent
from Persistence import PersistentMapping
from zExceptions import BadRequest
from zExceptions import Unauthorized
from zope.interface import implements
from AccessControl import AuthEncoding
from AccessControl import ClassSecurityInfo
from AccessControl.class_init import InitializeClass
from AccessControl.interfaces import IStandardUserFolder
from AccessControl.Permissions import manage_users as ManageUsers
from AccessControl.rolemanager import DEFAULTMAXLISTUSERS
from AccessControl.rolemanager import RoleManager
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager
from AccessControl.users import User
from AccessControl.users import _remote_user_mode
from AccessControl.users import emergency_user
from AccessControl.users import nobody
from AccessControl.users import addr_match
from AccessControl.users import host_match
from AccessControl.ZopeSecurityPolicy import _noroles
class BasicUserFolder(Implicit, Persistent, RoleManager):
"""Base class for UserFolder-like objects"""
meta_type = 'User Folder'
id = 'acl_users'
title ='User Folder'
isPrincipiaFolderish = 1
isAUserFolder = 1
maxlistusers = DEFAULTMAXLISTUSERS
encrypt_passwords = 1
_remote_user_mode = _remote_user_mode
_domain_auth_mode = 0
_emergency_user = emergency_user
_nobody = nobody
security = ClassSecurityInfo()
security.declareProtected(ManageUsers, 'getUserNames')
def getUserNames(self):
"""Return a list of usernames"""
raise NotImplementedError
security.declareProtected(ManageUsers, 'getUsers')
def getUsers(self):
"""Return a list of user objects"""
raise NotImplementedError
security.declareProtected(ManageUsers, 'getUser')
def getUser(self, name):
"""Return the named user object or None"""
raise NotImplementedError
security.declareProtected(ManageUsers, 'getUserById')
def getUserById(self, id, default=None):
"""Return the user corresponding to the given id.
"""
# The connection between getting by ID and by name is not a strong
# one
user = self.getUser(id)
if user is None:
return default
return user
def _doAddUser(self, name, password, roles, domains, **kw):
"""Create a new user. This should be implemented by subclasses to
do the actual adding of a user. The 'password' will be the
original input password, unencrypted. The implementation of this
method is responsible for performing any needed encryption."""
raise NotImplementedError
def _doChangeUser(self, name, password, roles, domains, **kw):
"""Modify an existing user. This should be implemented by subclasses
to make the actual changes to a user. The 'password' will be the
original input password, unencrypted. The implementation of this
method is responsible for performing any needed encryption."""
raise NotImplementedError
def _doDelUsers(self, names):
"""Delete one or more users. This should be implemented by subclasses
to do the actual deleting of users."""
raise NotImplementedError
def identify(self, auth):
if auth and auth.lower().startswith('basic '):
try:
name, password = tuple(decodestring(
auth.split(' ')[-1]).split(':', 1))
except:
raise BadRequest('Invalid authentication token')
return name, password
else:
return None, None
def authenticate(self, name, password, request):
emergency = self._emergency_user
if name is None:
return None
if emergency and name==emergency.getUserName():
user = emergency
else:
user = self.getUser(name)
if user is not None and user.authenticate(password, request):
return user
else:
return None
def authorize(self, user, accessed, container, name, value, roles):
user = getattr(user, 'aq_base', user).__of__(self)
newSecurityManager(None, user)
security = getSecurityManager()
try:
try:
# This is evil: we cannot pass _noroles directly because
# it is a special marker, and that special marker is not
# the same between the C and Python policy implementations.
# We __really__ need to stop using this marker pattern!
if roles is _noroles:
if security.validate(accessed, container, name, value):
return 1
else:
if security.validate(accessed, container, name, value,
roles):
return 1
except:
noSecurityManager()
raise
except Unauthorized:
pass
return 0
def validate(self, request, auth='', roles=_noroles):
"""
this method performs identification, authentication, and
authorization
v is the object (value) we're validating access to
n is the name used to access the object
a is the object the object was accessed through
c is the physical container of the object
We allow the publishing machinery to defer to higher-level user
folders or to raise an unauthorized by returning None from this
method.
"""
v = request['PUBLISHED'] # the published object
a, c, n, v = self._getobcontext(v, request)
# we need to continue to support this silly mode
# where if there is no auth info, but if a user in our
# database has no password and he has domain restrictions,
# return him as the authorized user.
if not auth:
if self._domain_auth_mode:
for user in self.getUsers():
if user.getDomains():
if self.authenticate(user.getUserName(), '', request):
if self.authorize(user, a, c, n, v, roles):
return user.__of__(self)
name, password = self.identify(auth)
user = self.authenticate(name, password, request)
# user will be None if we can't authenticate him or if we can't find
# his username in this user database.
emergency = self._emergency_user
if emergency and user is emergency:
if self._isTop():
# we do not need to authorize the emergency user against the
# published object.
return emergency.__of__(self)
else:
# we're not the top-level user folder
return None
elif user is None:
# either we didn't find the username, or the user's password
# was incorrect. try to authorize and return the anonymous user.
if (self._isTop() and
self.authorize(self._nobody, a, c, n, v, roles)):
return self._nobody.__of__(self)
else:
# anonymous can't authorize or we're not top-level user folder
return None
else:
# We found a user, his password was correct, and the user
# wasn't the emergency user. We need to authorize the user
# against the published object.
if self.authorize(user, a, c, n, v, roles):
return user.__of__(self)
# That didn't work. Try to authorize the anonymous user.
elif (self._isTop() and
self.authorize(self._nobody, a, c, n, v, roles)):
return self._nobody.__of__(self)
else:
# we can't authorize the user, and we either can't authorize
# nobody against the published object or we're not top-level
return None
if _remote_user_mode:
def validate(self, request, auth='', roles=_noroles):
v = request['PUBLISHED']
a, c, n, v = self._getobcontext(v, request)
name = request.environ.get('REMOTE_USER', None)
if name is None:
if self._domain_auth_mode:
for user in self.getUsers():
if user.getDomains():
if self.authenticate(user.getUserName(),
'', request):
if self.authorize(user, a, c, n, v, roles):
return user.__of__(self)
user = self.getUser(name)
# user will be None if we can't find his username in this user
# database.
emergency = self._emergency_user
if emergency and name==emergency.getUserName():
if self._isTop():
# we do not need to authorize the emergency user against
#the published object.
return emergency.__of__(self)
else:
# we're not the top-level user folder
return None
elif user is None:
# we didn't find the username in this database
# try to authorize and return the anonymous user.
if self._isTop() and self.authorize(self._nobody,
a, c, n, v, roles):
return self._nobody.__of__(self)
else:
# anonymous can't authorize or we're not top-level user
# folder
return None
else:
# We found a user and the user wasn't the emergency user.
# We need to authorize the user against the published object.
if self.authorize(user, a, c, n, v, roles):
return user.__of__(self)
# That didn't work. Try to authorize the anonymous user.
elif self._isTop() and self.authorize(
self._nobody, a, c, n, v, roles):
return self._nobody.__of__(self)
else:
# we can't authorize the user, and we either can't
# authorize nobody against the published object or
# we're not top-level
return None
def _getobcontext(self, v, request):
"""
v is the object (value) we're validating access to
n is the name used to access the object
a is the object the object was accessed through
c is the physical container of the object
"""
if len(request.steps) == 0: # someone deleted root index_html
request.RESPONSE.notFoundError('no default view (root default view'
' was probably deleted)')
n = request.steps[-1]
# default to accessed and container as v.__parent__
a = c = request['PARENTS'][0]
# try to find actual container
inner = getattr(v, 'aq_inner', v)
innerparent = getattr(inner, '__parent__', None)
if innerparent is not None:
# this is not a method, we needn't treat it specially
c = innerparent
elif hasattr(v, 'im_self'):
# this is a method, we need to treat it specially
c = v.im_self
c = getattr(v, 'aq_inner', v)
request_container = getattr(request['PARENTS'][-1], '__parent__', [])
# if pub's __parent__ or container is the request container, it
# means pub was accessed from the root
if a is request_container:
a = request['PARENTS'][-1]
if c is request_container:
c = request['PARENTS'][-1]
return a, c, n, v
def _isTop(self):
try:
parent = aq_base(aq_parent(self))
return parent.isTopLevelPrincipiaApplicationObject
except:
return 0
def __len__(self):
return 1
def _isPasswordEncrypted(self, pw):
return AuthEncoding.is_encrypted(pw)
def _encryptPassword(self, pw):
return AuthEncoding.pw_encrypt(pw, 'SSHA')
def domainSpecValidate(self, spec):
for ob in spec:
am = addr_match(ob)
hm = host_match(ob)
if am is None and hm is None:
return 0
return 1
security.declareProtected(ManageUsers, 'user_names')
def user_names(self):
return self.getUserNames()
def __creatable_by_emergency_user__(self):
return 1
# Domain authentication support. This is a good candidate to
# become deprecated in future Zope versions.
security.declareProtected(ManageUsers, 'setDomainAuthenticationMode')
def setDomainAuthenticationMode(self, domain_auth_mode):
"""Set the domain-based authentication mode. By default, this
mode is off due to the high overhead of the operation that
is incurred for all anonymous accesses. If you have the
'Manage Users' permission, you can call this method via
the web, passing a boolean value for domain_auth_mode to
turn this behavior on or off."""
v = self._domain_auth_mode = domain_auth_mode and 1 or 0
return 'Domain authentication mode set to %d' % v
def domainAuthModeEnabled(self):
""" returns true if domain auth mode is set to true"""
return getattr(self, '_domain_auth_mode', None)
class UserFolder(BasicUserFolder):
"""Standard UserFolder object
A UserFolder holds User objects which contain information
about users including name, password domain, and roles.
UserFolders function chiefly to control access by authenticating
users and binding them to a collection of roles."""
implements(IStandardUserFolder)
meta_type = 'User Folder'
id = 'acl_users'
title = 'User Folder'
def __init__(self):
self.data=PersistentMapping()
def getUserNames(self):
"""Return a list of usernames"""
names=self.data.keys()
names.sort()
return names
def getUsers(self):
"""Return a list of user objects"""
data=self.data
names=data.keys()
names.sort()
return [data[n] for n in names]
def getUser(self, name):
"""Return the named user object or None"""
return self.data.get(name, None)
def hasUsers(self):
""" This is not a formal API method: it is used only to provide
a way for the quickstart page to determine if the default user
folder contains any users to provide instructions on how to
add a user for newbies. Using getUserNames or getUsers would have
posed a denial of service risk."""
return not not len(self.data)
def _doAddUser(self, name, password, roles, domains, **kw):
"""Create a new user"""
if password is not None and self.encrypt_passwords \
and not self._isPasswordEncrypted(password):
password = self._encryptPassword(password)
self.data[name] = User(name, password, roles, domains)
def _doChangeUser(self, name, password, roles, domains, **kw):
user=self.data[name]
if password is not None:
if (self.encrypt_passwords
and not self._isPasswordEncrypted(password)):
password = self._encryptPassword(password)
user.__ = password
user.roles = roles
user.domains = domains
def _doDelUsers(self, names):
for name in names:
del self.data[name]
InitializeClass(UserFolder)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Access control package.
"""
import os
import re
import socket
from Acquisition import aq_parent
from Acquisition import aq_inContextOf
from Acquisition import Implicit
from Persistence import Persistent
from AccessControl import AuthEncoding
from AccessControl import SpecialUsers
from .PermissionRole import _what_not_even_god_should_do
from .PermissionRole import rolesForPermissionOn
_marker=[]
class BasicUser(Implicit):
"""Base class for all User objects"""
# ----------------------------
# Public User object interface
# ----------------------------
# Maybe allow access to unprotected attributes. Note that this is
# temporary to avoid exposing information but without breaking
# everyone's current code. In the future the security will be
# clamped down and permission-protected here. Because there are a
# fair number of user object types out there, this method denies
# access to names that are private parts of the standard User
# interface or implementation only. The other approach (only
# allowing access to public names in the User interface) would
# probably break a lot of other User implementations with extended
# functionality that we cant anticipate from the base scaffolding.
def __allow_access_to_unprotected_subobjects__(self, name, value=None):
deny_names=('name', '__', 'roles', 'domains', '_getPassword',
'authenticate', '_shared_roles')
if name in deny_names:
return 0
return 1
def __init__(self, name, password, roles, domains):
raise NotImplementedError
def getUserName(self):
"""Return the username of a user"""
raise NotImplementedError
def getId(self):
"""Get the ID of the user. The ID can be used, at least from
Python, to get the user from the user's
UserDatabase"""
return self.getUserName()
def _getPassword(self):
"""Return the password of the user."""
raise NotImplementedError
def getRoles(self):
"""Return the list of roles assigned to a user."""
raise NotImplementedError
def getRolesInContext(self, object):
"""Return the list of roles assigned to the user,
including local roles assigned in context of
the passed in object."""
userid=self.getId()
roles=self.getRoles()
local={}
object=getattr(object, 'aq_inner', object)
while 1:
local_roles = getattr(object, '__ac_local_roles__', None)
if local_roles:
if callable(local_roles):
local_roles=local_roles()
dict=local_roles or {}
for r in dict.get(userid, []):
local[r]=1
inner = getattr(object, 'aq_inner', object)
parent = getattr(inner, '__parent__', None)
if parent is not None:
object = parent
continue
if hasattr(object, 'im_self'):
object=object.im_self
object=getattr(object, 'aq_inner', object)
continue
break
roles=list(roles) + local.keys()
return roles
def getDomains(self):
"""Return the list of domain restrictions for a user"""
raise NotImplementedError
# ------------------------------
# Internal User object interface
# ------------------------------
def authenticate(self, password, request):
passwrd=self._getPassword()
result = AuthEncoding.pw_validate(passwrd, password)
domains=self.getDomains()
if domains:
return result and domainSpecMatch(domains, request)
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):
# Check that 'object' exists in the acquisition context of
# the parent of the acl_users object containing this user,
# to prevent "stealing" access through acquisition tricks.
# Return true if in context, false if not or if context
# cannot be determined (object is not wrapped).
parent = getattr(self, '__parent__', None)
context = getattr(parent, '__parent__', None)
if context is not None:
if object is None:
return 1
if hasattr(object, 'im_self'):
# This is a method. Grab its self.
object = object.im_self
return aq_inContextOf(object, context, 1)
# This is lame, but required to keep existing behavior.
return 1
def allowed(self, object, object_roles=None):
"""Check whether the user has access to object. The user must
have one of the roles in object_roles to allow access."""
if object_roles is _what_not_even_god_should_do:
return 0
# Short-circuit the common case of anonymous access.
if object_roles is None or 'Anonymous' in object_roles:
return 1
# Provide short-cut access if object is protected by 'Authenticated'
# role and user is not nobody
if 'Authenticated' in object_roles and (
self.getUserName() != 'Anonymous User'):
if self._check_context(object):
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
# the user, then with local roles only if necessary. We
# want to avoid as much overhead as possible.
user_roles = self.getRoles()
for role in object_roles:
if role in user_roles:
if self._check_context(object):
return 1
return None
# Still have not found a match, so check local roles. We do
# this manually rather than call getRolesInContext so that
# we can incur only the overhead required to find a match.
inner_obj = getattr(object, 'aq_inner', object)
userid = self.getId()
while 1:
local_roles = getattr(inner_obj, '__ac_local_roles__', None)
if local_roles:
if callable(local_roles):
local_roles = local_roles()
dict = local_roles or {}
local_roles = dict.get(userid, [])
for role in object_roles:
if role in local_roles:
if self._check_context(object):
return 1
return 0
inner = getattr(inner_obj, 'aq_inner', inner_obj)
parent = getattr(inner, '__parent__', None)
if parent is not None:
inner_obj = parent
continue
if hasattr(inner_obj, 'im_self'):
inner_obj=inner_obj.im_self
inner_obj=getattr(inner_obj, 'aq_inner', inner_obj)
continue
break
return None
domains=[]
def has_role(self, roles, object=None):
"""Check to see if a user has a given role or roles."""
if isinstance(roles, str):
roles=[roles]
if object is not None:
user_roles = self.getRolesInContext(object)
else:
# Global roles only...
user_roles=self.getRoles()
for role in roles:
if role in user_roles:
return 1
return 0
def has_permission(self, permission, object):
"""Check to see if a user has a given permission on an object."""
roles=rolesForPermissionOn(permission, object)
if isinstance(roles, str):
roles=[roles]
return self.allowed(object, roles)
def __len__(self):
return 1
def __str__(self):
return self.getUserName()
def __repr__(self):
return '<%s %r>' % (self.__class__.__name__, self.getUserName())
class SimpleUser(BasicUser):
"""A very simple user implementation
that doesn't make a database commitment"""
def __init__(self, name, password, roles, domains):
self.name = name
self.__ = password
self.roles = roles
self.domains = domains
def getUserName(self):
"""Return the username of a user"""
return self.name
def _getPassword(self):
"""Return the password of the user."""
return self.__
def getRoles(self):
"""Return the list of roles assigned to a user."""
if self.name == 'Anonymous User':
return tuple(self.roles)
else:
return tuple(self.roles) + ('Authenticated', )
def getDomains(self):
"""Return the list of domain restrictions for a user"""
return tuple(self.domains)
class SpecialUser(SimpleUser):
"""Class for special users, like emergency user and nobody"""
def getId(self):
pass
class User(SimpleUser, Persistent):
"""Standard User object"""
class UnrestrictedUser(SpecialUser):
"""User that passes all security checks. Note, however, that modules
like Owner.py can still impose restrictions.
"""
def allowed(self, parent, roles=None):
return roles is not _what_not_even_god_should_do
def has_role(self, roles, object=None):
return 1
def has_permission(self, permission, object):
return 1
class NullUnrestrictedUser(SpecialUser):
"""User created if no emergency user exists. It is only around to
satisfy third party userfolder implementations that may
expect the emergency user to exist and to be able to call certain
methods on it (in other words, backward compatibility).
Note that when no emergency user is installed, this object that
exists in its place is more of an anti-superuser since you cannot
login as this user and it has no priveleges at all."""
__null_user__=1
def __init__(self):
pass
def getUserName(self):
# return an unspellable username
return (None, None)
_getPassword=getUserName
def getRoles(self):
return ()
getDomains=getRoles
def getRolesInContext(self, object):
return ()
def authenticate(self, password, request):
return 0
def allowed(self, parent, roles=None):
return 0
def has_role(self, roles, object=None):
return 0
def has_permission(self, permission, object):
return 0
def __str__(self):
# See https://bugs.launchpad.net/zope2/+bug/142563
return repr(self)
def readUserAccessFile(filename):
'''Reads an access file from the instance home.
Returns name, password, domains, remote_user_mode.
'''
environ = os.environ
instancehome = environ.get('INSTANCE_HOME', None)
if not instancehome:
return None
try:
f = open(os.path.join(instancehome, filename), 'r')
line = f.readline()
f.close()
except IOError:
return None
if line:
data = line.strip().split(':')
remote_user_mode = not data[1]
try:
ds = data[2].split(' ')
except:
ds = []
return data[0], data[1], ds, remote_user_mode
else:
return None
# Create emergency user.
_remote_user_mode = 0
info = readUserAccessFile('access')
if info:
_remote_user_mode = info[3]
emergency_user = UnrestrictedUser(info[0], info[1], ('manage', ), info[2])
else:
emergency_user = NullUnrestrictedUser()
del info
nobody = SpecialUser('Anonymous User', '', ('Anonymous', ), [])
system = UnrestrictedUser('System Processes', '', ('manage', ), [])
# stuff these in a handier place for importing
SpecialUsers.nobody = nobody
SpecialUsers.system = system
SpecialUsers.emergency_user = emergency_user
# Note: use of the 'super' name is deprecated.
SpecialUsers.super = emergency_user
def rolejoin(roles, other):
dict = {}
for role in roles:
dict[role] = 1
for role in other:
dict[role] = 1
roles = dict.keys()
roles.sort()
return roles
addr_match=re.compile(r'((\d{1,3}\.){1,3}\*)|((\d{1,3}\.){3}\d{1,3})').match
host_match=re.compile(r'(([\_0-9a-zA-Z\-]*\.)*[0-9a-zA-Z\-]*)').match
def domainSpecMatch(spec, request):
# Fast exit for the match-all case
if len(spec) == 1 and spec[0] == '*':
return 1
host = request.get('REMOTE_HOST', '')
addr = request.getClientAddr()
if not host and not addr:
return 0
if not host:
try:
host=socket.gethostbyaddr(addr)[0]
except:
pass
if not addr:
try:
addr=socket.gethostbyname(host)
except:
pass
_host = host.split('.')
_addr = addr.split('.')
_hlen = len(_host)
for ob in spec:
sz = len(ob)
_ob = ob.split('.')
_sz = len(_ob)
mo = addr_match(ob)
if mo is not None:
if mo.end(0)==sz:
fail=0
for i in range(_sz):
a = _addr[i]
o = _ob[i]
if (o != a) and (o != '*'):
fail = 1
break
if fail:
continue
return 1
mo = host_match(ob)
if mo is not None:
if mo.end(0)==sz:
if _hlen < _sz:
continue
elif _hlen > _sz:
_item = _host[-_sz:]
else:
_item = _host
fail = 0
for i in range(_sz):
h = _item[i]
o = _ob[i]
if (o != h) and (o != '*'):
fail = 1
break
if fail:
continue
return 1
return 0
def absattr(attr):
if callable(attr):
return attr()
return attr
def reqattr(request, attr):
try:
return request[attr]
except:
return None
......@@ -4,6 +4,7 @@ versions = versions
[versions]
# Zope2-specific
Zope2 =
AccessControl = 2.13.0
Acquisition = 2.13.3
DateTime = 2.12.2
ExtensionClass = 2.13.2
......
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