############################################################################## # # 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 Products.ERP5Type.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 from Products.ERP5Security.ERP5UserManager import SUPER_USER 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 self.getUserName() == SUPER_USER: # super user is allowed to any object return 1 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(inner_obj, '_getAcquireLocalRoles', None) is not None: if not inner_obj._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)