[Checkins] SVN: Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/ Added updateAllLoginNames to PAS and the ZODBUserManager.
Maurits van Rees
cvs-admin at zope.org
Fri Jan 4 20:04:13 UTC 2013
Log message for revision 129017:
Added updateAllLoginNames to PAS and the ZODBUserManager.
This is now called when a relevant change is made to the login_transform property.
Changed:
U Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/PluggableAuthService.py
U Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/authservice.py
U Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/plugins.py
U Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/plugins/ZODBUserManager.py
-=-
Modified: Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/PluggableAuthService.py
===================================================================
--- Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/PluggableAuthService.py 2013-01-04 16:22:08 UTC (rev 129016)
+++ Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/PluggableAuthService.py 2013-01-04 20:04:12 UTC (rev 129017)
@@ -1105,6 +1105,16 @@
return
return transform
+ security.declarePrivate( '_setPropValue' )
+ def _setPropValue(self, id, value):
+ if id == 'login_transform':
+ orig_value = getattr(self, id)
+ super(PluggableAuthService, self)._setPropValue(id, value)
+ if id == 'login_transform' and value and value != orig_value:
+ logger.info("login_transform changed from %r to %r. "
+ "Updating existing login names.", orig_value, value)
+ self.updateAllLoginNames()
+
security.declarePublic( 'lower' )
def lower( self, value ):
""" Transform for login name.
@@ -1299,7 +1309,25 @@
else:
logger.info("login name changed to: %r", login_name)
+ security.declareProtected( ManageUsers, 'updateLoginName')
+ def updateAllLoginNames(self, quit_on_first_error=True):
+ """Update login names of all users to their canonical value.
+ This should be done after changing the login_transform
+ property of PAS.
+
+ You can set quit_on_first_error to False to report all errors
+ before quitting with an error. This can be useful if you want
+ to know how many problems there are, if any.
+ """
+ plugins = self._getOb('plugins')
+ updaters = plugins.listPlugins(IUpdateLoginNamePlugin)
+ for updater_id, updater in updaters:
+ # Note: do not swallow any exceptions here.
+ updater.updateAllLoginNames(
+ quit_on_first_error=quit_on_first_error)
+
+
classImplements( PluggableAuthService
, (IPluggableAuthService, IObjectManager, IPropertyManager)
)
Modified: Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/authservice.py
===================================================================
--- Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/authservice.py 2013-01-04 16:22:08 UTC (rev 129016)
+++ Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/authservice.py 2013-01-04 20:04:12 UTC (rev 129017)
@@ -223,7 +223,18 @@
"""Update own login name of authenticated user.
"""
+ def updateAllLoginNames(quit_on_first_error=True):
+ """Update login names of all users to their canonical value.
+ This should be done after changing the login_transform
+ property of PAS.
+
+ You can set quit_on_first_error to False to report all errors
+ before quitting with an error. This can be useful if you want
+ to know how many problems there are, if any.
+ """
+
+
# The IMutableUserFolder and IEnumerableFolder are not supported
# out-of-the-box by the pluggable authentication service. These
# interfaces describe contracts that other standard Zope user folders
Modified: Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/plugins.py
===================================================================
--- Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/plugins.py 2013-01-04 16:22:08 UTC (rev 129016)
+++ Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/interfaces/plugins.py 2013-01-04 20:04:12 UTC (rev 129017)
@@ -277,6 +277,17 @@
"""
+ def updateAllLoginNames(quit_on_first_error=True):
+ """Update login names of all users to their canonical value.
+
+ This should be done after changing the login_transform
+ property of PAS.
+
+ You can set quit_on_first_error to False to report all errors
+ before quitting with an error. This can be useful if you want
+ to know how many problems there are, if any.
+ """
+
class IValidationPlugin( Interface ):
""" Specify allowable values for user properties.
Modified: Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/plugins/ZODBUserManager.py
===================================================================
--- Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/plugins/ZODBUserManager.py 2013-01-04 16:22:08 UTC (rev 129016)
+++ Products.PluggableAuthService/branches/maurits-login-transform/Products/PluggableAuthService/plugins/ZODBUserManager.py 2013-01-04 20:04:12 UTC (rev 129017)
@@ -16,6 +16,7 @@
$Id$
"""
import copy
+import logging
try:
from hashlib import sha1 as sha
except:
@@ -48,7 +49,9 @@
from Products.PluggableAuthService.utils import createViewName
from Products.PluggableAuthService.utils import csrf_only
+logger = logging.getLogger('PluggableAuthService')
+
class IZODBUserManager(Interface):
""" Marker interface.
"""
@@ -329,6 +332,62 @@
self._login_to_userid[login_name] = user_id
self._userid_to_login[user_id] = login_name
+ security.declarePrivate('updateAllLoginNames')
+ def updateAllLoginNames(self, quit_on_first_error=True):
+ # Update all login names to their canonical value. This
+ # should be done after changing the login_transform property
+ # of pas. You can set quit_on_first_error to False to report
+ # all errors before quitting with an error. This can be
+ # useful if you want to know how many problems there are, if
+ # any.
+ pas = self._getPAS()
+ transform = pas._get_login_transform_method()
+ if not transform:
+ logger.warn("PAS has a non-existing, empty or wrong "
+ "login_transform property.")
+ return
+
+ # Make a fresh mapping, as we do not want to add or remove
+ # items to the original mapping while we are iterating over
+ # it.
+ new_login_to_userid = OOBTree()
+ errors = []
+ for old_login_name, user_id in self._login_to_userid.items():
+ new_login_name = transform(old_login_name)
+ if new_login_name in new_login_to_userid:
+ logger.error("User id %s: login name %r already taken.",
+ user_id, new_login_name)
+ errors.append(new_login_name)
+ if quit_on_first_error:
+ break
+ new_login_to_userid[new_login_name] = user_id
+ if new_login_name != old_login_name:
+ self._userid_to_login[user_id] = new_login_name
+ # Also, remove from the cache
+ view_name = createViewName('enumerateUsers', user_id)
+ self.ZCacheable_invalidate(view_name=view_name)
+ logger.info("User id %s: changed login name from %r to %r.",
+ user_id, old_login_name, new_login_name)
+
+ # If there were errors, we do not want to save any changes.
+ if errors:
+ logger.error("There were %d errors when updating login names. "
+ "quit_on_first_error was %r", len(errors),
+ quit_on_first_error)
+ # Make sure the exception we raise is not swallowed.
+ self._dont_swallow_my_exceptions = True
+ raise ValueError("Transformed login names are not unique: %s." %
+ ', '.join(errors))
+
+ # Make sure we did not lose any users.
+ assert(len(self._login_to_userid.keys())
+ == len(new_login_to_userid.keys()))
+ # Empty the main cache.
+ view_name = createViewName('enumerateUsers')
+ self.ZCacheable_invalidate(view_name=view_name)
+ # Store the new login mapping.
+ self._login_to_userid = new_login_to_userid
+
security.declarePrivate( 'removeUser' )
def removeUser( self, user_id ):
More information about the checkins
mailing list