[Erp5-report] r12286 - in /erp5/trunk/products: ERP5/ ERP5Security/ ERP5Security/www/ ERP5T...

nobody at svn.erp5.org nobody at svn.erp5.org
Wed Jan 24 13:12:29 CET 2007


Author: jerome
Date: Wed Jan 24 13:12:25 2007
New Revision: 12286

URL: http://svn.erp5.org?rev=12286&view=rev
Log:
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)


Added:
    erp5/trunk/products/ERP5Security/ERP5UserFactory.py
    erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5UserFactory.zpt
Modified:
    erp5/trunk/products/ERP5/ERP5Site.py
    erp5/trunk/products/ERP5Security/__init__.py
    erp5/trunk/products/ERP5Type/Base.py

Modified: erp5/trunk/products/ERP5/ERP5Site.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/ERP5Site.py?rev=12286&r1=12285&r2=12286&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/ERP5Site.py (original)
+++ erp5/trunk/products/ERP5/ERP5Site.py Wed Jan 24 13:12:25 2007
@@ -1278,30 +1278,41 @@
     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',
-                                                    'IGroupEnumerationPlugin'))
-      p.acl_users.zodb_roles.manage_activateInterfaces(('IRoleEnumerationPlugin',
-                                                    'IRolesPlugin', 'IRoleAssignerPlugin'))
+      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'))
       # 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',
-                                                        'IUserEnumerationPlugin',))
+      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()

Added: erp5/trunk/products/ERP5Security/ERP5UserFactory.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/ERP5UserFactory.py?rev=12286&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Security/ERP5UserFactory.py (added)
+++ erp5/trunk/products/ERP5Security/ERP5UserFactory.py Wed Jan 24 13:12:25 2007
@@ -1,0 +1,204 @@
+##############################################################################
+#
+# 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)

Modified: erp5/trunk/products/ERP5Security/__init__.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/__init__.py?rev=12286&r1=12285&r2=12286&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Security/__init__.py (original)
+++ erp5/trunk/products/ERP5Security/__init__.py Wed Jan 24 13:12:25 2007
@@ -24,6 +24,7 @@
 import ERP5UserManager
 import ERP5GroupManager
 import ERP5RoleManager
+import ERP5UserFactory
 
 def mergedLocalRoles(object):
     """Returns a merging of object and its ancestors'
@@ -59,13 +60,14 @@
 registerMultiPlugin(ERP5UserManager.ERP5UserManager.meta_type)
 registerMultiPlugin(ERP5GroupManager.ERP5GroupManager.meta_type)
 registerMultiPlugin(ERP5RoleManager.ERP5RoleManager.meta_type)
+registerMultiPlugin(ERP5UserFactory.ERP5UserFactory.meta_type)
 
 def initialize(context):
 
     context.registerClass( ERP5UserManager.ERP5UserManager
                          , permission=ManageUsers
                          , constructors=(
-                            ERP5UserManager.manage_addERP5UserManagerForm, 
+                            ERP5UserManager.manage_addERP5UserManagerForm,
                             ERP5UserManager.addERP5UserManager, )
                          , visibility=None
                          , icon='www/portal.gif'
@@ -74,7 +76,7 @@
     context.registerClass( ERP5GroupManager.ERP5GroupManager
                          , permission=ManageGroups
                          , constructors=(
-                            ERP5GroupManager.manage_addERP5GroupManagerForm, 
+                            ERP5GroupManager.manage_addERP5GroupManagerForm,
                             ERP5GroupManager.addERP5GroupManager, )
                          , visibility=None
                          , icon='www/portal.gif'
@@ -88,3 +90,13 @@
                          , visibility=None
                          , icon='www/portal.gif'
                          )
+
+    context.registerClass( ERP5UserFactory.ERP5UserFactory
+                         , permission=ManageUsers
+                         , constructors=(
+                            ERP5UserFactory.manage_addERP5UserFactoryForm,
+                            ERP5UserFactory.addERP5UserFactory, )
+                         , visibility=None
+                         , icon='www/portal.gif'
+                         )
+

Added: erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5UserFactory.zpt
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5UserFactory.zpt?rev=12286&view=auto
==============================================================================
--- erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5UserFactory.zpt (added)
+++ erp5/trunk/products/ERP5Security/www/ERP5Security_addERP5UserFactory.zpt Wed Jan 24 13:12:25 2007
@@ -1,0 +1,45 @@
+<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>

Modified: erp5/trunk/products/ERP5Type/Base.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Base.py?rev=12286&r1=12285&r2=12286&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Base.py (original)
+++ erp5/trunk/products/ERP5Type/Base.py Wed Jan 24 13:12:25 2007
@@ -2262,8 +2262,8 @@
       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)




More information about the Erp5-report mailing list