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):
if ERP5Security is not None:
# Use Pluggable Auth Service instead of the standard acl_users.
p.manage_addProduct['PluggableAuthService'].addPluggableAuthService()
pas_dispatcher = p.acl_users.manage_addProduct['PluggableAuthService']
# Add legacy ZODB support
p.acl_users.manage_addProduct['PluggableAuthService'].addZODBUserManager('zodb_users')
p.acl_users.manage_addProduct['PluggableAuthService'].addZODBGroupManager('zodb_groups')
p.acl_users.manage_addProduct['PluggableAuthService'].addZODBRoleManager('zodb_roles')
pas_dispatcher.addZODBUserManager('zodb_users')
pas_dispatcher.addZODBGroupManager('zodb_groups')
pas_dispatcher.addZODBRoleManager('zodb_roles')
# Add CMF Portal Roles
#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('Reviewer')
# Register ZODB Interface
p.acl_users.zodb_users.manage_activateInterfaces(('IAuthenticationPlugin',
'IUserEnumerationPlugin','IUserAdderPlugin'))
p.acl_users.zodb_groups.manage_activateInterfaces(('IGroupsPlugin',
p.acl_users.zodb_users.manage_activateInterfaces(
('IAuthenticationPlugin',
'IUserEnumerationPlugin',
'IUserAdderPlugin'))
p.acl_users.zodb_groups.manage_activateInterfaces(
('IGroupsPlugin',
'IGroupEnumerationPlugin'))
p.acl_users.zodb_roles.manage_activateInterfaces(('IRoleEnumerationPlugin',
'IRolesPlugin', 'IRoleAssignerPlugin'))
p.acl_users.zodb_roles.manage_activateInterfaces(
('IRoleEnumerationPlugin',
'IRolesPlugin',
'IRoleAssignerPlugin'))
# Add ERP5UserManager
p.acl_users.manage_addProduct['ERP5Security'].addERP5UserManager('erp5_users')
p.acl_users.manage_addProduct['ERP5Security'].addERP5GroupManager('erp5_groups')
p.acl_users.manage_addProduct['ERP5Security'].addERP5RoleManager('erp5_roles')
erp5security_dispatcher = p.acl_users.manage_addProduct['ERP5Security']
erp5security_dispatcher.addERP5UserManager('erp5_users')
erp5security_dispatcher.addERP5GroupManager('erp5_groups')
erp5security_dispatcher.addERP5RoleManager('erp5_roles')
erp5security_dispatcher.addERP5UserFactory('erp5_user_factory')
# Register ERP5UserManager Interface
p.acl_users.erp5_users.manage_activateInterfaces(('IAuthenticationPlugin',
p.acl_users.erp5_users.manage_activateInterfaces(
('IAuthenticationPlugin',
'IUserEnumerationPlugin',))
p.acl_users.erp5_groups.manage_activateInterfaces(('IGroupsPlugin',))
p.acl_users.erp5_roles.manage_activateInterfaces(('IRolesPlugin',))
p.acl_users.erp5_user_factory.manage_activateInterfaces(
('IUserFactoryPlugin',))
elif withnuxgroups:
# NuxUserGroups user folder
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
import ERP5UserManager
import ERP5GroupManager
import ERP5RoleManager
import ERP5UserFactory
def mergedLocalRoles(object):
"""Returns a merging of object and its ancestors'
......@@ -59,6 +60,7 @@ def mergedLocalRoles(object):
registerMultiPlugin(ERP5UserManager.ERP5UserManager.meta_type)
registerMultiPlugin(ERP5GroupManager.ERP5GroupManager.meta_type)
registerMultiPlugin(ERP5RoleManager.ERP5RoleManager.meta_type)
registerMultiPlugin(ERP5UserFactory.ERP5UserFactory.meta_type)
def initialize(context):
......@@ -88,3 +90,13 @@ def initialize(context):
, visibility=None
, 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,
Zope objects.
- False means that the role acquisition chain is cut.
The code to support this is in the user folder, see
patches/PropertiedUser.py
The code to support this is on the user class, see
ERP5Security.ERP5UserFactory.ERP5User
"""
def cached_getAcquireLocalRoles(portal_type):
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