Back to index

plone3  3.1.7
upgrade.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2004 Zope Corporation. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Visible Source 
00006 # License, Version 1.0 (ZVSL).  A copy of the ZVSL should accompany this 
00007 # distribution.
00008 #
00009 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00010 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00011 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00012 # FOR A PARTICULAR PURPOSE.
00013 #
00014 ##############################################################################
00015 """ External method for upgrading existing AccessControl.User.UserFolder
00016 
00017     NOTA BENE: Use at your own risk. This external method will replace a
00018     stock User Folder (AccessControl.User.UserFolder) with a
00019     PluggableAuthService consisting of the following:
00020 
00021         - ZODBUserManager with a record for each existing User
00022           (AccessControl.User.User)
00023 
00024         - ZODBRoleManger with a record for each existing role present
00025           in the __ac_roles__ attribute of the container (minus Anonymous
00026           and Authenticated)
00027 
00028     Each migrated user will be assigned the global roles they have in the
00029     previous acl_users record.
00030 
00031 $Id: upgrade.py 73612 2007-03-25 15:39:50Z shh $
00032 """
00033 import logging
00034 import transaction
00035 
00036 def _write(response, tool, message):
00037     logger = logging.getLogger('PluggableAuthService.upgrade.%s' % tool)
00038     logger.info(message)
00039     if response is not None:
00040         response.write(message)
00041 
00042 def _replaceUserFolder(self, RESPONSE=None):
00043     """replaces the old acl_users folder with a PluggableAuthService,
00044     preserving users and passwords, if possible
00045     """
00046     from Acquisition import aq_base
00047     from Products.PluggableAuthService.PluggableAuthService \
00048         import PluggableAuthService, _PLUGIN_TYPE_INFO
00049     from Products.PluginRegistry.PluginRegistry import PluginRegistry
00050     from Products.PluggableAuthService.plugins.ZODBUserManager \
00051         import ZODBUserManager
00052     from Products.PluggableAuthService.plugins.ZODBRoleManager \
00053         import ZODBRoleManager
00054     from Products.PluggableAuthService.interfaces.plugins \
00055          import IAuthenticationPlugin, IUserEnumerationPlugin
00056     from Products.PluggableAuthService.interfaces.plugins \
00057         import IRolesPlugin, IRoleEnumerationPlugin, IRoleAssignerPlugin
00058 
00059     if getattr( aq_base(self), '__allow_groups__', None ):
00060         if self.__allow_groups__.__class__ is PluggableAuthService:
00061             _write( RESPONSE
00062                   , 'replaceUserFolder'
00063                   , 'Already replaced this user folder\n' )
00064             return
00065 
00066         # Capture all the user info from the previous user folder,
00067         # then delete it.
00068         old_acl = self.__allow_groups__
00069         user_map = []
00070         for user_name in old_acl.getUserNames():
00071             old_user = old_acl.getUser( user_name )
00072             _write( RESPONSE
00073                   , 'replaceRootUserFolder'
00074                   , 'Capturing user info for %s\n' % user_name )
00075             user_map.append(
00076                 { 'login' : user_name,
00077                   'password' : old_user._getPassword(),
00078                   'roles' : old_user.getRoles() }
00079                 )
00080         self._delObject( 'acl_users' )
00081 
00082         # Create the new PluggableAuthService, and re-populate from
00083         # the captured data
00084         _pas = self.manage_addProduct['PluggableAuthService']
00085         new_pas = _pas.addPluggableAuthService()
00086         new_acl = self.acl_users
00087 
00088         user_folder = ZODBUserManager( 'users' )
00089         new_acl._setObject( 'users', user_folder )
00090         role_manager = ZODBRoleManager( 'roles' )
00091         new_acl._setObject( 'roles', role_manager )
00092 
00093         plugins = getattr( new_acl, 'plugins' )
00094         plugins.activatePlugin( IAuthenticationPlugin, 'users' )
00095         plugins.activatePlugin( IUserEnumerationPlugin, 'users' )
00096         plugins.activatePlugin( IRolesPlugin, 'roles' )
00097         plugins.activatePlugin( IRoleEnumerationPlugin, 'roles' )
00098         plugins.activatePlugin( IRoleAssignerPlugin, 'roles' )
00099         for user_dict in user_map:
00100             _write( RESPONSE
00101                   , 'replaceRootUserFolder'
00102                   , 'Translating user %s\n' % user_name )
00103             login = user_dict['login']
00104             password = user_dict['password']
00105             roles = user_dict['roles']
00106 
00107             _migrate_user( new_acl, login, password, roles )
00108         _write( RESPONSE
00109               , 'replaceRootUserFolder'
00110               , 'Replaced root acl_users with PluggableAuthService\n' )
00111 
00112     transaction.savepoint(True)
00113 
00114 def _migrate_user( pas, login, password, roles ):
00115 
00116     from AccessControl import AuthEncoding
00117 
00118     if AuthEncoding.is_encrypted( password ):
00119         pas.users._user_passwords[ login ] = password
00120         pas.users._login_to_userid[ login ] = login
00121         pas.users._userid_to_login[ login ] = login
00122     else:
00123         pas.users.addUser( login, login, password )
00124 
00125     new_user = pas.getUser( login )
00126     for role_id in roles:
00127         if role_id not in ['Authenticated', 'Anonymous']:
00128             pas.roles.assignRoleToPrincipal( role_id,
00129                                              new_user.getId() )
00130 
00131 def _upgradeLocalRoleAssignments(self, RESPONSE=None):
00132     """ upgrades the __ac_local_roles__ attributes on objects to account
00133         for a move to using the PluggableAuthService.
00134     """
00135     from Acquisition import aq_base
00136 
00137     seen = {}
00138 
00139     def descend(user_folder, obj):
00140         path = obj.getPhysicalPath()
00141         if path not in seen:
00142             # get __ac_local_roles__, break it apart and refashion it
00143             # with new spellings.
00144             seen[path] = 1
00145             if getattr( aq_base( obj ), '__ac_local_roles__', None ):
00146                 if not callable(obj.__ac_local_roles__):
00147                     new_map = {}
00148                     map = obj.__ac_local_roles__
00149                     for key in map.keys():
00150                         new_principals = user_folder.searchPrincipals(id=key)
00151                         if not new_principals:
00152                             _write(
00153                                 RESPONSE
00154                               , 'upgradeLocalRoleAssignmentsFromRoot'
00155                               , '  Ignoring map for unknown principal %s\n'
00156                                 % key )
00157                             new_map[key] = map[key]
00158                             continue
00159                         npid = new_principals[0]['id']
00160                         new_map[npid] = map[key]
00161                         _write( RESPONSE
00162                               , 'upgradeLocalRoleAssignmentsFromRoot'
00163                               , '  Translated %s to %s\n' % ( key, npid ) )
00164                         _write( RESPONSE
00165                               , 'upgradeLocalRoleAssignmentsFromRoot'
00166                               , '  Assigned roles %s to %s\n' % ( map[key]
00167                                                                 , npid ) )
00168                     obj.__ac_local_roles__ = new_map
00169                     _write( RESPONSE
00170                           , 'upgradeLocalRoleAssignmentsFromRoot'
00171                           , ( 'Local Roles map changed for (%s)\n'
00172                               % '/'.join(path) ) )
00173             if (len(seen) % 100 ) == 0:
00174                 transaction.savepoint(True)
00175                 _write( RESPONSE
00176                       , 'upgradeLocalRoleAssignmentsFromRoot'
00177                       , "  -- Set savepoint at object # %d\n" % len( seen ) )
00178             if getattr(aq_base(obj), 'isPrincipiaFolderish', 0):
00179                 for o in obj.objectValues():
00180                     descend(user_folder, o)
00181 
00182     if getattr( self, '_upgraded_acl_users', None ):
00183         _write( RESPONSE
00184               , '_upgradeLocalRoleAssignments'
00185               , 'Local role assignments have already been updated.\n' )
00186         return
00187 
00188     descend(self.acl_users, self)
00189 
00190     transaction.savepoint(True)
00191 
00192 # External Method to use
00193 
00194 def replace_acl_users(self, RESPONSE=None):
00195     _replaceUserFolder(self, RESPONSE)
00196     _upgradeLocalRoleAssignments(self, RESPONSE)
00197     self._upgraded_acl_users = 1
00198     _write( RESPONSE
00199           , 'replace_acl_users'
00200           , 'Root acl_users has been replaced,'
00201             ' and local role assignments updated.\n' )