Commit 8e409efa authored by Hanno Schlichting's avatar Hanno Schlichting

Moved ``Products/Five/security.py`` into the AccessControl package.

parent 9e193fa3
......@@ -11,6 +11,8 @@ Trunk (unreleased)
Restructuring
+++++++++++++
- Moved ``Products/Five/security.py`` into the AccessControl package.
- Moved ``Products/Five/traversing.zcml`` directly into the configure.zcml.
- Moved zope.security-style permission registrations from Products.Five into
......
<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"
......
##############################################################################
#
# Copyright (c) 2004-2009 Zope Corporation 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 _registeredPermissions
from AccessControl.Permission import pname
import Products
from AccessControl.Permission import ApplicationDefaultPermissions
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):
sec = {}
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.
"""
global _registeredPermissions
# Zope 2 uses string, not unicode yet
zope2_permission = str(permission.title)
roles = ('Manager',)
if not _registeredPermissions.has_key(zope2_permission):
_registeredPermissions[zope2_permission] = 1
Products.__ac_permissions__ += ((zope2_permission, (), roles,),)
mangled = pname(zope2_permission)
setattr(ApplicationDefaultPermissions, mangled, roles)
......@@ -37,6 +37,12 @@ from zope.app.publisher.browser.viewmeta import providesCallable
from zope.app.publisher.browser.viewmeta import _handle_menu
from zope.app.publisher.browser.viewmeta import _handle_for
from AccessControl.security import getSecurityInfo
from AccessControl.security import protectClass
from AccessControl.security import protectName
from AccessControl.security import CheckerPrivateId
from App.class_init import InitializeClass
from Products.Five.browser import BrowserView
from Products.Five.browser.resource import FileResourceFactory
from Products.Five.browser.resource import ImageResourceFactory
......@@ -44,12 +50,7 @@ from Products.Five.browser.resource import PageTemplateResourceFactory
from Products.Five.browser.resource import DirectoryResourceFactory
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.Five.metaclass import makeClass
from Products.Five.security import getSecurityInfo
from Products.Five.security import protectClass
from Products.Five.security import protectName
from Products.Five.security import CheckerPrivateId
from App.class_init import InitializeClass
def page(_context, name, permission, for_,
layer=IDefaultBrowserLayer, template=None, class_=None,
......
......@@ -30,7 +30,7 @@ def test_menu():
>>> zcml.load_config("permissions.zcml", AccessControl)
>>> zcml.load_config('menu.zcml', package=Products.Five.browser.tests)
>>> from Products.Five.security import newInteraction
>>> from AccessControl.security import newInteraction
>>> newInteraction()
Now for some actual testing... Let's look up the menu we registered:
......
......@@ -11,7 +11,7 @@ def test_check_permission():
... xmlns="http://namespaces.zope.org/zope"
... xmlns:browser="http://namespaces.zope.org/browser">
... <securityPolicy
... component="Products.Five.security.FiveSecurityPolicy" />
... component="AccessControl.security.SecurityPolicy" />
... <configure package="Products.Five.browser.tests">
... <browser:page
... for="OFS.interfaces.IFolder"
......
......@@ -26,10 +26,12 @@ _ = MessageFactory('zope')
from zope.app.publisher.browser.menumeta import menuItemDirective
from zope.app.form.browser.metaconfigure import BaseFormDirective
from zope.browser.interfaces import IAdding
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from AccessControl.security import protectClass
from Products.Five.form import EditView, AddView
from Products.Five.metaclass import makeClass
from Products.Five.security import protectClass
from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
from Products.Five.browser.metaconfigure import makeClassForTemplate
......
......@@ -17,8 +17,8 @@ $Id$
"""
import warnings
from zope.security import metaconfigure
from AccessControl.security import protectName
from App.class_init import InitializeClass
from Products.Five.security import protectName
class ClassDirective(metaconfigure.ClassDirective):
......
<configure xmlns="http://namespaces.zope.org/zope"
i18n_domain="Five">
<!-- 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"
/>
<include package="AccessControl" file="permissions.zcml" />
<permission
id="five.ManageSite"
title="Manage Five local sites"
/>
<include package="AccessControl" file="permissions.zcml" />
<!-- CMF Core Permissions -->
<permission
......
......@@ -18,165 +18,20 @@ $Id$
from zope.deferredimport import deprecated
deprecated("Please import InitializeClass from App.class_init",
initializeClass = 'App.class_init:InitializeClass',
)
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 _registeredPermissions
from AccessControl.Permission import pname
import Products
from AccessControl.Permission import ApplicationDefaultPermissions
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):
sec = {}
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 3 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 FiveSecurityPolicy(ParanoidSecurityPolicy):
"""Security policy that bridges between Zope 3 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 3 to use Zope 2's checkPermission.
Zope 3 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 3 into using Zope 2's checker...
"""
if getattr(thread_local, 'interaction', None) is None:
thread_local.interaction = FiveSecurityPolicy()
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.
"""
global _registeredPermissions
# Zope 2 uses string, not unicode yet
zope2_permission = str(permission.title)
roles = ('Manager',)
if not _registeredPermissions.has_key(zope2_permission):
_registeredPermissions[zope2_permission] = 1
Products.__ac_permissions__ += ((zope2_permission, (), roles,),)
mangled = pname(zope2_permission)
setattr(ApplicationDefaultPermissions, mangled, roles)
initializeClass = 'App.class_init:InitializeClass',
)
deprecated("Please import from AccessControl.security",
CheckerPublicId = 'AccessControl.security:CheckerPublicId',
CheckerPrivateId = 'AccessControl.security:CheckerPrivateId',
getSecurityInfo = 'AccessControl.security:getSecurityInfo',
clearSecurityInfo = 'AccessControl.security:clearSecurityInfo',
checkPermission = 'AccessControl.security:checkPermission',
FiveSecurityPolicy = 'AccessControl.security:SecurityPolicy',
newInteraction = 'AccessControl.security:newInteraction',
_getSecurity = 'AccessControl.security:_getSecurity',
protectName = 'AccessControl.security:protectName',
protectClass = 'AccessControl.security:protectClass',
create_permission_from_permission_directive = \
'AccessControl.security:create_permission_from_permission_directive',
)
......@@ -151,7 +151,7 @@ def test_security_equivalence():
Before we end we should clean up after ourselves:
>>> from Products.Five.security import clearSecurityInfo
>>> from AccessControl.security import clearSecurityInfo
>>> clearSecurityInfo(Dummy1)
>>> clearSecurityInfo(Dummy2)
......@@ -292,8 +292,8 @@ def test_checkPermission():
has the permission to access an object. The function delegates to
the security policy's checkPermission() method.
Five has the same function, Five.security.checkPermission, but in
a Zope2-compatible implementation. It too uses the currently
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.
......@@ -310,7 +310,7 @@ def test_checkPermission():
a) zope2.Public (which should always be available to everyone)
>>> from Products.Five.security import checkPermission
>>> from AccessControl.security import checkPermission
>>> checkPermission('zope2.Public', self.folder)
True
......@@ -342,7 +342,7 @@ def test_checkPermission():
>>> from zope.security.management import endInteraction
>>> endInteraction()
>>> from Products.Five.security import newInteraction
>>> from AccessControl.security import newInteraction
>>> newInteraction()
a) zope2.Public (which should always be available to everyone)
......
......@@ -20,17 +20,15 @@ import os
from zope.app.publisher.browser import viewmeta
from zope.component import zcml
from zope.configuration.exceptions import ConfigurationError
from zope.interface import classImplements
from zope.interface import implements
from zope.interface import Interface
from zope.browser.interfaces import IBrowserView
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.viewlet import interfaces
from AccessControl.security import protectClass
from AccessControl.security import protectName
from App.class_init import InitializeClass
from App.special_dtml import DTMLFile
from Products.Five.security import protectClass
from Products.Five.security import protectName
from Products.Five.viewlet import manager
from Products.Five.viewlet import viewlet
......@@ -157,9 +155,6 @@ def viewletDirective(
new_class = type(class_.__name__,
(class_, viewlet.SimpleAttributeViewlet), cdict)
if hasattr(class_, '__implements__'):
classImplements(new_class, IBrowserPublisher)
else:
# Create a new class for the viewlet template alone.
new_class = viewlet.SimpleViewletClass(template, name=name,
......
......@@ -19,8 +19,8 @@ from zope.component.testing import PlacelessSetup as CAPlacelessSetup
from zope.component.eventtesting import PlacelessSetup as EventPlacelessSetup
from zope.container.testing import PlacelessSetup as ContainerPlacelessSetup
from zope.i18n.testing import PlacelessSetup as I18nPlacelessSetup
from zope.security.management import newInteraction
from zope.security.testing import addCheckerPublic
from AccessControl.security import newInteraction
class PlacelessSetup(CAPlacelessSetup,
......
......@@ -21,6 +21,6 @@
<securityPolicy
component="Products.Five.security.FiveSecurityPolicy" />
component="AccessControl.security.SecurityPolicy" />
</configure>
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