[Erp5-report] r36487 mohamadou - /erp5/trunk/products/ERP5eGovSecurity/
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Jun 22 00:02:08 CEST 2010
Author: mohamadou
Date: Tue Jun 22 00:02:08 2010
New Revision: 36487
URL: http://svn.erp5.org?rev=36487&view=rev
Log:
Add EGov Group and User Manager
Added:
erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py
erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.pyc (with props)
erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py~
erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py
erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.pyc (with props)
erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py~
erp5/trunk/products/ERP5eGovSecurity/__init__.py
erp5/trunk/products/ERP5eGovSecurity/__init__.pyc (with props)
Added: erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py?rev=36487&view=auto
==============================================================================
--- erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py (added)
+++ erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py [utf8] Tue Jun 22 00:02:08 2010
@@ -0,0 +1,230 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2010 Nexedi SARL and Contributors. All Rights Reserved.
+# Mohamadou Mbengue <mayoro at gmail.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+""" Classes: ERP5GroupManager
+"""
+
+from Globals import InitializeClass
+from AccessControl.SecurityManagement import newSecurityManager,\
+ getSecurityManager, setSecurityManager
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from AccessControl import ClassSecurityInfo
+from Products.PluggableAuthService.PropertiedUser import PropertiedUser
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.utils import classImplements
+from Products.PluggableAuthService.interfaces.plugins import IGroupsPlugin
+from Products.ERP5Security.ERP5GroupManager import ERP5GroupManager
+from Products.ERP5Type.Cache import CachingMethod
+from ZODB.POSException import ConflictError
+from Products.ERP5Security.ERP5GroupManager import ConsistencyError
+
+import sys
+
+from zLOG import LOG, WARNING
+
+from Products.ERP5Security.ERP5UserManager import SUPER_USER
+
+
+NO_CACHE_MODE = 0
+manage_addEGOVGroupManagerForm = PageTemplateFile(
+ 'www/ERP5Security_addERP5GroupManager', globals(),
+ __name__='manage_addERP5GroupManagerForm' )
+
+def addEGOVGroupManager( dispatcher, id, title=None, REQUEST=None ):
+ """ Add a EGOVGroupManager to a Pluggable Auth Service. """
+ egm = EGOVGroupManager(id, title)
+ dispatcher._setObject(egm.getId(), egm)
+
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(
+ '%s/manage_workspace'
+ '?manage_tabs_message='
+ 'EGOVGroupManager+added.'
+ % dispatcher.absolute_url())
+
+
+class EGOVGroupManager(ERP5GroupManager):
+ """ PAS plugin for dynamically adding Groups
+ this plugin permit to login with evry portal_type
+ So it's possible to login with organisation
+ """
+ meta_type = 'EGOV Group Manager'
+ security = ClassSecurityInfo()
+
+ portal_type_list = ('Person',)
+
+ _properties = BasePlugin._properties + (
+ {'label' : 'Portal Type List (Experimental)',
+ 'type' : 'lines',
+ 'id' : 'portal_type_list',
+ 'mode' : 'w',
+ },
+ )
+
+ def __init__(self, id, title=None):
+
+ self._id = self.id = id
+ self.title = title
+
+ #
+ # IGroupsPlugin implementation
+ #
+ def getGroupsForPrincipal(self, principal, request=None):
+ """ See IGroupsPlugin.
+ """
+ # If this is the super user, skip the check.
+ if principal.getId() == SUPER_USER:
+ return ()
+
+ def _getGroupsForPrincipal(user_name, path):
+ security_category_dict = {} # key is the base_category_list,
+ # value is the list of fetched categories
+ security_group_list = []
+ security_definition_list = ()
+
+ # because we aren't logged in, we have to create our own
+ # SecurityManager to be able to access the Catalog
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+ try:
+ # To get the complete list of groups, we try to call the
+ # ERP5Type_getSecurityCategoryMapping which should return a list
+ # of lists of two elements (script, base_category_list) like :
+ # (
+ # ('script_1', ['base_category_1', 'base_category_2', ...]),
+ # ('script_2', ['base_category_1', 'base_category_3', ...])
+ # )
+ #
+ # else, if the script does not exist, falls back to a list containng
+ # only one list :
+ # (('ERP5Type_getSecurityCategoryFromAssignment',
+ # self.getPortalAssignmentBaseCategoryList() ),)
+
+ mapping_method = getattr(self,
+ 'ERP5Type_getSecurityCategoryMapping', None)
+ if mapping_method is None:
+ security_definition_list = ((
+ 'ERP5Type_getSecurityCategoryFromAssignment',
+ self.getPortalAssignmentBaseCategoryList()
+ ),)
+ else:
+ security_definition_list = mapping_method()
+
+ # get the person from its reference - no security check needed
+ catalog_result = self.portal_catalog.unrestrictedSearchResults(
+ portal_type=self.portal_type_list, reference=user_name)
+
+ if len(catalog_result) != 1: # we won't proceed with groups
+ if len(catalog_result) > 1: # configuration is screwed
+ raise ConsistencyError, 'There is more than one Person whose \
+ login is %s : %s' % (user_name,
+ repr([r.getObject() for r in catalog_result]))
+ else: # no person is linked to this user login
+ portal = self.getPortalObject()
+
+ # this permit to get the module of the application
+ # the goal is to work with anonymous applications, even if
+ # they are not reindexed
+
+ module_id = self.REQUEST.get('anonymous_module', None)
+ if module_id:
+ module = getattr(portal, module_id, None)
+ if module is not None:
+ result = module._getOb(user_name, None)
+ if result is not None:
+ person_object = result
+ else:
+ return ()
+ else:
+ return ()
+ else:
+ person_object = catalog_result[0].getObject()
+ person_id = person_object.getId()
+
+ # Fetch category values from defined scripts
+ for (method_name, base_category_list) in security_definition_list:
+ base_category_list = tuple(base_category_list)
+ method = getattr(self, method_name)
+ security_category_list = security_category_dict.setdefault(
+ base_category_list, [])
+ try:
+ security_category_list.extend(
+ method(base_category_list, user_name, person_object, '')
+ )
+ except ConflictError:
+ raise
+ except:
+ LOG('EGOVGroupManager', WARNING,
+ 'could not get security categories from %s' % (method_name,),
+ error = sys.exc_info())
+
+ # Get group names from category values
+ group_id_list_generator = getattr(self,
+ 'ERP5Type_asSecurityGroupIdList', None)
+ if group_id_list_generator is None:
+ group_id_list_generator = getattr(self, 'ERP5Type_asSecurityGroupId')
+ generator_name = "ERP5Type_asSecurityGroupId"
+ else:
+ generator_name = 'ERP5Type_asSecurityGroupIdList'
+ for base_category_list, category_value_list in \
+ security_category_dict.items():
+ for category_dict in category_value_list:
+ try:
+ group_id_list = group_id_list_generator(
+ category_order=base_category_list,
+ **category_dict)
+ if isinstance(group_id_list, str):
+ group_id_list = [group_id_list]
+ security_group_list.extend(group_id_list)
+ except ConflictError:
+ raise
+ except:
+ LOG('EGOVGroupManager', WARNING,
+ 'could not get security groups from %s' %
+ generator_name,
+ error = sys.exc_info())
+ finally:
+ setSecurityManager(sm)
+ return tuple(security_group_list)
+
+ if not NO_CACHE_MODE:
+ _getGroupsForPrincipal = CachingMethod(_getGroupsForPrincipal,
+ id='EGOVGroupManager_getGroupsForPrincipal',
+ cache_factory='erp5_content_short')
+
+ return _getGroupsForPrincipal(
+ user_name=principal.getId(),
+ path=self.getPhysicalPath())
+
+
+classImplements( EGOVGroupManager
+ , IGroupsPlugin
+ )
+
+InitializeClass(EGOVGroupManager)
Added: erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.pyc
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.pyc?rev=36487&view=auto
==============================================================================
Binary file - no diff available.
Propchange: erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.pyc
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py~
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py%7E?rev=36487&view=auto
==============================================================================
--- erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py~ (added)
+++ erp5/trunk/products/ERP5eGovSecurity/EGOVGroupManager.py~ [utf8] Tue Jun 22 00:02:08 2010
@@ -0,0 +1,217 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# 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: ERP5GroupManager
+"""
+
+from Globals import InitializeClass
+from AccessControl.SecurityManagement import newSecurityManager,\
+ getSecurityManager, setSecurityManager
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from AccessControl import ClassSecurityInfo
+from Products.PluggableAuthService.PropertiedUser import PropertiedUser
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.utils import classImplements
+from Products.PluggableAuthService.interfaces.plugins import IGroupsPlugin
+from Products.ERP5Security.ERP5GroupManager import ERP5GroupManager
+from Products.ERP5Type.Cache import CachingMethod
+from ZODB.POSException import ConflictError
+from Products.ERP5Security.ERP5GroupManager import ConsistencyError
+
+import sys
+
+from zLOG import LOG, WARNING
+
+from Products.ERP5Security.ERP5UserManager import SUPER_USER
+
+
+NO_CACHE_MODE = 0
+manage_addEGOVGroupManagerForm = PageTemplateFile(
+ 'www/ERP5Security_addERP5GroupManager', globals(),
+ __name__='manage_addERP5GroupManagerForm' )
+
+def addEGOVGroupManager( dispatcher, id, title=None, REQUEST=None ):
+ """ Add a EGOVGroupManager to a Pluggable Auth Service. """
+ egm = EGOVGroupManager(id, title)
+ dispatcher._setObject(egm.getId(), egm)
+
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(
+ '%s/manage_workspace'
+ '?manage_tabs_message='
+ 'EGOVGroupManager+added.'
+ % dispatcher.absolute_url())
+
+
+class EGOVGroupManager(ERP5GroupManager):
+ """ PAS plugin for dynamically adding Groups
+ this plugin permit to login with evry portal_type
+ So it's possible to login with organisation
+ """
+ meta_type = 'EGOV Group Manager'
+ security = ClassSecurityInfo()
+
+ portal_type_list = ('Person',)
+
+ _properties = BasePlugin._properties + (
+ {'label' : 'Portal Type List (Experimental)',
+ 'type' : 'lines',
+ 'id' : 'portal_type_list',
+ 'mode' : 'w',
+ },
+ )
+
+ def __init__(self, id, title=None):
+
+ self._id = self.id = id
+ self.title = title
+
+ #
+ # IGroupsPlugin implementation
+ #
+ def getGroupsForPrincipal(self, principal, request=None):
+ """ See IGroupsPlugin.
+ """
+ # If this is the super user, skip the check.
+ if principal.getId() == SUPER_USER:
+ return ()
+
+ def _getGroupsForPrincipal(user_name, path):
+ security_category_dict = {} # key is the base_category_list,
+ # value is the list of fetched categories
+ security_group_list = []
+ security_definition_list = ()
+
+ # because we aren't logged in, we have to create our own
+ # SecurityManager to be able to access the Catalog
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+ try:
+ # To get the complete list of groups, we try to call the
+ # ERP5Type_getSecurityCategoryMapping which should return a list
+ # of lists of two elements (script, base_category_list) like :
+ # (
+ # ('script_1', ['base_category_1', 'base_category_2', ...]),
+ # ('script_2', ['base_category_1', 'base_category_3', ...])
+ # )
+ #
+ # else, if the script does not exist, falls back to a list containng
+ # only one list :
+ # (('ERP5Type_getSecurityCategoryFromAssignment',
+ # self.getPortalAssignmentBaseCategoryList() ),)
+
+ mapping_method = getattr(self,
+ 'ERP5Type_getSecurityCategoryMapping', None)
+ if mapping_method is None:
+ security_definition_list = ((
+ 'ERP5Type_getSecurityCategoryFromAssignment',
+ self.getPortalAssignmentBaseCategoryList()
+ ),)
+ else:
+ security_definition_list = mapping_method()
+
+ # get the person from its reference - no security check needed
+ catalog_result = self.portal_catalog.unrestrictedSearchResults(
+ portal_type=self.portal_type_list, reference=user_name)
+
+ if len(catalog_result) != 1: # we won't proceed with groups
+ if len(catalog_result) > 1: # configuration is screwed
+ raise ConsistencyError, 'There is more than one Person whose \
+ login is %s : %s' % (user_name,
+ repr([r.getObject() for r in catalog_result]))
+ else: # no person is linked to this user login
+ portal = self.getPortalObject()
+
+ # this permit to get the module of the application
+ # the goal is to work with anonymous applications, even if
+ # they are not reindexed
+
+ module_id = self.REQUEST.get('anonymous_module', None)
+ if module_id:
+ module = getattr(portal, module_id, None)
+ if module is not None:
+ result = module._getOb(user_name, None)
+ if result is not None:
+ person_object = result
+ else:
+ return ()
+ else:
+ return ()
+ else:
+ person_object = catalog_result[0].getObject()
+ person_id = person_object.getId()
+
+ # Fetch category values from defined scripts
+ for (method_name, base_category_list) in security_definition_list:
+ base_category_list = tuple(base_category_list)
+ method = getattr(self, method_name)
+ security_category_list = security_category_dict.setdefault(
+ base_category_list, [])
+ try:
+ security_category_list.extend(
+ method(base_category_list, user_name, person_object, '')
+ )
+ except ConflictError:
+ raise
+ except:
+ LOG('EGOVGroupManager', WARNING,
+ 'could not get security categories from %s' % (method_name,),
+ error = sys.exc_info())
+
+ # Get group names from category values
+ group_id_list_generator = getattr(self,
+ 'ERP5Type_asSecurityGroupIdList', None)
+ if group_id_list_generator is None:
+ group_id_list_generator = getattr(self, 'ERP5Type_asSecurityGroupId')
+ generator_name = "ERP5Type_asSecurityGroupId"
+ else:
+ generator_name = 'ERP5Type_asSecurityGroupIdList'
+ for base_category_list, category_value_list in \
+ security_category_dict.items():
+ for category_dict in category_value_list:
+ try:
+ group_id_list = group_id_list_generator(
+ category_order=base_category_list,
+ **category_dict)
+ if isinstance(group_id_list, str):
+ group_id_list = [group_id_list]
+ security_group_list.extend(group_id_list)
+ except ConflictError:
+ raise
+ except:
+ LOG('EGOVGroupManager', WARNING,
+ 'could not get security groups from %s' %
+ generator_name,
+ error = sys.exc_info())
+ finally:
+ setSecurityManager(sm)
+ return tuple(security_group_list)
+
+ if not NO_CACHE_MODE:
+ _getGroupsForPrincipal = CachingMethod(_getGroupsForPrincipal,
+ id='EGOVGroupManager_getGroupsForPrincipal',
+ cache_factory='erp5_content_short')
+
+ return _getGroupsForPrincipal(
+ user_name=principal.getId(),
+ path=self.getPhysicalPath())
+
+
+classImplements( EGOVGroupManager
+ , IGroupsPlugin
+ )
+
+InitializeClass(EGOVGroupManager)
Added: erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py?rev=36487&view=auto
==============================================================================
--- erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py (added)
+++ erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py [utf8] Tue Jun 22 00:02:08 2010
@@ -0,0 +1,311 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2010 Nexedi SARL and Contributors. All Rights Reserved.
+# Mohamadou Mbengue <mayoro at gmail.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+""" Classes: ERP5UserManager
+"""
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from AccessControl.SecurityManagement import getSecurityManager,\
+ setSecurityManager, newSecurityManager
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PluggableAuthService.PluggableAuthService import \
+ _SWALLOWABLE_PLUGIN_EXCEPTIONS
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.utils import classImplements
+from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin
+from Products.PluggableAuthService.interfaces.plugins import IUserEnumerationPlugin
+from Products.ERP5Type.Cache import CachingMethod
+from Products.ERP5Security.ERP5UserManager import ERP5UserManager
+from ZODB.POSException import ConflictError
+import sys
+from DateTime import DateTime
+from zLOG import LOG, PROBLEM
+
+try :
+ from AccessControl.AuthEncoding import pw_validate
+except ImportError:
+ pw_validate = lambda reference, attempt: reference == attempt
+
+# This user is used to bypass all security checks.
+SUPER_USER = '__erp5security-=__'
+
+manage_addEGOVUserManagerForm = PageTemplateFile(
+ 'www/ERP5Security_addERP5UserManager', globals(),
+ __name__='manage_addERP5UserManagerForm' )
+
+
+def addEGOVUserManager(dispatcher, id, title=None, REQUEST=None):
+ """ Add a EGOVUserManager to a Pluggable Auth Service. """
+ eum = EGOVUserManager(id, title)
+ dispatcher._setObject(eum.getId(), eum)
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(
+ '%s/manage_workspace'
+ '?manage_tabs_message='
+ 'EGOVUserManager+added.'
+ % dispatcher.absolute_url())
+
+class EGOVUserManager(ERP5UserManager):
+ """ PAS plugin for managing users in ERP5
+ this plugin permit to login with evry portal_type
+ So it's possible to login with organisation
+ """
+
+ meta_type = 'EGOV User Manager'
+
+ security = ClassSecurityInfo()
+
+ portal_type_list = ('Person',)
+
+ _properties = BasePlugin._properties + (
+ {'label' : 'Portal Type List (Experimental)',
+ 'type' : 'lines',
+ 'id' : 'portal_type_list',
+ 'mode' : 'w',
+ },
+ )
+
+ def __init__(self, id, title=None):
+
+ self._id = self.id = id
+ self.title = title
+
+ #
+ # IAuthenticationPlugin implementation
+ #
+ security.declarePrivate( 'authenticateCredentials' )
+ def authenticateCredentials(self, credentials):
+ """ See IAuthenticationPlugin.
+
+ o We expect the credentials to be those returned by
+ ILoginPasswordExtractionPlugin.
+ """
+ # Forbidden the usage of the super user.
+ if credentials.get('login') == SUPER_USER:
+ return None
+
+ def _authenticateCredentials(login, password, path):
+ if not login or not password:
+ return None
+
+ user_list = self.getUserByLogin((login,))
+
+ if not user_list:
+ return None
+
+ user = user_list[0]
+ user_portal_type = user.getPortalType()
+
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+
+ # search for assignment only on person entity
+ if user_portal_type == 'Person':
+ try:
+ # get assignment
+ assignment_list = [x for x in \
+ user.contentValues(portal_type="Assignment") if \
+ x.getValidationState() == "open"]
+ valid_assignment_list = []
+ # check dates if exist
+ login_date = DateTime()
+ for assignment in assignment_list:
+ if assignment.getStartDate() is not None and \
+ assignment.getStartDate() > login_date:
+ continue
+ if assignment.getStopDate() is not None and \
+ assignment.getStopDate() < login_date:
+ continue
+ valid_assignment_list.append(assignment)
+
+ if pw_validate(user.getPassword(), password) and \
+ len(valid_assignment_list): #user.getCareerRole() == 'internal':
+ return login, login # use same for user_id and login
+ finally:
+ setSecurityManager(sm)
+ else:
+ if pw_validate(user.getPassword(), password):
+ return login, login # use same for user_id and login
+
+ return None
+
+ _authenticateCredentials = CachingMethod(_authenticateCredentials,
+ id='ERP5UserManager_authenticateCredentials',
+ cache_factory='erp5_content_short')
+ return _authenticateCredentials(
+ login=credentials.get('login'),
+ password=credentials.get('password'),
+ path=self.getPhysicalPath())
+
+ #
+ # IUserEnumerationPlugin implementation
+ #
+ security.declarePrivate( 'enumerateUsers' )
+ def enumerateUsers(self, id=None, login=None, exact_match=False,
+ sort_by=None, max_results=None, **kw):
+ """ See IUserEnumerationPlugin.
+ """
+ def _enumerateUsers(id_tuple, exact_match, path):
+ user_info = []
+ plugin_id = self.getId()
+
+ id_list = []
+ for id in id_tuple:
+ if SUPER_USER == id:
+ info = { 'id' : SUPER_USER
+ , 'login' : SUPER_USER
+ , 'pluginid' : plugin_id
+ }
+ user_info.append(info)
+ else:
+ if exact_match:
+ id_list.append(id)
+ else:
+ id_list.append('%%%s%%' % id)
+
+ if id_list:
+ for user in self.getUserByLogin(tuple(id_list), exact_match=exact_match):
+ info = { 'id' : user.getReference()
+ , 'login' : user.getReference()
+ , 'pluginid' : plugin_id
+ }
+
+ user_info.append(info)
+
+ return tuple(user_info)
+
+ _enumerateUsers = CachingMethod(_enumerateUsers,
+ id='ERP5UserManager_enumerateUsers',
+ cache_factory='erp5_content_short')
+
+ if id is None:
+ id = login
+ if isinstance(id, list):
+ id = tuple(id)
+ elif not isinstance(id, tuple):
+ id = (id,)
+ return _enumerateUsers(id_tuple=id,
+ exact_match=exact_match,
+ path=self.getPhysicalPath())
+
+ def getUserByLogin(self, login, exact_match=True):
+ # Search the Catalog for login and return a list of person objects
+ # login can be a string or a list of strings
+ # (no docstring to prevent publishing)
+ if not login:
+ return []
+
+ portal = self.getPortalObject()
+
+ def _getUserByLogin(login, exact_match):
+ # because we aren't logged in, we have to create our own
+ # SecurityManager to be able to access the Catalog
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+
+ try:
+ try:
+ result = portal.portal_catalog.unrestrictedSearchResults(
+ select_expression='reference',
+ portal_type=self.portal_type_list, reference=login)
+ if len(result) != 1: # we won't proceed with groups
+ if len(result) > 1: # configuration is screwed
+ raise ConsistencyError, 'There is more than one Person whose \
+ login is %s : %s' % (user_name,
+ repr([r.getObject() for r in catalog_result]))
+ else: # no person is linked to this user login
+ # this permit to get the module of the application
+ # the goal is to work with anonymous applications, even if
+ # they are not reindexed
+ module_id = self.REQUEST.get('anonymous_module', None)
+ if module_id:
+ module = getattr(portal, module_id, None)
+ if module is not None:
+ result = module._getOb(login[0], None)
+ if result is not None:
+ return [result.getPath(),]
+ else:
+ return []
+ else:
+ return []
+ except ConflictError:
+ raise
+ except:
+ LOG('ERP5Security', PROBLEM, 'getUserByLogin failed', error=sys.exc_info())
+ # Here we must raise an exception to prevent callers from caching
+ # a result of a degraded situation.
+ # The kind of exception does not matter as long as it's catched by
+ # PAS and causes a lookup using another plugin or user folder.
+ # As PAS does not define explicitely such exception, we must use
+ # the _SWALLOWABLE_PLUGIN_EXCEPTIONS list.
+ raise _SWALLOWABLE_PLUGIN_EXCEPTIONS[0]
+ finally:
+ setSecurityManager(sm)
+ # XXX: Here, we filter catalog result list ALTHOUGH we did pass
+ # parameters to unrestrictedSearchResults to restrict result set.
+ # This is done because the following values can match person with
+ # reference "foo":
+ # "foo " because of MySQL (feature, PADSPACE collation):
+ # mysql> SELECT reference as r FROM catalog
+ # -> WHERE reference="foo ";
+ # +-----+
+ # | r |
+ # +-----+
+ # | foo |
+ # +-----+
+ # 1 row in set (0.01 sec)
+ # " foo", "foo " and other padding variations because of
+ # ZSQLCatalog (feature ?):
+ # (Pdb) print portal.portal_catalog.unrestrictedSearchResults(\
+ # portal_type="Person", reference=' foo ', src__=1)
+ # SELECT DISTINCT
+ # catalog.path, catalog.uid
+ # FROM
+ # catalog AS catalog
+ # WHERE
+ # 1 = 1
+ # AND (((((catalog.portal_type = 'Person'))))) AND (((((catalog.reference = 'foo')))))
+ # LIMIT 1000
+ # "bar OR foo" because of ZSQLCatalog tokenizing searched sgtrings
+ # by default (feature).
+ return [x.path for x in result if (not exact_match) or x['reference'] in login]
+ _getUserByLogin = CachingMethod(_getUserByLogin,
+ id='ERP5UserManager_getUserByLogin',
+ cache_factory='erp5_content_short')
+ result = _getUserByLogin(login, exact_match)
+ return [portal.unrestrictedTraverse(x) for x in result]
+
+classImplements( EGOVUserManager
+ , IAuthenticationPlugin
+ , IUserEnumerationPlugin
+ )
+
+InitializeClass(EGOVUserManager)
Added: erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.pyc
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.pyc?rev=36487&view=auto
==============================================================================
Binary file - no diff available.
Propchange: erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.pyc
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py~
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py%7E?rev=36487&view=auto
==============================================================================
--- erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py~ (added)
+++ erp5/trunk/products/ERP5eGovSecurity/EGOVUserManager.py~ [utf8] Tue Jun 22 00:02:08 2010
@@ -0,0 +1,298 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# 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: ERP5UserManager
+"""
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from AccessControl.SecurityManagement import getSecurityManager,\
+ setSecurityManager, newSecurityManager
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PluggableAuthService.PluggableAuthService import \
+ _SWALLOWABLE_PLUGIN_EXCEPTIONS
+from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
+from Products.PluggableAuthService.utils import classImplements
+from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin
+from Products.PluggableAuthService.interfaces.plugins import IUserEnumerationPlugin
+from Products.ERP5Type.Cache import CachingMethod
+from Products.ERP5Security.ERP5UserManager import ERP5UserManager
+from ZODB.POSException import ConflictError
+import sys
+from DateTime import DateTime
+from zLOG import LOG, PROBLEM
+
+try :
+ from AccessControl.AuthEncoding import pw_validate
+except ImportError:
+ pw_validate = lambda reference, attempt: reference == attempt
+
+# This user is used to bypass all security checks.
+SUPER_USER = '__erp5security-=__'
+
+manage_addEGOVUserManagerForm = PageTemplateFile(
+ 'www/ERP5Security_addERP5UserManager', globals(),
+ __name__='manage_addERP5UserManagerForm' )
+
+
+def addEGOVUserManager(dispatcher, id, title=None, REQUEST=None):
+ """ Add a EGOVUserManager to a Pluggable Auth Service. """
+ eum = EGOVUserManager(id, title)
+ dispatcher._setObject(eum.getId(), eum)
+ if REQUEST is not None:
+ REQUEST['RESPONSE'].redirect(
+ '%s/manage_workspace'
+ '?manage_tabs_message='
+ 'EGOVUserManager+added.'
+ % dispatcher.absolute_url())
+
+class EGOVUserManager(ERP5UserManager):
+ """ PAS plugin for managing users in ERP5
+ this plugin permit to login with evry portal_type
+ So it's possible to login with organisation
+ """
+
+ meta_type = 'EGOV User Manager'
+
+ security = ClassSecurityInfo()
+
+ portal_type_list = ('Person',)
+
+ _properties = BasePlugin._properties + (
+ {'label' : 'Portal Type List (Experimental)',
+ 'type' : 'lines',
+ 'id' : 'portal_type_list',
+ 'mode' : 'w',
+ },
+ )
+
+ def __init__(self, id, title=None):
+
+ self._id = self.id = id
+ self.title = title
+
+ #
+ # IAuthenticationPlugin implementation
+ #
+ security.declarePrivate( 'authenticateCredentials' )
+ def authenticateCredentials(self, credentials):
+ """ See IAuthenticationPlugin.
+
+ o We expect the credentials to be those returned by
+ ILoginPasswordExtractionPlugin.
+ """
+ # Forbidden the usage of the super user.
+ if credentials.get('login') == SUPER_USER:
+ return None
+
+ def _authenticateCredentials(login, password, path):
+ if not login or not password:
+ return None
+
+ user_list = self.getUserByLogin((login,))
+
+ if not user_list:
+ return None
+
+ user = user_list[0]
+ user_portal_type = user.getPortalType()
+
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+
+ # search for assignment only on person entity
+ if user_portal_type == 'Person':
+ try:
+ # get assignment
+ assignment_list = [x for x in \
+ user.contentValues(portal_type="Assignment") if \
+ x.getValidationState() == "open"]
+ valid_assignment_list = []
+ # check dates if exist
+ login_date = DateTime()
+ for assignment in assignment_list:
+ if assignment.getStartDate() is not None and \
+ assignment.getStartDate() > login_date:
+ continue
+ if assignment.getStopDate() is not None and \
+ assignment.getStopDate() < login_date:
+ continue
+ valid_assignment_list.append(assignment)
+
+ if pw_validate(user.getPassword(), password) and \
+ len(valid_assignment_list): #user.getCareerRole() == 'internal':
+ return login, login # use same for user_id and login
+ finally:
+ setSecurityManager(sm)
+ else:
+ if pw_validate(user.getPassword(), password):
+ return login, login # use same for user_id and login
+
+ return None
+
+ _authenticateCredentials = CachingMethod(_authenticateCredentials,
+ id='ERP5UserManager_authenticateCredentials',
+ cache_factory='erp5_content_short')
+ return _authenticateCredentials(
+ login=credentials.get('login'),
+ password=credentials.get('password'),
+ path=self.getPhysicalPath())
+
+ #
+ # IUserEnumerationPlugin implementation
+ #
+ security.declarePrivate( 'enumerateUsers' )
+ def enumerateUsers(self, id=None, login=None, exact_match=False,
+ sort_by=None, max_results=None, **kw):
+ """ See IUserEnumerationPlugin.
+ """
+ def _enumerateUsers(id_tuple, exact_match, path):
+ user_info = []
+ plugin_id = self.getId()
+
+ id_list = []
+ for id in id_tuple:
+ if SUPER_USER == id:
+ info = { 'id' : SUPER_USER
+ , 'login' : SUPER_USER
+ , 'pluginid' : plugin_id
+ }
+ user_info.append(info)
+ else:
+ if exact_match:
+ id_list.append(id)
+ else:
+ id_list.append('%%%s%%' % id)
+
+ if id_list:
+ for user in self.getUserByLogin(tuple(id_list), exact_match=exact_match):
+ info = { 'id' : user.getReference()
+ , 'login' : user.getReference()
+ , 'pluginid' : plugin_id
+ }
+
+ user_info.append(info)
+
+ return tuple(user_info)
+
+ _enumerateUsers = CachingMethod(_enumerateUsers,
+ id='ERP5UserManager_enumerateUsers',
+ cache_factory='erp5_content_short')
+
+ if id is None:
+ id = login
+ if isinstance(id, list):
+ id = tuple(id)
+ elif not isinstance(id, tuple):
+ id = (id,)
+ return _enumerateUsers(id_tuple=id,
+ exact_match=exact_match,
+ path=self.getPhysicalPath())
+
+ def getUserByLogin(self, login, exact_match=True):
+ # Search the Catalog for login and return a list of person objects
+ # login can be a string or a list of strings
+ # (no docstring to prevent publishing)
+ if not login:
+ return []
+
+ portal = self.getPortalObject()
+
+ def _getUserByLogin(login, exact_match):
+ # because we aren't logged in, we have to create our own
+ # SecurityManager to be able to access the Catalog
+ sm = getSecurityManager()
+ if sm.getUser().getId() != SUPER_USER:
+ newSecurityManager(self, self.getUser(SUPER_USER))
+
+ try:
+ try:
+ result = portal.portal_catalog.unrestrictedSearchResults(
+ select_expression='reference',
+ portal_type=self.portal_type_list, reference=login)
+ if len(result) != 1: # we won't proceed with groups
+ if len(result) > 1: # configuration is screwed
+ raise ConsistencyError, 'There is more than one Person whose \
+ login is %s : %s' % (user_name,
+ repr([r.getObject() for r in catalog_result]))
+ else: # no person is linked to this user login
+ # this permit to get the module of the application
+ # the goal is to work with anonymous applications, even if
+ # they are not reindexed
+ module_id = self.REQUEST.get('anonymous_module', None)
+ if module_id:
+ module = getattr(portal, module_id, None)
+ if module is not None:
+ result = module._getOb(login[0], None)
+ if result is not None:
+ return [result.getPath(),]
+ else:
+ return []
+ else:
+ return []
+ except ConflictError:
+ raise
+ except:
+ LOG('ERP5Security', PROBLEM, 'getUserByLogin failed', error=sys.exc_info())
+ # Here we must raise an exception to prevent callers from caching
+ # a result of a degraded situation.
+ # The kind of exception does not matter as long as it's catched by
+ # PAS and causes a lookup using another plugin or user folder.
+ # As PAS does not define explicitely such exception, we must use
+ # the _SWALLOWABLE_PLUGIN_EXCEPTIONS list.
+ raise _SWALLOWABLE_PLUGIN_EXCEPTIONS[0]
+ finally:
+ setSecurityManager(sm)
+ # XXX: Here, we filter catalog result list ALTHOUGH we did pass
+ # parameters to unrestrictedSearchResults to restrict result set.
+ # This is done because the following values can match person with
+ # reference "foo":
+ # "foo " because of MySQL (feature, PADSPACE collation):
+ # mysql> SELECT reference as r FROM catalog
+ # -> WHERE reference="foo ";
+ # +-----+
+ # | r |
+ # +-----+
+ # | foo |
+ # +-----+
+ # 1 row in set (0.01 sec)
+ # " foo", "foo " and other padding variations because of
+ # ZSQLCatalog (feature ?):
+ # (Pdb) print portal.portal_catalog.unrestrictedSearchResults(\
+ # portal_type="Person", reference=' foo ', src__=1)
+ # SELECT DISTINCT
+ # catalog.path, catalog.uid
+ # FROM
+ # catalog AS catalog
+ # WHERE
+ # 1 = 1
+ # AND (((((catalog.portal_type = 'Person'))))) AND (((((catalog.reference = 'foo')))))
+ # LIMIT 1000
+ # "bar OR foo" because of ZSQLCatalog tokenizing searched sgtrings
+ # by default (feature).
+ return [x.path for x in result if (not exact_match) or x['reference'] in login]
+ _getUserByLogin = CachingMethod(_getUserByLogin,
+ id='ERP5UserManager_getUserByLogin',
+ cache_factory='erp5_content_short')
+ result = _getUserByLogin(login, exact_match)
+ return [portal.unrestrictedTraverse(x) for x in result]
+
+classImplements( EGOVUserManager
+ , IAuthenticationPlugin
+ , IUserEnumerationPlugin
+ )
+
+InitializeClass(EGOVUserManager)
Added: erp5/trunk/products/ERP5eGovSecurity/__init__.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/__init__.py?rev=36487&view=auto
==============================================================================
--- erp5/trunk/products/ERP5eGovSecurity/__init__.py (added)
+++ erp5/trunk/products/ERP5eGovSecurity/__init__.py [utf8] Tue Jun 22 00:02:08 2010
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+""" ERP5Security product initialization.
+"""
+
+from copy import deepcopy
+
+from AccessControl.Permissions import manage_users as ManageUsers
+from Products.PluggableAuthService.PluggableAuthService import registerMultiPlugin
+from Products.PluggableAuthService.permissions import ManageGroups
+
+import EGOVUserManager
+import EGOVGroupManager
+from Products.ERP5Security import ERP5UserFactory
+from Products.ERP5Security import ERP5RoleManager
+
+
+def mergedLocalRoles(object):
+ """Returns a merging of object and its ancestors'
+ __ac_local_roles__."""
+ # Modified to take into account _getAcquireLocalRoles
+ merged = {}
+ object = getattr(object, 'aq_inner', object)
+ while 1:
+ if getattr(object, '__ac_local_roles__', None) is not None:
+ roles = object.__ac_local_roles__ or {}
+ if callable(roles): roles = roles()
+ for k, v in roles.iteritems():
+ merged.setdefault(k, []).extend(v)
+ # block acquisition
+ if getattr(object, '_getAcquireLocalRoles', None) is not None:
+ if not object._getAcquireLocalRoles() is not None:
+ break
+ if getattr(object, 'aq_parent', None) is not None:
+ object = object.aq_parent
+ object = getattr(object, 'aq_inner', object)
+ continue
+ if getattr(object, 'im_self', None) is not None:
+ object = object.im_self
+ object = getattr(object, 'aq_inner', object)
+ continue
+ break
+
+ return deepcopy(merged)
+
+registerMultiPlugin(EGOVUserManager.EGOVUserManager.meta_type)
+registerMultiPlugin(EGOVGroupManager.EGOVGroupManager.meta_type)
+
+def initialize(context):
+
+ context.registerClass( EGOVUserManager.EGOVUserManager
+ , permission=ManageUsers
+ , constructors=(
+ EGOVUserManager.manage_addEGOVUserManagerForm,
+ EGOVUserManager.addEGOVUserManager, )
+ , visibility=None
+ , icon='www/portal.gif'
+ )
+
+ context.registerClass( EGOVGroupManager.EGOVGroupManager
+ , permission=ManageGroups
+ , constructors=(
+ EGOVGroupManager.manage_addEGOVGroupManagerForm,
+ EGOVGroupManager.addEGOVGroupManager, )
+ , visibility=None
+ , icon='www/portal.gif'
+ )
Added: erp5/trunk/products/ERP5eGovSecurity/__init__.pyc
URL: http://svn.erp5.org/erp5/trunk/products/ERP5eGovSecurity/__init__.pyc?rev=36487&view=auto
==============================================================================
Binary file - no diff available.
Propchange: erp5/trunk/products/ERP5eGovSecurity/__init__.pyc
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
More information about the Erp5-report
mailing list