[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Security - ISecurityManager.py:1.1.2.6.6.1 ISecurityPolicy.py:1.1.2.3.6.1 SecurityManagement.py:1.1.2.5.6.1 SecurityManager.py:1.1.2.8.6.1 SimpleSecurityPolicies.py:1.1.2.4.6.1 ZopeSecurityPolicy.py:1.1.2.24.4.1 protectClass.py:1.1.2.12.6.1 publicClass.py:1.1.2.8.6.1 security.zcml:1.1.2.4.2.1
Jim Fulton
jim@zope.com
Fri, 26 Apr 2002 14:23:18 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/App/Security
In directory cvs.zope.org:/tmp/cvs-serv26237/lib/python/Zope/App/Security
Modified Files:
Tag: SecurityProxy-branch
ISecurityManager.py ISecurityPolicy.py SecurityManagement.py
SecurityManager.py SimpleSecurityPolicies.py
ZopeSecurityPolicy.py protectClass.py publicClass.py
security.zcml
Log Message:
Changed security code to use security proxies and name-based
security. This has pretty far-reaching implications:
- You now protect names/operations, *not* values. This means it's as
easy yo protect data attributes that have simple values as it is to
protect methods.
- There is no longer a __permissions__ attribute. :)
- There is no longer a validate method in either security managers or
policies.
- No more need to have a special compiler for restricted code.
In exchange, lots of objects are proxies and code sometimes needs to
be prepared to remove proxies.
In addition:
- Basic objects (None, strings, numbers, etc.) are not wrapped in
context wrappers.
- There is a test that fails unless Python 2.3 is used.
=== Zope3/lib/python/Zope/App/Security/ISecurityManager.py 1.1.2.6 => 1.1.2.6.6.1 ===
executable context and policies.
"""
+
def getPrincipal():
"""
Return the authenticated principal.
@@ -27,25 +28,6 @@
REQUEST['AUTHENTICATED_USER']
but is a bit cleaner, especially if 'REQUEST' isn't handy.
- """
-
- def validate( name, value ):
- """
- Validate access, raising Unauthorized if not allowed..
-
- Arguments:
-
- name -- The attribute name used to access the value
-
- value -- The value retrieved though the access.
- """
-
- def validateValue( value ):
- """
- Validate access, raising Unauthorized if not allowed..
-
- This is a shortcut for the common case of
- validating a value without providing access information.
"""
def checkPermission( permission, object ):
=== Zope3/lib/python/Zope/App/Security/ISecurityPolicy.py 1.1.2.3 => 1.1.2.3.6.1 ===
class ISecurityPolicy( Interface ):
-
- def validate( name
- , value
- , context
- ):
- """
- Validate access, raising Unauthorized if not allowed.
-
- Arguments:
-
- name -- The name used to access the value
-
- value -- The value returned by the access
-
- context -- must implement ISecurityContext; access to information
- such as the context stack and AUTHENTICATED_USER.
- """
def checkPermission( permission
, object
=== Zope3/lib/python/Zope/App/Security/SecurityManagement.py 1.1.2.5 => 1.1.2.5.6.1 ===
_managers={}
+from Zope.Testing.CleanUp import addCleanUp
+addCleanUp(_managers.clear)
+
+
#
# ISecurityManagementSetup implementation
#
=== Zope3/lib/python/Zope/App/Security/SecurityManager.py 1.1.2.8 => 1.1.2.8.6.1 ===
_defaultPolicy = ParanoidSecurityPolicy()
+def _clear():
+ global _defaultPolicy
+ _defaultPolicy = ParanoidSecurityPolicy()
+
+from Zope.Testing.CleanUp import addCleanUp
+addCleanUp(_clear)
+
+
def setSecurityPolicy( aSecurityPolicy ):
"""
Set the system default security policy.
@@ -69,31 +77,6 @@
but is a bit cleaner, especially if 'REQUEST' isn't handy.
"""
return self._context.user
-
- def validate( self, name, value ):
- """
- Validate access.
-
- Arguments:
-
- name -- The attribute name used to access the value
-
- value -- The value retrieved though the access.
-
- A boolean value is returned indicating whether the value is
- accessible. An Unauthorized exception may be raised in some
- cases.
- """
- return self._getPolicy().validate( name, value, self._context )
-
- def validateValue( self, value ):
- """
- Validate access. This is a shortcut for the common case of
- validating a value without providing access information.
-
- Raise Unauthorized if access not allowed.
- """
- return self._getPolicy().validate( None, value, self._context )
def checkPermission( self, permission, object ):
"""
=== Zope3/lib/python/Zope/App/Security/SimpleSecurityPolicies.py 1.1.2.4 => 1.1.2.4.6.1 ===
"""
__implements__ = ISecurityPolicy
-
- def validate( self, name, value, context ):
- raise Unauthorized(name=name, value=value)
def checkPermission( sel, permission, object, context ):
+ if (context.user is None # no user
+ and not context.stack # no untrusted code
+ ):
+ return 1 # Nobody not to trust!
+
return 0
class PermissiveSecurityPolicy:
@@ -33,30 +35,7 @@
Allow all access
"""
__implements__ = ISecurityPolicy
-
- def validate( self, name, value, context ):
- pass
def checkPermission( self, permission, object, context ):
- return 1
-
-class NameBasedSecurityPolicy:
- """ Allow access based on traversed name.
-
- The constructor takes a callable object, which is passed the name of the
- item accessed, or None. This method should either pass or raise
- Zope.Exceptions.Unauthorized.
-
- """
-
- __implements__ = ISecurityPolicy
-
- def __init__(self, nameChecker):
- self._nameChecker = nameChecker
-
- def validate(self, name, value, context):
- self._nameChecker(name)
-
- def checkPermission(self, permission, object, context):
return 1
=== Zope3/lib/python/Zope/App/Security/ZopeSecurityPolicy.py 1.1.2.24 => 1.1.2.24.4.1 ===
from Zope.ComponentArchitecture import getAdapter
-from Zope.ContextWrapper.ContainmentIterator import ContainmentIterator
-
+from Zope.Proxy.ContextWrapper import ContainmentIterator
from Zope.Exceptions import Unauthorized, Forbidden
-
from Zope.App.Security.IRolePermissionManager import IRolePermissionManager
from Zope.App.Security.IPrincipalPermissionManager \
import IPrincipalPermissionManager
@@ -39,9 +37,6 @@
from types import StringType, StringTypes, TupleType, ListType, IntType, MethodType, NoneType
-# XXX: hack alert
-from Zope.ContextWrapper import getbaseobject
-
getPermissionsForPrincipal = \
principalPermissionManager.getPermissionsForPrincipal
getPermissionsForRole = rolePermissionManager.getPermissionsForRole
@@ -75,48 +70,6 @@
self._ownerous=ownerous
self._authenticated=authenticated
- #
- # ISecurityPolicy implementation.
- #
- def validate( self
- , name
- , value
- , context
- ):
-
- try: permission=value.__permission__
- except AttributeError:
- # XXX: allow some simple types to get ZMI working
- # is this the right thing to do?
- # Also, respect the attribute
- # __allow_access_to_unprotected_subobjects__
- # as used in TALES iterators and other places
- # Also, respect __aatus__ for accessing methods of objects
- # (un)protected by it.
- # This is still a hack, and still incomplete, and just here
- # to get the ZMI working.
-
-
- unwrapped_value = getbaseobject(value)
- if (isinstance(unwrapped_value, (ListType, TupleType, StringTypes, IntType, NoneType))
- or
- getattr(value,'__allow_access_to_unprotected_subobjects__',0)):
- permission = 'Zope.Public'
- elif (isinstance(unwrapped_value, MethodType) and
- getattr(value.im_self,
- '__allow_access_to_unprotected_subobjects__',
- 0)):
- permission = 'Zope.Public'
- else:
- raise Forbidden(name, value, 'No permission set')
-
- if permission == 'Zope.Public': # XXX need unit test for this
- return
-
- if self.checkPermission(permission, value, context):
- return
- raise Unauthorized(permission, name, value)
-
def checkPermission( self, permission, object, context ):
# XXX We aren't really handling multiple principals yet
@@ -191,51 +144,6 @@
return 1 # Allow on global role
return 0 # Deny by default
-
-# for p in principals.keys():
-# if permission in getPermissionsForPrincipal(p):
-# del principals[p]
-# else:
-# for r in getRolesForPrincipal(p):
-# if permission in getPermissionsForRole(r):
-# del principals[p]
-# if r in roles:
-# return 1
-# return not principals
-
- #
- # Helper methods
- #
- def _allowName( self, name ):
- """
- Is 'name' ever allowed to be retrieved under this policy?
- """
- return name and isinstance(name, StringType) and name.strip()
-
- def _findPermission( self, value ):
- """
- Find the permission which guards the accessed object.
- """
- return getattr( value, '__permission__', None )
-
- def _listRolesFor( self, permission, object ):
- """
- Crawl the context of 'object' and return an accumulated
- list of all roles which have 'permission'.
-
- Note that we don't (yet) use 'object' to search for
- placeful permission-role bindings.
- """
- role_set = {}
-
- # Add "global" roles for permission here
- for role in getRolesForPermission( permission ):
- role_set[ role ] = 1
-
- roles = role_set.keys()
- roles.sort()
-
- return tuple( roles )
zopeSecurityPolicy=ZopeSecurityPolicy()
=== Zope3/lib/python/Zope/App/Security/protectClass.py 1.1.2.12 => 1.1.2.12.6.1 ===
#
##############################################################################
-"""Create the protection declarations object.
-
-Protection declarations are assert as part of the configuration process to map
-permissions to objects, ie to specific classes, class instances, and methods.
-\(Method permissions apply to both the class and class instance manifestations
-of the methods.)
-
-When the declarations are expressed as a simple (ie, empty) tag, they are
-applied to both the class and the instances of the class. When the tags have
-subtags, then the instances are not inherently affected - the subtag directive
-"instances" can then be used. [XXX this needs to be fleshed out.]
-
-Invalid protection declarations raise ProtectionDeclarationException
-instances."""
+"""Make assertions about permissions needed to access class instances attributes
+"""
from Interface.Method import Method
from Exceptions import UndefinedPermissionError
@@ -33,25 +21,25 @@
from Zope.Configuration.ConfigurationDirectiveInterfaces \
import INonEmptyDirective
+from Zope.Security.Checker import defineChecker, getCheckerForInstancesOf
+from Zope.Security.Checker import Checker, CheckerPublic
+
class ProtectionDeclarationException(Exception):
"""Security-protection-specific exceptions."""
pass
-
class protectClass:
__class_implements__ = INonEmptyDirective
def __init__(self, _context, name, permission_id=None, interface=None,
- methods=None):
+ names=None):
self.__class = _context.resolve(name)
self.__name = name
self.__permission_id = permission_id
self.__context = _context
- self.__r = self.protect(_context, permission_id, interface, methods)
- # So subsequent simple-declaration-style self() calls process instances
- self.__empty = 1
+ self.__r = self.protect(_context, permission_id, interface, names)
# ._getPermission() is handy for subclassing with different permission
# policy, eg publicClass.
@@ -68,12 +56,12 @@
return permission_id
def protect(self, _context, permission_id=None, interface=None,
- methods=None):
+ names=None):
"Protect a specific aspect"
self.__empty = 0
- if not (interface or methods):
+ if not (interface or names):
return []
permission_id = self._getPermission(permission_id)
@@ -81,52 +69,31 @@
if interface:
self.__protectByInterface(interface, permission_id, r)
- if methods:
- self.__protectMethods(methods, permission_id, r)
-
- return r
+ if names:
+ self.__protectNames(names, permission_id, r)
- def instances(self, _context, permission_id=None):
- "Protect instances of the class, as opposed to methods"
- self.__empty = 0
-
- permission_id = self._getPermission(permission_id)
- r=[]
- self.__instances(permission_id, r)
return r
- def __instances(self, permission_id, r):
- "Protect instances of the class, as opposed to methods"
- permission_id = self._getPermission(permission_id)
- r.append((
- ('protectInstances', self.__class),
- protectInstancesOfClass, (self.__class, permission_id,)))
-
- def __protectMethod(self, method, permission_id, r):
- "Set a permission on a particular method."
+ def __protectName(self, name, permission_id, r):
+ "Set a permission on a particular name."
r.append((
- ('protectMethod', self.__class, method),
- protectMethod, (self.__class, method, permission_id)))
-
- def __protectMethods(self, methods, permission_id, r):
- "Set a permission on a bunch of methods."
- for method in methods.split(","):
- self.__protectMethod(method.strip(), permission_id, r)
+ ('protectName', self.__class, name),
+ protectName, (self.__class, name, permission_id)))
+ def __protectNames(self, names, permission_id, r):
+ "Set a permission on a bunch of names."
+ for name in names.split(","):
+ self.__protectName(name.strip(), permission_id, r)
def __protectByInterface(self, interface, permission_id, r):
- "Set a permission on methods in an interface."
+ "Set a permission on names in an interface."
interface = self.__context.resolve(interface)
for n, d in interface.namesAndDescriptions(1):
- if isinstance(d, Method):
- self.__protectMethod(n, permission_id, r)
+ self.__protectName(n, permission_id, r)
def __call__(self):
"Handle empty/simple declaration."
- r = self.__r
- if self.__empty:
- self.__instances(self.__permission_id, r)
- return r
+ return self.__r
def _checkPermission(permission_id):
"""Check to make sure that the permission is valid.
@@ -135,58 +102,17 @@
if not permissionRegistry.definedPermission(permission_id):
raise UndefinedPermissionError(permission_id)
-
-def protectInstancesOfClass(class_, permission_id):
- _checkPermission(permission_id)
- class_.__permission__ = permission_id
-
-def protectMethod(class_, method, permission_id):
- "Set a permission on a particular method."
- _checkPermission(permission_id)
-
- m = getattr(class_, method)
-
- d = class_.__dict__
- if not d.has_key(method):
- # Hm, we inherit the method. Dang, we need to insert a stub
-
- # Make sure we have new style class:
- if not issubclass(class_, object):
- raise TypeError(
- "Can only protected inherited methods of new "
- "style classes", class_)
-
- f = Protected(class_, method, permission_id)
- setattr(class_, method, f)
- return
-
- try:
- setattr(m, "__permission__", permission_id)
- except (AttributeError, TypeError):
- if hasattr(m, "im_func"):
- setattr(m.im_func, "__permission__", permission_id)
- else:
- raise ProtectionDeclarationException(
- "Couldn't assign permission to method %s of class %s"
- % (m, class_.__name__))
-
-# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Hack!!!!!!!!!!
-
-class Protected(object):
-
- def __init__(self, *args):
- self.__args = args # class_, method, permission_id
-
- def __get__(self, instance, type=None):
- return ProtectedMethod(self.__args, instance)
-
+def protectName(class_, name, permission_id):
+ "Set a permission on a particular name."
+ checker = getCheckerForInstancesOf(class_)
+ if checker is None:
+ checker = Checker({}.get)
+ defineChecker(class_, checker)
+
+ # OK, so it's a hack.
+ names = checker.getPermission_func().__self__
+ if permission_id == 'Zope.Public':
+ # Translate public permission to CheckerPublic
+ permission_id = CheckerPublic
-class ProtectedMethod(object):
-
- def __init__(self, args, instance):
- class_, method, self.__permission__ = args
- m = getattr(super(class_, instance), method)
- self.__m = self.__call__ = m
-
- def __call__(self, *args, **kw):
- return self.__m(*args, **kw)
+ names[name] = permission_id
=== Zope3/lib/python/Zope/App/Security/publicClass.py 1.1.2.8 => 1.1.2.8.6.1 ===
def __init__(self, _context, name, permission_id=None, interface=None,
- methods=None):
+ names=None):
self._getPermission(permission_id) # Prohibit explicit permission!
protectClass.__init__(self, _context, name,
permission_id=PublicPermission,
- interface=interface, methods=methods)
+ interface=interface, names=names)
def _getPermission(self, permission_id=None):
if permission_id not in [None, PublicPermission]:
=== Zope3/lib/python/Zope/App/Security/security.zcml 1.1.2.4 => 1.1.2.4.2.1 ===
<security:protectClass name="Zope.App.Security.RolePermissionView."
permission_id="Zope.Security"
- methods="index, roles, permissions, permissionRoles, action,
+ names="index, roles, permissions, permissionRoles, action,
manage_permissionForm, update_permission,
manage_roleForm, update_role, permissionForID" />
<security:protectClass
name="Zope.App.Security.RolePermissionView.PermissionRoles."
permission_id="Zope.Security"
- methods="roles, rolesInfo"
+ names="roles, rolesInfo"
interface="Zope.App.Security.IRegisteredObject." />
@@ -55,7 +55,7 @@
<security:protectClass name="Zope.App.Security.PrincipalPermissionView."
permission_id="Zope.Security"
- methods="index, get_principal, unsetPermissions, denyPermissions,
+ names="index, get_principal, unsetPermissions, denyPermissions,
grantPermissions, getUnsetPermissionsForPrincipal,
getPermissionsForPrincipal" />