Commit 61564f72 authored by Jérome Perrin's avatar Jérome Perrin

Move local roles bocking code in a dedicated ERP5User class instead of monkey

patching PropertiedUser. Register an UserFactoryPlugin to return ERP5Users.

ERP5Type/patches/PropertiedUser.py is now useless and will disapear soon. To
update your ERP5 instance, you will have to add an ERP5 User Factory in your
acl_users (using the ZMI)



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@12286 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent d173ff54
...@@ -1278,30 +1278,41 @@ class ERP5Generator(PortalGenerator): ...@@ -1278,30 +1278,41 @@ class ERP5Generator(PortalGenerator):
if ERP5Security is not None: if ERP5Security is not None:
# Use Pluggable Auth Service instead of the standard acl_users. # Use Pluggable Auth Service instead of the standard acl_users.
p.manage_addProduct['PluggableAuthService'].addPluggableAuthService() p.manage_addProduct['PluggableAuthService'].addPluggableAuthService()
pas_dispatcher = p.acl_users.manage_addProduct['PluggableAuthService']
# Add legacy ZODB support # Add legacy ZODB support
p.acl_users.manage_addProduct['PluggableAuthService'].addZODBUserManager('zodb_users') pas_dispatcher.addZODBUserManager('zodb_users')
p.acl_users.manage_addProduct['PluggableAuthService'].addZODBGroupManager('zodb_groups') pas_dispatcher.addZODBGroupManager('zodb_groups')
p.acl_users.manage_addProduct['PluggableAuthService'].addZODBRoleManager('zodb_roles') pas_dispatcher.addZODBRoleManager('zodb_roles')
# Add CMF Portal Roles # Add CMF Portal Roles
#XXX Maybe it will be no longer required once PAS is the standard #XXX Maybe it will be no longer required once PAS is the standard
p.acl_users.zodb_roles.addRole('Member') p.acl_users.zodb_roles.addRole('Member')
p.acl_users.zodb_roles.addRole('Reviewer') p.acl_users.zodb_roles.addRole('Reviewer')
# Register ZODB Interface # Register ZODB Interface
p.acl_users.zodb_users.manage_activateInterfaces(('IAuthenticationPlugin', p.acl_users.zodb_users.manage_activateInterfaces(
'IUserEnumerationPlugin','IUserAdderPlugin')) ('IAuthenticationPlugin',
p.acl_users.zodb_groups.manage_activateInterfaces(('IGroupsPlugin', 'IUserEnumerationPlugin',
'IUserAdderPlugin'))
p.acl_users.zodb_groups.manage_activateInterfaces(
('IGroupsPlugin',
'IGroupEnumerationPlugin')) 'IGroupEnumerationPlugin'))
p.acl_users.zodb_roles.manage_activateInterfaces(('IRoleEnumerationPlugin', p.acl_users.zodb_roles.manage_activateInterfaces(
'IRolesPlugin', 'IRoleAssignerPlugin')) ('IRoleEnumerationPlugin',
'IRolesPlugin',
'IRoleAssignerPlugin'))
# Add ERP5UserManager # Add ERP5UserManager
p.acl_users.manage_addProduct['ERP5Security'].addERP5UserManager('erp5_users') erp5security_dispatcher = p.acl_users.manage_addProduct['ERP5Security']
p.acl_users.manage_addProduct['ERP5Security'].addERP5GroupManager('erp5_groups') erp5security_dispatcher.addERP5UserManager('erp5_users')
p.acl_users.manage_addProduct['ERP5Security'].addERP5RoleManager('erp5_roles') erp5security_dispatcher.addERP5GroupManager('erp5_groups')
erp5security_dispatcher.addERP5RoleManager('erp5_roles')
erp5security_dispatcher.addERP5UserFactory('erp5_user_factory')
# Register ERP5UserManager Interface # Register ERP5UserManager Interface
p.acl_users.erp5_users.manage_activateInterfaces(('IAuthenticationPlugin', p.acl_users.erp5_users.manage_activateInterfaces(
('IAuthenticationPlugin',
'IUserEnumerationPlugin',)) 'IUserEnumerationPlugin',))
p.acl_users.erp5_groups.manage_activateInterfaces(('IGroupsPlugin',)) p.acl_users.erp5_groups.manage_activateInterfaces(('IGroupsPlugin',))
p.acl_users.erp5_roles.manage_activateInterfaces(('IRolesPlugin',)) p.acl_users.erp5_roles.manage_activateInterfaces(('IRolesPlugin',))
p.acl_users.erp5_user_factory.manage_activateInterfaces(
('IUserFactoryPlugin',))
elif withnuxgroups: elif withnuxgroups:
# NuxUserGroups user folder # NuxUserGroups user folder
p.manage_addProduct['NuxUserGroups'].addUserFolderWithGroups() p.manage_addProduct['NuxUserGroups'].addUserFolderWithGroups()
......
##############################################################################
#
# Copyright (c) 2001 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.
#
##############################################################################
""" Classes: ERP5User, ERP5UserFactory
"""
from Globals import InitializeClass
from Acquisition import aq_inner, aq_parent
from AccessControl import ClassSecurityInfo
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from Products.PluggableAuthService.utils import classImplements
from Products.PluggableAuthService.interfaces.plugins import IUserFactoryPlugin
from Products.PluggableAuthService.PropertiedUser import PropertiedUser
from Products.PluggableAuthService.PropertiedUser import \
_what_not_even_god_should_do
manage_addERP5UserFactoryForm = PageTemplateFile(
'www/ERP5Security_addERP5UserFactory', globals(),
__name__='manage_addERP5UserFactoryForm' )
def addERP5UserFactory( dispatcher, id, title=None, REQUEST=None ):
""" Add a ERP5UserFactory to a Pluggable Auth Service. """
euf = ERP5UserFactory(id, title)
dispatcher._setObject(euf.getId(), euf)
if REQUEST is not None:
REQUEST['RESPONSE'].redirect( '%s/manage_workspace'
'?manage_tabs_message='
'ERP5UserFactory+added.'
% dispatcher.absolute_url())
class ERP5User(PropertiedUser):
""" User class that checks the object allows acquisition of local roles the
ERP5Type way.
"""
def getRolesInContext( self, object ):
""" Return the list of roles assigned to the user.
For ERP5, we check if a _getAcquireLocalRoles is defined on the object.
"""
user_id = self.getId()
# [ x.getId() for x in self.getGroups() ]
group_ids = self.getGroups()
principal_ids = list( group_ids )
principal_ids.insert( 0, user_id )
local ={}
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 principal_id in principal_ids:
for role in dict.get( principal_id, [] ):
local[ role ] = 1
# patch by Klaus for LocalRole blocking
if getattr(object, '_getAcquireLocalRoles', None) is not None:
if not object._getAcquireLocalRoles():
break
inner = aq_inner( object )
parent = aq_parent( inner )
if parent is not None:
object = parent
continue
new = getattr( object, 'im_self', None )
if new is not None:
object = aq_inner( new )
continue
break
return list( self.getRoles() ) + local.keys()
def allowed( self, object, object_roles=None ):
""" Check whether the user has access to object.
As for getRolesInContext, we take into account _getAcquireLocalRoles for
ERP5.
"""
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'):
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 = aq_inner( object )
user_id = self.getId()
# [ x.getId() for x in self.getGroups() ]
group_ids = self.getGroups()
principal_ids = list( group_ids )
principal_ids.insert( 0, user_id )
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 {}
for principal_id in principal_ids:
local_roles = dict.get( principal_id, [] )
for role in object_roles:
if role in local_roles:
if self._check_context( object ):
return 1
return 0
# patch by Klaus for LocalRole blocking
if getattr(object, '_getAcquireLocalRoles', None) is not None:
if not object._getAcquireLocalRoles():
break
inner = aq_inner( inner_obj )
parent = aq_parent( inner )
if parent is not None:
inner_obj = parent
continue
new = getattr( inner_obj, 'im_self', None )
if new is not None:
inner_obj = aq_inner( new )
continue
break
return None
InitializeClass(ERP5User)
class ERP5UserFactory(BasePlugin):
""" PAS plugin for creating users that understand local roles blocking based
on type information's acquire_local_roles
"""
meta_type = 'ERP5 User Factory'
security = ClassSecurityInfo()
def __init__(self, id, title=None):
self._id = self.id = id
self.title = title
def createUser( self, user_id, name ):
""" See IUserFactoryPlugin
"""
return ERP5User(user_id, name)
classImplements( ERP5UserFactory
, IUserFactoryPlugin
)
InitializeClass(ERP5UserFactory)
...@@ -24,6 +24,7 @@ from Products.PluggableAuthService.permissions import ManageGroups ...@@ -24,6 +24,7 @@ from Products.PluggableAuthService.permissions import ManageGroups
import ERP5UserManager import ERP5UserManager
import ERP5GroupManager import ERP5GroupManager
import ERP5RoleManager import ERP5RoleManager
import ERP5UserFactory
def mergedLocalRoles(object): def mergedLocalRoles(object):
"""Returns a merging of object and its ancestors' """Returns a merging of object and its ancestors'
...@@ -59,6 +60,7 @@ def mergedLocalRoles(object): ...@@ -59,6 +60,7 @@ def mergedLocalRoles(object):
registerMultiPlugin(ERP5UserManager.ERP5UserManager.meta_type) registerMultiPlugin(ERP5UserManager.ERP5UserManager.meta_type)
registerMultiPlugin(ERP5GroupManager.ERP5GroupManager.meta_type) registerMultiPlugin(ERP5GroupManager.ERP5GroupManager.meta_type)
registerMultiPlugin(ERP5RoleManager.ERP5RoleManager.meta_type) registerMultiPlugin(ERP5RoleManager.ERP5RoleManager.meta_type)
registerMultiPlugin(ERP5UserFactory.ERP5UserFactory.meta_type)
def initialize(context): def initialize(context):
...@@ -88,3 +90,13 @@ def initialize(context): ...@@ -88,3 +90,13 @@ def initialize(context):
, visibility=None , visibility=None
, icon='www/portal.gif' , icon='www/portal.gif'
) )
context.registerClass( ERP5UserFactory.ERP5UserFactory
, permission=ManageUsers
, constructors=(
ERP5UserFactory.manage_addERP5UserFactoryForm,
ERP5UserFactory.addERP5UserFactory, )
, visibility=None
, icon='www/portal.gif'
)
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add ERP5 User Factory"
tal:replace="structure here/manage_form_title">Form Title</h2>
<p class="form-help">
ERP5 User Factory creates user objects.
</p>
<form action="addERP5UserFactory" method="post">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
...@@ -2262,8 +2262,8 @@ class Base( CopyContainer, ...@@ -2262,8 +2262,8 @@ class Base( CopyContainer,
Zope objects. Zope objects.
- False means that the role acquisition chain is cut. - False means that the role acquisition chain is cut.
The code to support this is in the user folder, see The code to support this is on the user class, see
patches/PropertiedUser.py ERP5Security.ERP5UserFactory.ERP5User
""" """
def cached_getAcquireLocalRoles(portal_type): def cached_getAcquireLocalRoles(portal_type):
ti = self._getTypesTool().getTypeInfo(self) ti = self._getTypesTool().getTypeInfo(self)
......
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