Index: main/waeup.kofa/trunk/src/waeup/kofa/authentication.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/authentication.py	(revision 14669)
+++ main/waeup.kofa/trunk/src/waeup/kofa/authentication.py	(revision 14670)
@@ -645,2 +645,26 @@
                     pass
         return
+
+
+class UpdatePAUPlugin(grok.GlobalUtility):
+    """A plugin that updates a local PAU.
+
+    We insert an 'xmlrpc-credentials' PAU-plugin into a sites PAU if it is not
+    present already. There must be 'credentials' plugin registered already.
+
+    XXX: This Plugin fixes a shortcoming of waeup.kofa 1.5. Sites created or
+         updated afterwards do not need this plugin and it should be removed.
+    """
+    grok.implements(IKofaPluggable)
+    grok.name('site-pluggable-auth')
+
+    def setup(self, site, name, logger):
+        return
+
+    def update(self, site, name, logger):
+        pau = site.getSiteManager()['PluggableAuthentication']
+        if 'xmlrpc-credentials' in pau.credentialsPlugins:
+            return
+        plugins = list(pau.credentialsPlugins)
+        plugins.insert(plugins.index('credentials'), 'xmlrpc-credentials')
+        pau.credentialsPlugins = tuple(plugins)
Index: main/waeup.kofa/trunk/src/waeup/kofa/tests/test_authentication.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/tests/test_authentication.py	(revision 14669)
+++ main/waeup.kofa/trunk/src/waeup/kofa/tests/test_authentication.py	(revision 14670)
@@ -31,8 +31,9 @@
 from zope.securitypolicy.interfaces import IPrincipalRoleManager
 from waeup.kofa.testing import FunctionalTestCase, FunctionalLayer
+from waeup.kofa.app import University
 from waeup.kofa.authentication import (
     UserAuthenticatorPlugin, Account, KofaPrincipalInfo, FailedLoginInfo,
     get_principal_role_manager, UsersPlugin, KofaXMLRPCCredentialsPlugin,
-    setup_authentication)
+    setup_authentication, UpdatePAUPlugin)
 from waeup.kofa.interfaces import (
     IAuthPluginUtility, IUserAccount, IFailedLoginInfo, IKofaPrincipalInfo,
@@ -368,4 +369,15 @@
     pass
 
+
+def get_logger():
+    logger = logging.getLogger('waeup.test')
+    stream = StringIO()
+    handler = logging.StreamHandler(stream)
+    logger.setLevel(logging.DEBUG)
+    logger.propagate = False
+    logger.addHandler(handler)
+    return logger, stream
+
+
 class UsersPluginTests(unittest.TestCase):
 
@@ -375,13 +387,4 @@
         self.site['users'] = grok.Container()
         return
-
-    def get_logger(self):
-        logger = logging.getLogger('waeup.test')
-        stream = StringIO()
-        handler = logging.StreamHandler(stream)
-        logger.setLevel(logging.DEBUG)
-        logger.propagate = False
-        logger.addHandler(handler)
-        return logger, stream
 
     def test_ifaces(self):
@@ -395,10 +398,10 @@
         # make sure user accounts are updated properly.
         plugin = UsersPlugin()
-        logger, stream = self.get_logger()
+        logger, stream = get_logger()
         plugin.update(self.site, 'app', logger)
         stream.seek(0)
         self.assertEqual(stream.read(), '')
         self.site['users']['bob'] = FakeUserAccount()
-        logger, stream = self.get_logger()
+        logger, stream = get_logger()
         plugin.update(self.site, 'app', logger)
         stream.seek(0)
@@ -412,2 +415,42 @@
         self.assertTrue('attribute failed_logins added' in log_content)
         return
+
+
+class TestUpdatePAUPlugin(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def setUp(self):
+        super(TestUpdatePAUPlugin, self).setUp()
+        self.getRootFolder()['app'] = University()
+        self.site = self.getRootFolder()['app']
+
+    def tearDown(self):
+        clearSite()
+        super(TestUpdatePAUPlugin, self).tearDown()
+
+    def get_pau(self):
+        # the PAU is registered as a local utility in local site manager.
+        # the name is derived from class name.
+        pau = self.site.getSiteManager()['PluggableAuthentication']
+        assert pau is not None
+        return pau
+
+    def test_update_outdated(self):
+        # we can update outdated sites.
+        plugin = UpdatePAUPlugin()
+        logger, stream = get_logger()
+        pau = self.get_pau()
+        pau.credentialsPlugins = ('foo', 'credentials', 'bar')
+        plugin.update(self.site, 'xmlrpc-credentials', logger)
+        assert 'xmlrpc-credentials' in pau.credentialsPlugins
+        assert pau.credentialsPlugins.index('xmlrpc-credentials') == 1
+
+    def test_update_uptodate(self):
+        # we cope with already updated sites.
+        plugin = UpdatePAUPlugin()
+        logger, stream = get_logger()
+        pau = self.get_pau()
+        pau.credentialsPlugins = ('foo', 'xmlrpc-credentials', 'bar')
+        plugin.update(self.site, 'xmlrpc-credentials', logger)
+        assert pau.credentialsPlugins.count('xmlrpc-credentials') == 1
