[Checkins] SVN: zope.password/ Split off passwod managers from zope.app.authentication.

Dan Korostelev nadako at gmail.com
Fri Mar 6 06:47:05 EST 2009


Log message for revision 97560:
  Split off passwod managers from zope.app.authentication.

Changed:
  A   zope.password/
  A   zope.password/trunk/
  U   zope.password/trunk/CHANGES.txt
  U   zope.password/trunk/README.txt
  U   zope.password/trunk/buildout.cfg
  U   zope.password/trunk/setup.py
  D   zope.password/trunk/src/zope/app/
  A   zope.password/trunk/src/zope/password/
  U   zope.password/trunk/src/zope/password/README.txt
  D   zope.password/trunk/src/zope/password/SETUP.cfg
  U   zope.password/trunk/src/zope/password/__init__.py
  D   zope.password/trunk/src/zope/password/authentication.py
  D   zope.password/trunk/src/zope/password/browser/
  D   zope.password/trunk/src/zope/password/configure.zcml
  A   zope.password/trunk/src/zope/password/configure.zcml
  D   zope.password/trunk/src/zope/password/ftesting.zcml
  D   zope.password/trunk/src/zope/password/ftpplugins.py
  D   zope.password/trunk/src/zope/password/ftpplugins.zcml
  D   zope.password/trunk/src/zope/password/generic.py
  D   zope.password/trunk/src/zope/password/groupfolder.py
  D   zope.password/trunk/src/zope/password/groupfolder.txt
  D   zope.password/trunk/src/zope/password/groupfolder.zcml
  D   zope.password/trunk/src/zope/password/httpplugins.py
  D   zope.password/trunk/src/zope/password/httpplugins.zcml
  D   zope.password/trunk/src/zope/password/i18n.py
  D   zope.password/trunk/src/zope/password/idpicker.py
  U   zope.password/trunk/src/zope/password/interfaces.py
  U   zope.password/trunk/src/zope/password/password.py
  D   zope.password/trunk/src/zope/password/password.zcml
  D   zope.password/trunk/src/zope/password/placelesssetup.py
  D   zope.password/trunk/src/zope/password/principalfolder.py
  D   zope.password/trunk/src/zope/password/principalfolder.txt
  D   zope.password/trunk/src/zope/password/principalfolder.zcml
  D   zope.password/trunk/src/zope/password/session.py
  D   zope.password/trunk/src/zope/password/session.zcml
  D   zope.password/trunk/src/zope/password/testing.py
  A   zope.password/trunk/src/zope/password/testing.py
  U   zope.password/trunk/src/zope/password/tests.py
  D   zope.password/trunk/src/zope/password/vocabulary.py
  D   zope.password/trunk/src/zope/password/vocabulary.txt
  D   zope.password/trunk/src/zope/password/zope.app.authentication-configure.zcml

-=-
Modified: zope.password/trunk/CHANGES.txt
===================================================================
--- zope.app.authentication/trunk/CHANGES.txt	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/CHANGES.txt	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,62 +1,10 @@
 =======
-Changes
+CHANGES
 =======
 
-3.5.0a3 (unreleased)
---------------------
-
-- ...
-
-3.5.0a2 (2009-02-01)
---------------------
-
-* Make old encoded passwords really work.
-
-3.5.0a1 (2009-01-31)
---------------------
-
-* Use ``zope.container`` instead of ``zope.app.container``.
-
-* Encoded passwords are now stored with a prefix ({MD5}, {SHA1},
-  {SSHA}) indicating the used encoding schema. Old (encoded) passwords
-  can still be used.
-
-* Add an SSHA password manager that is compatible with standard LDAP
-  passwords. As this encoding gives better security agains dictionary
-  attacks, users are encouraged to switch to this new password schema.
-
-* InternalPrincipal now uses SSHA password manager by default.
-
-3.4.4 (2008-12-12)
+3.5.0 (unreleased)
 ------------------
 
-* Depend on zope.session instead of zope.app.session. The first one
-  currently has all functionality we need.
-* Fix deprecation warnings for ``md5`` and ``sha`` on Python 2.6.
-
-3.4.3 (2008-08-07)
-------------------
-
-* No changes. Retag for correct release on PyPI.
-
-3.4.2 (2008-07-09)
--------------------
-
-* Make it compatible with zope.app.container 3.6.1 and 3.5.4 changes,
-  Changed ``super(BTreeContainer, self).__init__()`` to 
-  ``super(GroupFolder, self).__init__()`` in ``GroupFolder`` class.
-
-3.4.1 (2007-10-24)
-------------------
-
-* Avoid deprecation warning.
-
-3.4.0 (2007-10-11)
-------------------
-
-* Updated package meta-data.
-
-3.4.0b1 (2007-09-27)
---------------------
-
-* First release independent of Zope.
+First release. This package was splitted off from ``zope.app.authentication``
+to separate password manager functionality that is greatly re-usable without
+any bit of ``zope.app.authentication`` and to reduce its dependencies.

Modified: zope.password/trunk/README.txt
===================================================================
--- zope.app.authentication/trunk/README.txt	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/README.txt	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,6 +1 @@
-==========================
- Pluggable Authentication
-==========================
-
-This package provides a flexible and pluggable authentication utility for Zope
-3. Several common plugins are provided.
+See the src/zope/password/README.txt file.

Modified: zope.password/trunk/buildout.cfg
===================================================================
--- zope.app.authentication/trunk/buildout.cfg	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/buildout.cfg	2009-03-06 11:47:04 UTC (rev 97560)
@@ -4,4 +4,4 @@
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = zope.app.authentication [test]
+eggs = zope.password [test]

Modified: zope.password/trunk/setup.py
===================================================================
--- zope.app.authentication/trunk/setup.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/setup.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2006 Zope Corporation and Contributors.
+# Copyright (c) 2009 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -11,36 +11,24 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Setup for zope.app.authentication package
+"""Setup for zope.password package
 
 $Id$
 """
-import os
 from setuptools import setup, find_packages
 
-def read(*rnames):
-    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
 
-setup(name='zope.app.authentication',
-      version = '3.5.0a3dev',
+setup(name='zope.password',
+      version='3.5.0dev',
       author='Zope Corporation and Contributors',
       author_email='zope-dev at zope.org',
-      description='Pluggable Authentication Utility',
+      description='Password encoding and checking utilities',
       long_description=(
-        read('README.txt')
+        open('README.txt').read(),
         + '\n\n' +
-        'Detailed Documentation\n' +
-        '----------------------\n'
-        + '\n' +
-        read('src', 'zope', 'app', 'authentication', 'README.txt')
-        + '\n\n' +
-        read('src', 'zope', 'app', 'authentication', 'principalfolder.txt')
-        + '\n\n' +
-        read('src', 'zope', 'app', 'authentication', 'vocabulary.txt')
-        + '\n\n' +
-        read('CHANGES.txt')
+        open('CHANGES.txt').read()
         ),
-      url='http://pypi.python.org/pypi/zope.app.authentication',
+      url='http://pypi.python.org/pypi/zope.password',
       license='ZPL 2.1',
       classifiers = [
           'Development Status :: 5 - Production/Stable',
@@ -52,33 +40,13 @@
           'Operating System :: OS Independent',
           'Topic :: Internet :: WWW/HTTP',
           'Framework :: Zope3'],
-      keywords='zope3 authentication pluggable principal group',
+      keywords='zope3 zope authentication password',
       packages=find_packages('src'),
       package_dir = {'': 'src'},
-      extras_require=dict(test=['zope.app.testing',
-                                'zope.app.securitypolicy',
-                                'zope.app.zcmlfiles',
-                                'zope.securitypolicy',
-                                'zope.testbrowser']),
-      namespace_packages=['zope', 'zope.app'],
+      extras_require=dict(test=['zope.testing']),
+      namespace_packages=['zope'],
       install_requires=['setuptools',
-                        'zope.app.component',
-                        'zope.app.container',
-                        'zope.app.form',
-                        'zope.app.security',
-                        'zope.dublincore',
-                        'zope.event',
-                        'zope.exceptions',
-                        'zope.i18n',
-                        'zope.i18nmessageid',
                         'zope.interface',
-                        'zope.location',
-                        'zope.publisher',
-                        'zope.schema',
-                        'zope.security',
-                        'zope.session',
-                        'zope.traversing',
-                        'ZODB3',
                         ],
       include_package_data = True,
       zip_safe = False,

Modified: zope.password/trunk/src/zope/password/README.txt
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/README.txt	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/README.txt	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,822 +1,38 @@
-================================
-Pluggable-Authentication Utility
-================================
+================
+Password Manager
+================
 
-The Pluggable-Authentication Utility (PAU) provides a framework for
-authenticating principals and associating information with them. It uses
-plugins and subscribers to get its work done.
+This package provides a password manager mechanism. Password manager is an
+utility object that can encode and check encoded passwords. Beyond the generic
+interface, this package also provides four implementations:
 
-For a pluggable-authentication utility to be used, it should be
-registered as a utility providing the
-`zope.app.security.interfaces.IAuthentication` interface.
+ * PlainTextPasswordManager - the most simple and the less secure one. It does
+   not do any password encoding and simply checks password by string equality.
+   It's useful in tests or as a base class for more secure implementations.
 
-Authentication
---------------
+ * MD5PasswordManager - a password manager that uses MD5 algorithm to encode
+   passwords. It adds salt to the encoded password, but the salt is not used
+   for encoding the password itself, so the use of salt in it is purely
+   cosmetical. It's generally weak against dictionary attacks.
+ 
+ * SHA1PasswordManager - a password manager that uses SHA1 algorithm to encode
+   passwords. It has the same salt weakness as the MD5PasswordManager.
+ 
+ * SSHAPasswordManager - the most secure password manager that is strong against
+   dictionary attacks. It's basically SHA1-encoding password manager which also
+   incorporates a salt into the password when encoding it. This password manager
+   is compatible with passwords used in LDAP databases.
 
-The primary job of PAU is to authenticate principals. It uses two types of
-plug-ins in its work:
+It is strongly recommended to use SSHAPasswordManager, as it's the most secure
+one.
 
-  - Credentials Plugins
+Usage
+-----
 
-  - Authenticator Plugins
+It's very easy to use password managers. The ``zope.password.interfaces.IPasswordManager``
+interface defines only two methods:
 
-Credentials plugins are responsible for extracting user credentials from a
-request. A credentials plugin may in some cases issue a 'challenge' to obtain
-credentials. For example, a 'session' credentials plugin reads credentials
-from a session (the "extraction"). If it cannot find credentials, it will
-redirect the user to a login form in order to provide them (the "challenge").
-
-Authenticator plugins are responsible for authenticating the credentials
-extracted by a credentials plugin. They are also typically able to create
-principal objects for credentials they successfully authenticate.
-
-Given a request object, the PAU returns a principal object, if it can. The PAU
-does this by first iterateing through its credentials plugins to obtain a
-set of credentials. If it gets credentials, it iterates through its
-authenticator plugins to authenticate them.
-
-If an authenticator succeeds in authenticating a set of credentials, the PAU
-uses the authenticator to create a principal corresponding to the credentials.
-The authenticator notifies subscribers if an authenticated principal is
-created. Subscribers are responsible for adding data, especially groups, to
-the principal. Typically, if a subscriber adds data, it should also add
-corresponding interface declarations.
-
-Simple Credentials Plugin
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To illustrate, we'll create a simple credentials plugin::
-
-  >>> from zope import interface
-  >>> from zope.app.authentication import interfaces
-
-  >>> class MyCredentialsPlugin(object):
-  ...
-  ...     interface.implements(interfaces.ICredentialsPlugin)
-  ...
-  ...     def extractCredentials(self, request):
-  ...         return request.get('credentials')
-  ...
-  ...     def challenge(self, request):
-  ...         pass # challenge is a no-op for this plugin
-  ...
-  ...     def logout(self, request):
-  ...         pass # logout is a no-op for this plugin
-
-As a plugin, MyCredentialsPlugin needs to be registered as a named utility::
-
-  >>> myCredentialsPlugin = MyCredentialsPlugin()
-  >>> provideUtility(myCredentialsPlugin, name='My Credentials Plugin')
-
-Simple Authenticator Plugin
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Next we'll create a simple authenticator plugin. For our plugin, we'll need
-an implementation of IPrincipalInfo::
-
-  >>> class PrincipalInfo(object):
-  ...
-  ...     interface.implements(interfaces.IPrincipalInfo)
-  ...
-  ...     def __init__(self, id, title, description):
-  ...         self.id = id
-  ...         self.title = title
-  ...         self.description = description
-  ...
-  ...     def __repr__(self):
-  ...         return 'PrincipalInfo(%r)' % self.id
-
-Our authenticator uses this type when it creates a principal info::
-
-  >>> class MyAuthenticatorPlugin(object):
-  ...
-  ...     interface.implements(interfaces.IAuthenticatorPlugin)
-  ...
-  ...     def authenticateCredentials(self, credentials):
-  ...         if credentials == 'secretcode':
-  ...             return PrincipalInfo('bob', 'Bob', '')
-  ...
-  ...     def principalInfo(self, id):
-  ...         pass # plugin not currently supporting search
-
-As with the credentials plugin, the authenticator plugin must be registered
-as a named utility::
-
-  >>> myAuthenticatorPlugin = MyAuthenticatorPlugin()
-  >>> provideUtility(myAuthenticatorPlugin, name='My Authenticator Plugin')
-
-Principal Factories
-~~~~~~~~~~~~~~~~~~~
-
-While authenticator plugins provide principal info, they are not responsible
-for creating principals. This function is performed by factory adapters. For
-these tests we'll borrow some factories from the principal folder::
-
-  >>> from zope.app.authentication import principalfolder
-  >>> provideAdapter(principalfolder.AuthenticatedPrincipalFactory)
-  >>> provideAdapter(principalfolder.FoundPrincipalFactory)
-
-For more information on these factories, see their docstrings.
-
-Configuring a PAU
-~~~~~~~~~~~~~~~~~
-
-Finally, we'll create the PAU itself::
-
-  >>> from zope.app import authentication
-  >>> pau = authentication.PluggableAuthentication('xyz_')
-
-and configure it with the two plugins::
-
-  >>> pau.credentialsPlugins = ('My Credentials Plugin', )
-  >>> pau.authenticatorPlugins = ('My Authenticator Plugin', )
-
-Using the PAU to Authenticate
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We can now use the PAU to authenticate a sample request::
-
-  >>> from zope.publisher.browser import TestRequest
-  >>> print pau.authenticate(TestRequest())
-  None
-
-In this case, we cannot authenticate an empty request. In the same way, we
-will not be able to authenticate a request with the wrong credentials::
-
-  >>> print pau.authenticate(TestRequest(credentials='let me in!'))
-  None
-
-However, if we provide the proper credentials::
-
-  >>> request = TestRequest(credentials='secretcode')
-  >>> principal = pau.authenticate(request)
-  >>> principal
-  Principal('xyz_bob')
-
-we get an authenticated principal.
-
-Authenticated Principal Creates Events
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We can verify that the appropriate event was published::
-
-  >>> [event] = getEvents(interfaces.IAuthenticatedPrincipalCreated)
-  >>> event.principal is principal
-  True
-  >>> event.info
-  PrincipalInfo('bob')
-  >>> event.request is request
-  True
-
-The info object has the id, title, and description of the principal.  The info
-object is also generated by the authenticator plugin, so the plugin may
-itself have provided additional information on the info object::
-
-  >>> event.info.title
-  'Bob'
-  >>> event.info.id # does not include pau prefix
-  'bob'
-  >>> event.info.description
-  ''
-
-It is also decorated with two other attributes, credentialsPlugin and
-authenticatorPlugin: these are the plugins used to extract credentials for and
-authenticate this principal.  These attributes can be useful for subscribers
-that want to react to the plugins used.  For instance, subscribers can
-determine that a given credential plugin does or does not support logout, and
-provide information usable to show or hide logout user interface::
-
-  >>> event.info.credentialsPlugin is myCredentialsPlugin
-  True
-  >>> event.info.authenticatorPlugin is myAuthenticatorPlugin
-  True
-
-Normally, we provide subscribers to these events that add additional
-information to the principal. For example, we'll add one that sets
-the title::
-
-  >>> def add_info(event):
-  ...     event.principal.title = event.info.title
-  >>> subscribe([interfaces.IAuthenticatedPrincipalCreated], None, add_info)
-
-Now, if we authenticate a principal, its title is set::
-
-  >>> principal = pau.authenticate(request)
-  >>> principal.title
-  'Bob'
-
-Multiple Authenticator Plugins
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The PAU works with multiple authenticator plugins. It uses each plugin, in the
-order specified in the PAU's authenticatorPlugins attribute, to authenticate
-a set of credentials.
-
-To illustrate, we'll create another authenticator::
-
-  >>> class MyAuthenticatorPlugin2(MyAuthenticatorPlugin):
-  ...
-  ...     def authenticateCredentials(self, credentials):
-  ...         if credentials == 'secretcode':
-  ...             return PrincipalInfo('black', 'Black Spy', '')
-  ...         elif credentials == 'hiddenkey':
-  ...             return PrincipalInfo('white', 'White Spy', '')
-
-  >>> provideUtility(MyAuthenticatorPlugin2(), name='My Authenticator Plugin 2')
-
-If we put it before the original authenticator::
-
-  >>> pau.authenticatorPlugins = (
-  ...     'My Authenticator Plugin 2',
-  ...     'My Authenticator Plugin')
-
-Then it will be given the first opportunity to authenticate a request::
-
-  >>> pau.authenticate(TestRequest(credentials='secretcode'))
-  Principal('xyz_black')
-
-If neither plugins can authenticate, pau returns None::
-
-  >>> print pau.authenticate(TestRequest(credentials='let me in!!'))
-  None
-
-When we change the order of the authenticator plugins::
-
-  >>> pau.authenticatorPlugins = (
-  ...     'My Authenticator Plugin',
-  ...     'My Authenticator Plugin 2')
-
-we see that our original plugin is now acting first::
-
-  >>> pau.authenticate(TestRequest(credentials='secretcode'))
-  Principal('xyz_bob')
-
-The second plugin, however, gets a chance to authenticate if first does not::
-
-  >>> pau.authenticate(TestRequest(credentials='hiddenkey'))
-  Principal('xyz_white')
-
-Multiple Credentials Plugins
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As with with authenticators, we can specify multiple credentials plugins. To
-illustrate, we'll create a credentials plugin that extracts credentials from
-a request form::
-
-  >>> class FormCredentialsPlugin:
-  ...
-  ...     interface.implements(interfaces.ICredentialsPlugin)
-  ...
-  ...     def extractCredentials(self, request):
-  ...         return request.form.get('my_credentials')
-  ...
-  ...     def challenge(self, request):
-  ...         pass
-  ...
-  ...     def logout(request):
-  ...         pass
-
-  >>> provideUtility(FormCredentialsPlugin(),
-  ...                name='Form Credentials Plugin')
-
-and insert the new credentials plugin before the existing plugin::
-
-  >>> pau.credentialsPlugins = (
-  ...     'Form Credentials Plugin',
-  ...     'My Credentials Plugin')
-
-The PAU will use each plugin in order to try and obtain credentials from a
-request::
-
-  >>> pau.authenticate(TestRequest(credentials='secretcode',
-  ...                              form={'my_credentials': 'hiddenkey'}))
-  Principal('xyz_white')
-
-In this case, the first credentials plugin succeeded in getting credentials
-from the form and the second authenticator was able to authenticate the
-credentials. Specifically, the PAU went through these steps:
-
- - Get credentials using 'Form Credentials Plugin'
-
- - Got 'hiddenkey' credentials using 'Form Credentials Plugin', try to
-   authenticate using 'My Authenticator Plugin'
-
- - Failed to authenticate 'hiddenkey' with 'My Authenticator Plugin', try
-   'My Authenticator Plugin 2'
-
- - Succeeded in authenticating with 'My Authenticator Plugin 2'
-
-Let's try a different scenario::
-
-  >>> pau.authenticate(TestRequest(credentials='secretcode'))
-  Principal('xyz_bob')
-
-In this case, the PAU went through these steps::
-
-  - Get credentials using 'Form Credentials Plugin'
-
-  - Failed to get credentials using 'Form Credentials Plugin', try
-    'My Credentials Plugin'
-
-  - Got 'scecretcode' credentials using 'My Credentials Plugin', try to
-    authenticate using 'My Authenticator Plugin'
-
-  - Succeeded in authenticating with 'My Authenticator Plugin'
-
-Let's try a slightly more complex scenario::
-
-  >>> pau.authenticate(TestRequest(credentials='hiddenkey',
-  ...                              form={'my_credentials': 'bogusvalue'}))
-  Principal('xyz_white')
-
-This highlights PAU's ability to use multiple plugins for authentication:
-
-  - Get credentials using 'Form Credentials Plugin'
-
-  - Got 'bogusvalue' credentials using 'Form Credentials Plugin', try to
-    authenticate using 'My Authenticator Plugin'
-
-  - Failed to authenticate 'boguskey' with 'My Authenticator Plugin', try
-    'My Authenticator Plugin 2'
-
-  - Failed to authenticate 'boguskey' with 'My Authenticator Plugin 2' --
-    there are no more authenticators to try, so lets try the next credentials
-    plugin for some new credentials
-
-  - Get credentials using 'My Credentials Plugin'
-
-  - Got 'hiddenkey' credentials using 'My Credentials Plugin', try to
-    authenticate using 'My Authenticator Plugin'
-
-  - Failed to authenticate 'hiddenkey' using 'My Authenticator Plugin', try
-    'My Authenticator Plugin 2'
-
-  - Succeeded in authenticating with 'My Authenticator Plugin 2' (shouts and
-    cheers!)
-
-
-Principal Searching
--------------------
-
-As a component that provides IAuthentication, a PAU lets you lookup a
-principal with a principal ID. The PAU looks up a principal by delegating to
-its authenticators. In our example, none of the authenticators implement this
-search capability, so when we look for a principal::
-
-  >>> print pau.getPrincipal('xyz_bob')
-  Traceback (most recent call last):
-  PrincipalLookupError: bob
-
-  >>> print pau.getPrincipal('white')
-  Traceback (most recent call last):
-  PrincipalLookupError: white
-
-  >>> print pau.getPrincipal('black')
-  Traceback (most recent call last):
-  PrincipalLookupError: black
-
-For a PAU to support search, it needs to be configured with one or more
-authenticator plugins that support search. To illustrate, we'll create a new
-authenticator::
-
-  >>> class SearchableAuthenticatorPlugin:
-  ...
-  ...     interface.implements(interfaces.IAuthenticatorPlugin)
-  ...
-  ...     def __init__(self):
-  ...         self.infos = {}
-  ...         self.ids = {}
-  ...
-  ...     def principalInfo(self, id):
-  ...         return self.infos.get(id)
-  ...
-  ...     def authenticateCredentials(self, credentials):
-  ...         id = self.ids.get(credentials)
-  ...         if id is not None:
-  ...             return self.infos[id]
-  ...
-  ...     def add(self, id, title, description, credentials):
-  ...         self.infos[id] = PrincipalInfo(id, title, description)
-  ...         self.ids[credentials] = id
-
-This class is typical of an authenticator plugin. It can both authenticate
-principals and find principals given a ID. While there are cases
-where an authenticator may opt to not perform one of these two functions, they
-are less typical.
-
-As with any plugin, we need to register it as a utility::
-
-  >>> searchable = SearchableAuthenticatorPlugin()
-  >>> provideUtility(searchable, name='Searchable Authentication Plugin')
-
-We'll now configure the PAU to use only the searchable authenticator::
-
-  >>> pau.authenticatorPlugins = ('Searchable Authentication Plugin',)
-
-and add some principals to the authenticator::
-
-  >>> searchable.add('bob', 'Bob', 'A nice guy', 'b0b')
-  >>> searchable.add('white', 'White Spy', 'Sneaky', 'deathtoblack')
-
-Now when we ask the PAU to find a principal::
-
-  >>> pau.getPrincipal('xyz_bob')
-  Principal('xyz_bob')
-
-but only those it knows about::
-
-  >>> print pau.getPrincipal('black')
-  Traceback (most recent call last):
-  PrincipalLookupError: black
-
-Found Principal Creates Events
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As evident in the authenticator's 'createFoundPrincipal' method (see above),
-a FoundPrincipalCreatedEvent is published when the authenticator finds a
-principal on behalf of PAU's 'getPrincipal'::
-
-  >>> clearEvents()
-  >>> principal = pau.getPrincipal('xyz_white')
-  >>> principal
-  Principal('xyz_white')
-
-  >>> [event] = getEvents(interfaces.IFoundPrincipalCreated)
-  >>> event.principal is principal
-  True
-  >>> event.info
-  PrincipalInfo('white')
-
-The info has an authenticatorPlugin, but no credentialsPlugin, since none was
-used::
-
-  >>> event.info.credentialsPlugin is None
-  True
-  >>> event.info.authenticatorPlugin is searchable
-  True
-
-As we have seen with authenticated principals, it is common to subscribe to
-principal created events to add information to the newly created principal.
-In this case, we need to subscribe to IFoundPrincipalCreated events::
-
-  >>> subscribe([interfaces.IFoundPrincipalCreated], None, add_info)
-
-Now when a principal is created as a result of a search, it's title and
-description will be set (by the add_info handler function).
-
-Multiple Authenticator Plugins
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As with the other operations we've seen, the PAU uses multiple plugins to
-find a principal. If the first authenticator plugin can't find the requested
-principal, the next plugin is used, and so on.
-
-To illustrate, we'll create and register a second searchable authenticator::
-
-  >>> searchable2 = SearchableAuthenticatorPlugin()
-  >>> provideUtility(searchable2, name='Searchable Authentication Plugin 2')
-
-and add a principal to it::
-
-  >>> searchable.add('black', 'Black Spy', 'Also sneaky', 'deathtowhite')
-
-When we configure the PAU to use both searchable authenticators (note the
-order)::
-
-  >>> pau.authenticatorPlugins = (
-  ...     'Searchable Authentication Plugin 2',
-  ...     'Searchable Authentication Plugin')
-
-we see how the PAU uses both plugins::
-
-  >>> pau.getPrincipal('xyz_white')
-  Principal('xyz_white')
-
-  >>> pau.getPrincipal('xyz_black')
-  Principal('xyz_black')
-
-If more than one plugin know about the same principal ID, the first plugin is
-used and the remaining are not delegated to. To illustrate, we'll add
-another principal with the same ID as an existing principal::
-
-  >>> searchable2.add('white', 'White Rider', '', 'r1der')
-  >>> pau.getPrincipal('xyz_white').title
-  'White Rider'
-
-If we change the order of the plugins::
-
-  >>> pau.authenticatorPlugins = (
-  ...     'Searchable Authentication Plugin',
-  ...     'Searchable Authentication Plugin 2')
-
-we get a different principal for ID 'white'::
-
-  >>> pau.getPrincipal('xyz_white').title
-  'White Spy'
-
-
-Issuing a Challenge
--------------------
-
-Part of PAU's IAuthentication contract is to challenge the user for
-credentials when its 'unauthorized' method is called. The need for this
-functionality is driven by the following use case:
-
-  - A user attempts to perform an operation he is not authorized to perform.
-
-  - A handler responds to the unauthorized error by calling IAuthentication
-    'unauthorized'.
-
-  - The authentication component (in our case, a PAU) issues a challenge to
-    the user to collect new credentials (typically in the form of logging in
-    as a new user).
-
-The PAU handles the credentials challenge by delegating to its credentials
-plugins.
-
-Currently, the PAU is configured with the credentials plugins that don't
-perform any action when asked to challenge (see above the 'challenge' methods).
-
-To illustrate challenges, we'll subclass an existing credentials plugin and
-do something in its 'challenge'::
-
-  >>> class LoginFormCredentialsPlugin(FormCredentialsPlugin):
-  ...
-  ...     def __init__(self, loginForm):
-  ...         self.loginForm = loginForm
-  ...
-  ...     def challenge(self, request):
-  ...         request.response.redirect(self.loginForm)
-  ...         return True
-
-This plugin handles a challenge by redirecting the response to a login form.
-It returns True to signal to the PAU that it handled the challenge.
-
-We will now create and register a couple of these plugins::
-
-  >>> provideUtility(LoginFormCredentialsPlugin('simplelogin.html'),
-  ...                name='Simple Login Form Plugin')
-
-  >>> provideUtility(LoginFormCredentialsPlugin('advancedlogin.html'),
-  ...                name='Advanced Login Form Plugin')
-
-and configure the PAU to use them::
-
-  >>> pau.credentialsPlugins = (
-  ...     'Simple Login Form Plugin',
-  ...     'Advanced Login Form Plugin')
-
-Now when we call 'unauthorized' on the PAU::
-
-  >>> request = TestRequest()
-  >>> pau.unauthorized(id=None, request=request)
-
-we see that the user is redirected to the simple login form::
-
-  >>> request.response.getStatus()
-  302
-  >>> request.response.getHeader('location')
-  'simplelogin.html'
-
-We can change the challenge policy by reordering the plugins::
-
-  >>> pau.credentialsPlugins = (
-  ...     'Advanced Login Form Plugin',
-  ...     'Simple Login Form Plugin')
-
-Now when we call 'unauthorized'::
-
-  >>> request = TestRequest()
-  >>> pau.unauthorized(id=None, request=request)
-
-the advanced plugin is used because it's first::
-
-  >>> request.response.getStatus()
-  302
-  >>> request.response.getHeader('location')
-  'advancedlogin.html'
-
-Challenge Protocols
-~~~~~~~~~~~~~~~~~~~
-
-Sometimes, we want multiple challengers to work together. For example, the
-HTTP specification allows multiple challenges to be issued in a response. A
-challenge plugin can provide a `challengeProtocol` attribute that effectively
-groups related plugins together for challenging. If a plugin returns `True`
-from its challenge and provides a non-None challengeProtocol, subsequent
-plugins in the credentialsPlugins list that have the same challenge protocol
-will also be used to challenge.
-
-Without a challengeProtocol, only the first plugin to succeed in a challenge
-will be used.
-
-Let's look at an example. We'll define a new plugin that specifies an
-'X-Challenge' protocol::
-
-  >>> class XChallengeCredentialsPlugin(FormCredentialsPlugin):
-  ...
-  ...     challengeProtocol = 'X-Challenge'
-  ...
-  ...     def __init__(self, challengeValue):
-  ...         self.challengeValue = challengeValue
-  ...
-  ...     def challenge(self, request):
-  ...         value = self.challengeValue
-  ...         existing = request.response.getHeader('X-Challenge', '')
-  ...         if existing:
-  ...             value += ' ' + existing
-  ...         request.response.setHeader('X-Challenge', value)
-  ...         return True
-
-and register a couple instances as utilities::
-
-  >>> provideUtility(XChallengeCredentialsPlugin('basic'),
-  ...                name='Basic X-Challenge Plugin')
-
-  >>> provideUtility(XChallengeCredentialsPlugin('advanced'),
-  ...                name='Advanced X-Challenge Plugin')
-
-When we use both plugins with the PAU::
-
-  >>> pau.credentialsPlugins = (
-  ...     'Basic X-Challenge Plugin',
-  ...     'Advanced X-Challenge Plugin')
-
-and call 'unauthorized'::
-
-  >>> request = TestRequest()
-  >>> pau.unauthorized(None, request)
-
-we see that both plugins participate in the challange, rather than just the
-first plugin::
-
-  >>> request.response.getHeader('X-Challenge')
-  'advanced basic'
-
-
-Pluggable-Authentication Prefixes
----------------------------------
-
-Principal ids are required to be unique system wide. Plugins will often provide
-options for providing id prefixes, so that different sets of plugins provide
-unique ids within a PAU. If there are multiple pluggable-authentication
-utilities in a system, it's a good idea to give each PAU a unique prefix, so
-that principal ids from different PAUs don't conflict. We can provide a prefix
-when a PAU is created::
-
-  >>> pau = authentication.PluggableAuthentication('mypau_')
-  >>> pau.credentialsPlugins = ('My Credentials Plugin', )
-  >>> pau.authenticatorPlugins = ('My Authenticator Plugin', )
-
-When we create a request and try to authenticate::
-
-  >>> pau.authenticate(TestRequest(credentials='secretcode'))
-  Principal('mypau_bob')
-
-Note that now, our principal's id has the pluggable-authentication
-utility prefix.
-
-We can still lookup a principal, as long as we supply the prefix::
-
-  >> pau.getPrincipal('mypas_42')
-  Principal('mypas_42', "{'domain': 42}")
-
-  >> pau.getPrincipal('mypas_41')
-  OddPrincipal('mypas_41', "{'int': 41}")
-
-
-Searching
----------
-
-PAU implements ISourceQueriables::
-
-  >>> from zope.schema.interfaces import ISourceQueriables
-  >>> ISourceQueriables.providedBy(pau)
-  True
-
-This means a PAU can be used in a principal source vocabulary (Zope provides a
-sophisticated searching UI for principal sources).
-
-As we've seen, a PAU uses each of its authenticator plugins to locate a
-principal with a given ID. However, plugins may also provide the interface
-IQuerySchemaSearch to indicate they can be used in the PAU's principal search
-scheme.
-
-Currently, our list of authenticators::
-
-  >>> pau.authenticatorPlugins
-  ('My Authenticator Plugin',)
-
-does not include a queriable authenticator. PAU cannot therefore provide any
-queriables::
-
-  >>> list(pau.getQueriables())
-  []
-
-Before we illustrate how an authenticator is used by the PAU to search for
-principals, we need to setup an adapter used by PAU::
-
-  >>> provideAdapter(
-  ...     authentication.authentication.QuerySchemaSearchAdapter,
-  ...     provides=interfaces.IQueriableAuthenticator)
-
-This adapter delegates search responsibility to an authenticator, but prepends
-the PAU prefix to any principal IDs returned in a search.
-
-Next, we'll create a plugin that provides a search interface::
-
-  >>> class QueriableAuthenticatorPlugin(MyAuthenticatorPlugin):
-  ...
-  ...     interface.implements(interfaces.IQuerySchemaSearch)
-  ...
-  ...     schema = None
-  ...
-  ...     def search(self, query, start=None, batch_size=None):
-  ...         yield 'foo'
-  ...
-
-and install it as a plugin::
-
-  >>> plugin = QueriableAuthenticatorPlugin()
-  >>> provideUtility(plugin,
-  ...                provides=interfaces.IAuthenticatorPlugin,
-  ...                name='Queriable')
-  >>> pau.authenticatorPlugins += ('Queriable',)
-
-Now, the PAU provides a single queriable::
-
-  >>> list(pau.getQueriables()) # doctest: +ELLIPSIS
-  [('Queriable', ...QuerySchemaSearchAdapter object...)]
-
-We can use this queriable to search for our principal::
-
-  >>> queriable = list(pau.getQueriables())[0][1]
-  >>> list(queriable.search('not-used'))
-  ['mypau_foo']
-
-Note that the resulting principal ID includes the PAU prefix. Were we to search
-the plugin directly::
-
-  >>> list(plugin.search('not-used'))
-  ['foo']
-
-The result does not include the PAU prefix. The prepending of the prefix is
-handled by the PluggableAuthenticationQueriable.
-
-
-Queryiable plugins can provide the ILocation interface. In this case the
-QuerySchemaSearchAdapter's __parent__ is the same as the __parent__ of the
-plugin::
-
-  >>> import zope.location.interfaces
-  >>> class LocatedQueriableAuthenticatorPlugin(QueriableAuthenticatorPlugin):
-  ...
-  ...     interface.implements(zope.location.interfaces.ILocation)
-  ...
-  ...     __parent__ = __name__ = None
-  ...
-  >>> import zope.app.component.hooks
-  >>> site = zope.app.component.hooks.getSite()
-  >>> plugin = LocatedQueriableAuthenticatorPlugin()
-  >>> plugin.__parent__ = site
-  >>> plugin.__name__ = 'localname'
-  >>> provideUtility(plugin,
-  ...                provides=interfaces.IAuthenticatorPlugin,
-  ...                name='location-queriable')
-  >>> pau.authenticatorPlugins = ('location-queriable',)
-
-We have one queriable again::
-
-  >>> queriables = list(pau.getQueriables())
-  >>> queriables  # doctest: +ELLIPSIS
-  [('location-queriable', ...QuerySchemaSearchAdapter object...)]
-
-The queriable's __parent__ is the site as set above::
-
-  >>> queriable = queriables[0][1]
-  >>> queriable.__parent__ is site
-  True
-
-If the queriable provides ILocation but is not actually locatable (i.e. the
-parent is None) the pau itself becomes the parent::
-
-
-  >>> plugin = LocatedQueriableAuthenticatorPlugin()
-  >>> provideUtility(plugin,
-  ...                provides=interfaces.IAuthenticatorPlugin,
-  ...                name='location-queriable-wo-parent')
-  >>> pau.authenticatorPlugins = ('location-queriable-wo-parent',)
-
-We have one queriable again::
-
-  >>> queriables = list(pau.getQueriables())
-  >>> queriables  # doctest: +ELLIPSIS
-  [('location-queriable-wo-parent', ...QuerySchemaSearchAdapter object...)]
-
-And the parent is the pau::
-
-  >>> queriable = queriables[0][1]
-  >>> queriable.__parent__  # doctest: +ELLIPSIS
-  <zope.app.authentication.authentication.PluggableAuthentication object ...>
-  >>> queriable.__parent__ is pau
-  True
+ * encodePassword(password) - return encoded data for the given `password`
+ * checkPassword(storedPassword, password) - return whether the given `password`
+   coincide with the storedPassword, which is 
+ 
\ No newline at end of file

Deleted: zope.password/trunk/src/zope/password/SETUP.cfg
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/SETUP.cfg	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/SETUP.cfg	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,5 +0,0 @@
-# Tell zpkg how to install the ZCML slugs.
-
-<data-files zopeskel/etc/package-includes>
-  *-configure.zcml
-</data-files>

Modified: zope.password/trunk/src/zope/password/__init__.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/__init__.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/__init__.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2004 Zope Corporation and Contributors.
+# Copyright (c) 2009 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -11,10 +11,6 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Pluggable Authentication Utility
-
+"""
 $Id$
 """
-
-import interfaces
-from zope.app.authentication.authentication import PluggableAuthentication

Deleted: zope.password/trunk/src/zope/password/authentication.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/authentication.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/authentication.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,186 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""Pluggable Authentication Utility implementation
-
-$Id$
-"""
-import zope.interface
-from zope import component
-from zope.schema.interfaces import ISourceQueriables
-from zope.location.interfaces import ILocation
-
-from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
-from zope.app.component import queryNextUtility
-import zope.container.btree
-
-from zope.app.authentication import interfaces
-
-class PluggableAuthentication(zope.container.btree.BTreeContainer):
-
-    zope.interface.implements(
-        IAuthentication,
-        interfaces.IPluggableAuthentication,
-        ISourceQueriables)
-
-    authenticatorPlugins = ()
-    credentialsPlugins = ()
-
-    def __init__(self, prefix=''):
-        super(PluggableAuthentication, self).__init__()
-        self.prefix = prefix
-
-    @property
-    def registrationManager(self):
-        import warnings
-        warnings.warn(
-            "The registration manager is deprecated and will go away in "
-            "Zope 3.5.  Use the simpler registration api (registerUtility) "
-            "instead.",
-            DeprecationWarning, 2)
-        return self.__parent__.registrationManager
-
-    def _plugins(self, names, interface):
-        for name in names:
-            plugin = self.get(name)
-            if not interface.providedBy(plugin):
-                plugin = component.queryUtility(interface, name, context=self)
-            if plugin is not None:
-                yield name, plugin
-
-    def getAuthenticatorPlugins(self):
-        return self._plugins(
-            self.authenticatorPlugins, interfaces.IAuthenticatorPlugin)
-
-    def getCredentialsPlugins(self):
-        return self._plugins(
-            self.credentialsPlugins, interfaces.ICredentialsPlugin)
-
-    def authenticate(self, request):
-        authenticatorPlugins = [p for n, p in self.getAuthenticatorPlugins()]
-        for name, credplugin in self.getCredentialsPlugins():
-            credentials = credplugin.extractCredentials(request)
-            for authplugin in authenticatorPlugins:
-                if authplugin is None:
-                    continue
-                info = authplugin.authenticateCredentials(credentials)
-                if info is None:
-                    continue
-                info.credentialsPlugin = credplugin
-                info.authenticatorPlugin = authplugin
-                principal = component.getMultiAdapter((info, request),
-                    interfaces.IAuthenticatedPrincipalFactory)(self)
-                principal.id = self.prefix + info.id
-                return principal
-        return None
-
-    def getPrincipal(self, id):
-        if not id.startswith(self.prefix):
-            next = queryNextUtility(self, IAuthentication)
-            if next is None:
-                raise PrincipalLookupError(id)
-            return next.getPrincipal(id)
-        id = id[len(self.prefix):]
-        for name, authplugin in self.getAuthenticatorPlugins():
-            info = authplugin.principalInfo(id)
-            if info is None:
-                continue
-            info.credentialsPlugin = None
-            info.authenticatorPlugin = authplugin
-            principal = interfaces.IFoundPrincipalFactory(info)(self)
-            principal.id = self.prefix + info.id
-            return principal
-        next = queryNextUtility(self, IAuthentication)
-        if next is not None:
-            return next.getPrincipal(self.prefix + id)
-        raise PrincipalLookupError(id)
-
-    def getQueriables(self):
-        for name, authplugin in self.getAuthenticatorPlugins():
-            queriable = component.queryMultiAdapter((authplugin, self),
-                interfaces.IQueriableAuthenticator)
-            if queriable is not None:
-                yield name, queriable
-
-    def unauthenticatedPrincipal(self):
-        return None
-
-    def unauthorized(self, id, request):
-        challengeProtocol = None
-
-        for name, credplugin in self.getCredentialsPlugins():
-            protocol = getattr(credplugin, 'challengeProtocol', None)
-            if challengeProtocol is None or protocol == challengeProtocol:
-                if credplugin.challenge(request):
-                    if protocol is None:
-                        return
-                    elif challengeProtocol is None:
-                        challengeProtocol = protocol
-
-        if challengeProtocol is None:
-            next = queryNextUtility(self, IAuthentication)
-            if next is not None:
-                next.unauthorized(id, request)
-
-    def logout(self, request):
-        challengeProtocol = None
-
-        for name, credplugin in self.getCredentialsPlugins():
-            protocol = getattr(credplugin, 'challengeProtocol', None)
-            if challengeProtocol is None or protocol == challengeProtocol:
-                if credplugin.logout(request):
-                    if protocol is None:
-                        return
-                    elif challengeProtocol is None:
-                        challengeProtocol = protocol
-
-        if challengeProtocol is None:
-            next = queryNextUtility(self, IAuthentication)
-            if next is not None:
-                next.logout(request)
-
-
-class QuerySchemaSearchAdapter(object):
-    """Performs schema-based principal searches on behalf of a PAU.
-
-    Delegates the search to the adapted authenticator (which also provides
-    IQuerySchemaSearch) and prepends the PAU prefix to the resulting principal
-    IDs.
-    """
-    component.adapts(
-        interfaces.IQuerySchemaSearch,
-        interfaces.IPluggableAuthentication)
-
-    zope.interface.implements(
-        interfaces.IQueriableAuthenticator,
-        interfaces.IQuerySchemaSearch,
-        ILocation)
-
-    def __init__(self, authplugin, pau):
-        if (ILocation.providedBy(authplugin) and
-            authplugin.__parent__ is not None):
-            # Checking explicitly for the parent, because providing ILocation
-            # basically means that the object *could* be located. It doesn't
-            # say the object must be located.
-            self.__parent__ = authplugin.__parent__
-            self.__name__ = authplugin.__name__
-        else:
-            self.__parent__ = pau
-            self.__name__ = ""
-        self.authplugin = authplugin
-        self.pau = pau
-        self.schema = authplugin.schema
-
-    def search(self, query, start=None, batch_size=None):
-        for id in self.authplugin.search(query, start, batch_size):
-            yield self.pau.prefix + id

Deleted: zope.password/trunk/src/zope/password/configure.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/configure.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/configure.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,69 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    xmlns:browser="http://namespaces.zope.org/browser"
-    i18n_domain="zope"
-    >
-
-  <class class=".PluggableAuthentication">
-    <implements
-        interface="zope.annotation.interfaces.IAttributeAnnotatable"
-        />
-    <require
-        permission="zope.ManageSite"
-        interface=".interfaces.IPluggableAuthentication"
-        set_schema=".interfaces.IPluggableAuthentication"
-        />
-    <require
-        permission="zope.ManageServices"
-        attributes="registrationManager"
-        />
-  </class>
-
-  <adapter
-      for=".interfaces.IQuerySchemaSearch
-           .interfaces.IPluggableAuthentication"
-      provides=".interfaces.IQueriableAuthenticator"
-      factory=".authentication.QuerySchemaSearchAdapter"
-      />
-
-  <utility
-      component=".vocabulary.credentialsPlugins"
-      name="CredentialsPlugins"
-      />
-
-  <utility
-      component=".vocabulary.authenticatorPlugins"
-      name="AuthenticatorPlugins"
-      />
-
-  <utility
-      name="No Challenge if Authenticated"
-      factory=".generic.NoChallengeCredentialsPlugin"
-      provides=".interfaces.ICredentialsPlugin"
-      />
-
-  <!-- Registering documentation with API doc -->
-  <configure
-      xmlns:apidoc="http://namespaces.zope.org/apidoc"
-      xmlns:zcml="http://namespaces.zope.org/zcml"
-      zcml:condition="have apidoc">
-
-    <apidoc:bookchapter
-        id="authentication"
-        title="Pluggable Authentication"
-        doc_path="README.txt"
-        parent="security"
-        />
-
-  </configure>
-
-  <include file="password.zcml" />
-  <include file="session.zcml" />
-  <include file="httpplugins.zcml" />
-  <include file="principalfolder.zcml" />
-  <include file="groupfolder.zcml" />
-  <include file="ftpplugins.zcml" />
-
-  <include package=".browser" />
-
-</configure>

Copied: zope.password/trunk/src/zope/password/configure.zcml (from rev 97555, zope.app.authentication/trunk/src/zope/app/authentication/password.zcml)
===================================================================
--- zope.password/trunk/src/zope/password/configure.zcml	                        (rev 0)
+++ zope.password/trunk/src/zope/password/configure.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -0,0 +1,39 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+  <class class=".password.PlainTextPasswordManager">
+    <allow interface=".interfaces.IPasswordManager" />
+  </class>
+
+  <utility
+      name="Plain Text"
+      provides=".interfaces.IPasswordManager"
+      factory=".password.PlainTextPasswordManager"
+      />
+
+  <class class=".password.MD5PasswordManager">
+    <allow interface=".interfaces.IPasswordManager" />
+  </class>
+
+  <utility
+      name="MD5"
+      provides=".interfaces.IPasswordManager"
+      factory=".password.MD5PasswordManager"
+      />
+
+  <class class=".password.SHA1PasswordManager">
+    <allow interface=".interfaces.IPasswordManager" />
+  </class>
+
+  <utility
+      name="SHA1"
+      provides=".interfaces.IPasswordManager"
+      factory=".password.SHA1PasswordManager"
+      />
+
+  <utility
+      name="SSHA"
+      provides=".interfaces.IPasswordManager"
+      factory=".password.SSHAPasswordManager"
+      />
+
+</configure>

Deleted: zope.password/trunk/src/zope/password/ftesting.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/ftesting.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/ftesting.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,70 +0,0 @@
-<configure
-   xmlns="http://namespaces.zope.org/zope"
-   i18n_domain="zope"
-   package="zope.app.authentication"
-   >
-
-  <!-- This file is the equivalent of site.zcml and it is -->
-  <!-- used for functional testing setup -->
-
-  <include package="zope.app.securitypolicy" file="meta.zcml" />
-
-  <include package="zope.app.zcmlfiles" />
-  <include package="zope.formlib" />
-  <include package="zope.session" />
-  <include package="zope.app.authentication" />
-  <include package="zope.app.securitypolicy" />
-
-  <securityPolicy
-    component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
-
-  <role id="zope.Anonymous" title="Everybody"
-                 description="All users have this role implicitly" />
-  <role id="zope.Manager" title="Site Manager" />
-
-  <!-- Replace the following directive if you don't want public access -->
-  <grant permission="zope.View"
-                  role="zope.Anonymous" />
-
-  <grantAll role="zope.Manager" />
-
-  <include package="zope.app.securitypolicy.tests" file="functional.zcml" />
-
-  <!-- Principals -->
-
-  <unauthenticatedPrincipal
-      id="zope.anybody"
-      title="Unauthenticated User" />
-
-  <unauthenticatedGroup
-    id="zope.Anybody"
-    title="Unauthenticated Users"
-    />
-
-  <authenticatedGroup
-    id="zope.Authenticated"
-    title="Authenticated Users"
-    />
-
-  <everybodyGroup
-    id="zope.Everybody"
-    title="All Users"
-    />
-
-  <!-- Principal that tests generally run as -->
-  <principal
-      id="zope.mgr"
-      title="Manager"
-      login="mgr"
-      password="mgrpw" />
-
-  <!-- Bootstrap principal used to make local grant to the principal above -->
-  <principal
-      id="zope.globalmgr"
-      title="Manager"
-      login="globalmgr"
-      password="globalmgrpw" />
-
-  <grant role="zope.Manager" principal="zope.globalmgr" />
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/ftpplugins.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/ftpplugins.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/ftpplugins.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,65 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""PAS plugins related to FTP
-"""
-__docformat__ = 'restructuredtext'
-
-from zope.interface import implements
-from zope.publisher.interfaces.ftp import IFTPRequest
-
-from zope.app.authentication import interfaces
-
-class FTPCredentialsPlugin(object):
-
-    implements(interfaces.ICredentialsPlugin)
-
-    def extractCredentials(self, request):
-        """Extracts the FTP credentials from a request.
-
-        First we need to create a FTP request that contains some credentials.
-        Note the path is a required in the envirnoment.
-
-          >>> from zope.publisher.ftp import FTPRequest
-          >>> from StringIO import StringIO
-          >>> request = FTPRequest(StringIO(''),
-          ...                      {'credentials': ('bob', '123'),
-          ...                       'path': '/a/b/c'})
-
-        Now we create the plugin and get the credentials.
-
-          >>> plugin = FTPCredentialsPlugin()
-          >>> plugin.extractCredentials(request)
-          {'login': u'bob', 'password': u'123'}
-
-        This only works for FTPRequests.
-
-          >>> from zope.publisher.base import TestRequest
-          >>> print plugin.extractCredentials(TestRequest('/'))
-          None
-
-        """
-        if not IFTPRequest.providedBy(request):
-            return None
-
-        if request._auth:
-            login, password = request._auth
-            return {'login': login.decode('utf-8'),
-                    'password': password.decode('utf-8')}
-        return None
-
-    def challenge(self, request):
-        return False
-
-    def logout(self, request):
-        return False

Deleted: zope.password/trunk/src/zope/password/ftpplugins.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/ftpplugins.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/ftpplugins.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,12 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    i18n_domain="zope"
-    >
-
-  <utility
-      name="FTP Credentials"
-      provides=".interfaces.ICredentialsPlugin"
-      factory=".ftpplugins.FTPCredentialsPlugin"
-      />
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/generic.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/generic.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/generic.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,95 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""Generic PAS Plugins
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-from zope.interface import implements
-
-from zope.app.security.interfaces import IUnauthenticatedPrincipal
-
-from zope.app.authentication import interfaces
-
-
-class NoChallengeCredentialsPlugin(object):
-    """A plugin that doesn't challenge if the principal is authenticated.
-
-    There are two reasonable ways to handle an unauthorized error for an
-    authenticated principal:
-
-      - Inform the user of the unauthorized error
-
-      - Let the user login with a different set of credentials
-
-    Since either approach is reasonable, we need to give the site manager
-    some way of specifying one of the two policies.
-
-    By default, a user will be challenged for a new set of credentials if
-    unauthorized. A site manager can insert this plugin in the front of the
-    plugin list to prevent that challenge from occurring. This will
-    typically result in an 'Unauthorized' message to the user.
-
-    The 'challenge' behavior of the plugin is simple. To illustrate, we'll
-    create a plugin:
-
-      >>> challenger = NoChallengeCredentialsPlugin()
-
-    and a test request with an authenticated principal:
-
-      >>> from zope.publisher.browser import TestRequest
-      >>> request = TestRequest()
-      >>> IUnauthenticatedPrincipal.providedBy(request.principal)
-      False
-
-    When we challenge using the plugin:
-
-      >>> challenger.challenge(request)
-      True
-
-    we get a value that signals the PAU that this plugin successfully
-    challenged the user (even though it actually did nothing). The PAU
-    will stop trying to challenge and the user will not get a chance to
-    provide different credentials. The result is typically an error message.
-
-    On the other hand, if the user is unauthenticated:
-
-      >>> class Principal(object):
-      ...     implements(IUnauthenticatedPrincipal)
-      >>> request.setPrincipal(Principal())
-      >>> IUnauthenticatedPrincipal.providedBy(request.principal)
-      True
-
-    the plugin challenge will return None:
-
-      >>> print challenger.challenge(request)
-      None
-
-    signaling the PAU that it should try the next plugin for a challenge. If
-    the PAU is configured properly, the user will receive a challenge and be
-    allowed to provide different credentials.
-    """
-    implements(interfaces.ICredentialsPlugin)
-
-    def extractCredentials(self, request):
-        return None
-
-    def challenge(self, request):
-        if not IUnauthenticatedPrincipal.providedBy(request.principal):
-            return True
-        return None
-
-    def logout(self, request):
-        return False
-

Deleted: zope.password/trunk/src/zope/password/groupfolder.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/groupfolder.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/groupfolder.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,363 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""Zope Groups Folder implementation
-
-$Id$
-
-"""
-import BTrees.OOBTree
-import persistent
-
-from zope import interface, event, schema, component
-from zope.interface import alsoProvides
-from zope.security.interfaces import (
-    IGroup, IGroupAwarePrincipal, IMemberAwareGroup)
-
-from zope.container.btree import BTreeContainer
-import zope.container.constraints
-import zope.container.interfaces
-from zope.app.authentication.i18n import ZopeMessageFactory as _
-import zope.app.security.vocabulary
-from zope.app.security.interfaces import (
-    IAuthentication, IAuthenticatedGroup, IEveryoneGroup)
-from zope.app.authentication import principalfolder, interfaces
-
-
-class IGroupInformation(interface.Interface):
-
-    title = schema.TextLine(
-        title=_("Title"),
-        description=_("Provides a title for the permission."),
-        required=True)
-
-    description = schema.Text(
-        title=_("Description"),
-        description=_("Provides a description for the permission."),
-        required=False)
-
-    principals = schema.List(
-        title=_("Principals"),
-        value_type=schema.Choice(
-            source=zope.app.security.vocabulary.PrincipalSource()),
-        description=_(
-        "List of ids of principals which belong to the group"),
-        required=False)
-
-
-class IGroupFolder(zope.container.interfaces.IContainer):
-
-    zope.container.constraints.contains(IGroupInformation)
-
-    prefix = schema.TextLine(
-        title=_("Group ID prefix"),
-        description=_("Prefix added to IDs of groups in this folder"),
-        readonly=True,
-        )
-
-    def getGroupsForPrincipal(principalid):
-        """Get groups the given principal belongs to"""
-
-    def getPrincipalsForGroup(groupid):
-        """Get principals which belong to the group"""
-
-
-class IGroupContained(zope.container.interfaces.IContained):
-
-    zope.container.constraints.containers(IGroupFolder)
-
-class IGroupSearchCriteria(interface.Interface):
-
-    search = schema.TextLine(
-        title=_("Group Search String"),
-        required=False,
-        missing_value=u'',
-        )
-
-class IGroupPrincipalInfo(interfaces.IPrincipalInfo):
-    members = interface.Attribute('an iterable of members of the group')
-
-class GroupInfo(object):
-    """An implementation of IPrincipalInfo used by the group folder.
-
-    A group info is created with id, title, and description:
-
-      >>> class DemoGroupInformation(object):
-      ...     interface.implements(IGroupInformation)
-      ...     def __init__(self, title, description, principals):
-      ...         self.title = title
-      ...         self.description = description
-      ...         self.principals = principals
-      ...
-      >>> i = DemoGroupInformation(
-      ...     'Managers', 'Taskmasters', ('joe', 'jane'))
-      ...
-      >>> info = GroupInfo('groups.managers', i)
-      >>> info
-      GroupInfo('groups.managers')
-      >>> info.id
-      'groups.managers'
-      >>> info.title
-      'Managers'
-      >>> info.description
-      'Taskmasters'
-      >>> info.members
-      ('joe', 'jane')
-      >>> info.members = ('joe', 'jane', 'jaime')
-      >>> info.members
-      ('joe', 'jane', 'jaime')
-
-    """
-    interface.implements(IGroupPrincipalInfo)
-
-    def __init__(self, id, information):
-        self.id = id
-        self._information = information
-
-    @property
-    def title(self):
-        return self._information.title
-
-    @property
-    def description(self):
-        return self._information.description
-
-    @apply
-    def members():
-        def get(self):
-            return self._information.principals
-        def set(self, value):
-            self._information.principals = value
-        return property(get, set)
-
-    def __repr__(self):
-        return 'GroupInfo(%r)' % self.id
-
-
-class GroupFolder(BTreeContainer):
-
-    interface.implements(
-        interfaces.IAuthenticatorPlugin,
-        interfaces.IQuerySchemaSearch,
-        IGroupFolder)
-
-    schema = IGroupSearchCriteria
-
-    def __init__(self, prefix=u''):
-        super(GroupFolder, self).__init__()
-        self.prefix = prefix
-        # __inversemapping is used to map principals to groups
-        self.__inverseMapping = BTrees.OOBTree.OOBTree()
-
-    def __setitem__(self, name, value):
-        BTreeContainer.__setitem__(self, name, value)
-        group_id = self._groupid(value)
-        self._addPrincipalsToGroup(value.principals, group_id)
-        if value.principals:
-            event.notify(
-                interfaces.PrincipalsAddedToGroup(
-                    value.principals, self.__parent__.prefix + group_id))
-        group = principalfolder.Principal(self.prefix + name)
-        event.notify(interfaces.GroupAdded(group))
-
-    def __delitem__(self, name):
-        value = self[name]
-        group_id = self._groupid(value)
-        self._removePrincipalsFromGroup(value.principals, group_id)
-        if value.principals:
-            event.notify(
-                interfaces.PrincipalsRemovedFromGroup(
-                    value.principals, self.__parent__.prefix + group_id))
-        BTreeContainer.__delitem__(self, name)
-
-    def _groupid(self, group):
-        return self.prefix+group.__name__
-
-    def _addPrincipalsToGroup(self, principal_ids, group_id):
-        for principal_id in principal_ids:
-            self.__inverseMapping[principal_id] = (
-                self.__inverseMapping.get(principal_id, ())
-                + (group_id,))
-
-    def _removePrincipalsFromGroup(self, principal_ids, group_id):
-        for principal_id in principal_ids:
-            groups = self.__inverseMapping.get(principal_id)
-            if groups is None:
-                return
-            new = tuple([id for id in groups if id != group_id])
-            if new:
-                self.__inverseMapping[principal_id] = new
-            else:
-                del self.__inverseMapping[principal_id]
-
-    def getGroupsForPrincipal(self, principalid):
-        """Get groups the given principal belongs to"""
-        return self.__inverseMapping.get(principalid, ())
-
-    def getPrincipalsForGroup(self, groupid):
-        """Get principals which belong to the group"""
-        return self[groupid].principals
-
-    def search(self, query, start=None, batch_size=None):
-        """ Search for groups"""
-        search = query.get('search')
-        if search is not None:
-            n = 0
-            search = search.lower()
-            for i, (id, groupinfo) in enumerate(self.items()):
-                if (search in groupinfo.title.lower() or
-                    (groupinfo.description and 
-                     search in groupinfo.description.lower())):
-                    if not ((start is not None and i < start)
-                            or
-                            (batch_size is not None and n >= batch_size)):
-                        n += 1
-                        yield self.prefix + id
-
-    def authenticateCredentials(self, credentials):
-        # user folders don't authenticate
-        pass
-
-    def principalInfo(self, id):
-        if id.startswith(self.prefix):
-            id = id[len(self.prefix):]
-            info = self.get(id)
-            if info is not None:
-                return GroupInfo(
-                    self.prefix+id, info)
-
-class GroupCycle(Exception):
-    """There is a cyclic relationship among groups
-    """
-
-class InvalidPrincipalIds(Exception):
-    """A user has a group id for a group that can't be found
-    """
-
-class InvalidGroupId(Exception):
-    """A user has a group id for a group that can't be found
-    """
-
-def nocycles(principal_ids, seen, getPrincipal):
-    for principal_id in principal_ids:
-        if principal_id in seen:
-            raise GroupCycle(principal_id, seen)
-        seen.append(principal_id)
-        principal = getPrincipal(principal_id)
-        nocycles(principal.groups, seen, getPrincipal)
-        seen.pop()
-
-class GroupInformation(persistent.Persistent):
-
-    interface.implements(IGroupInformation, IGroupContained)
-
-    __parent__ = __name__ = None
-
-    _principals = ()
-
-    def __init__(self, title='', description=''):
-        self.title = title
-        self.description = description
-
-    def setPrincipals(self, prinlist, check=True):
-        # method is not a part of the interface
-        parent = self.__parent__
-        old = self._principals
-        self._principals = tuple(prinlist)
-
-        if parent is not None:
-            oldset = set(old)
-            new = set(prinlist)
-            group_id = parent._groupid(self)
-            removed = oldset - new
-            added = new - oldset
-            try:
-                parent._removePrincipalsFromGroup(removed, group_id)
-            except AttributeError:
-                removed = None
-
-            try:
-                parent._addPrincipalsToGroup(added, group_id)
-            except AttributeError:
-                added = None
-
-            if check:
-                try:
-                    principalsUtility = component.getUtility(IAuthentication)
-                    nocycles(new, [], principalsUtility.getPrincipal)
-                except GroupCycle:
-                    # abort
-                    self.setPrincipals(old, False)
-                    raise
-            # now that we've gotten past the checks, fire the events.
-            if removed:
-                event.notify(
-                    interfaces.PrincipalsRemovedFromGroup(
-                        removed, self.__parent__.__parent__.prefix + group_id))
-            if added:
-                event.notify(
-                    interfaces.PrincipalsAddedToGroup(
-                        added, self.__parent__.__parent__.prefix + group_id))
-
-    principals = property(lambda self: self._principals, setPrincipals)
-
-
-def specialGroups(event):
-    principal = event.principal
-    if (IGroup.providedBy(principal) or
-        not IGroupAwarePrincipal.providedBy(principal)):
-        return
-
-    everyone = component.queryUtility(IEveryoneGroup)
-    if everyone is not None:
-        principal.groups.append(everyone.id)
-
-    auth = component.queryUtility(IAuthenticatedGroup)
-    if auth is not None:
-        principal.groups.append(auth.id)
-
-
-def setGroupsForPrincipal(event):
-    """Set group information when a principal is created"""
-
-    principal = event.principal
-    if not IGroupAwarePrincipal.providedBy(principal):
-        return
-
-    authentication = event.authentication
-
-    for name, plugin in authentication.getAuthenticatorPlugins():
-        if not IGroupFolder.providedBy(plugin):
-            continue
-        groupfolder = plugin
-        principal.groups.extend(
-            [authentication.prefix + id
-             for id in groupfolder.getGroupsForPrincipal(principal.id)
-             ])
-        id = principal.id
-        prefix = authentication.prefix + groupfolder.prefix
-        if id.startswith(prefix) and id[len(prefix):] in groupfolder:
-            alsoProvides(principal, IGroup)
-
- at component.adapter(interfaces.IFoundPrincipalCreated)
-def setMemberSubscriber(event):
-    """adds `getMembers`, `setMembers` to groups made from IGroupPrincipalInfo.
-    """
-    info = event.info
-    if IGroupPrincipalInfo.providedBy(info):
-        principal = event.principal
-        principal.getMembers = lambda : info.members
-        def setMembers(value):
-            info.members = value
-        principal.setMembers = setMembers
-        alsoProvides(principal, IMemberAwareGroup)

Deleted: zope.password/trunk/src/zope/password/groupfolder.txt
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/groupfolder.txt	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/groupfolder.txt	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,427 +0,0 @@
-=============
-Group Folders
-=============
-
-Group folders provide support for groups information stored in the ZODB.  They
-are persistent, and must be contained within the PAUs that use them.
-
-Like other principals, groups are created when they are needed.
-
-Group folders contain group-information objects that contain group information.
-We create group information using the `GroupInformation` class:
-
-  >>> import zope.app.authentication.groupfolder
-  >>> g1 = zope.app.authentication.groupfolder.GroupInformation("Group 1")
-
-  >>> groups = zope.app.authentication.groupfolder.GroupFolder('group.')
-  >>> groups['g1'] = g1
-
-Note that when group-info is added, a GroupAdded event is generated:
-
-  >>> from zope.app.authentication import interfaces
-  >>> from zope.component.eventtesting import getEvents
-  >>> getEvents(interfaces.IGroupAdded)
-  [<GroupAdded 'group.g1'>]
-
-Groups are defined with respect to an authentication service.  Groups
-must be accessible via an authentication service and can contain
-principals accessible via an authentication service.
-
-To illustrate the group interaction with the authentication service,
-we'll create a sample authentication service:
-
-  >>> from zope import interface
-  >>> from zope.app.security.interfaces import IAuthentication
-  >>> from zope.app.security.interfaces import PrincipalLookupError
-  >>> from zope.security.interfaces import IGroupAwarePrincipal
-  >>> from zope.app.authentication.groupfolder import setGroupsForPrincipal
-
-  >>> class Principal:
-  ...     interface.implements(IGroupAwarePrincipal)
-  ...     def __init__(self, id, title='', description=''):
-  ...         self.id, self.title, self.description = id, title, description
-  ...         self.groups = []
-
-  >>> class PrincipalCreatedEvent:
-  ...     def __init__(self, authentication, principal):
-  ...         self.authentication = authentication
-  ...         self.principal = principal
-
-  >>> from zope.app.authentication import principalfolder
-
-  >>> class Principals:
-  ...
-  ...     interface.implements(IAuthentication)
-  ...
-  ...     def __init__(self, groups, prefix='auth.'):
-  ...         self.prefix = prefix
-  ...         self.principals = {
-  ...            'p1': principalfolder.PrincipalInfo('p1', '', '', ''),
-  ...            'p2': principalfolder.PrincipalInfo('p2', '', '', ''),
-  ...            'p3': principalfolder.PrincipalInfo('p3', '', '', ''),
-  ...            'p4': principalfolder.PrincipalInfo('p4', '', '', ''),
-  ...            }
-  ...         self.groups = groups
-  ...         groups.__parent__ = self
-  ...
-  ...     def getAuthenticatorPlugins(self):
-  ...         return [('principals', self.principals), ('groups', self.groups)]
-  ...
-  ...     def getPrincipal(self, id):
-  ...         if not id.startswith(self.prefix):
-  ...             raise PrincipalLookupError(id)
-  ...         id = id[len(self.prefix):]
-  ...         info = self.principals.get(id)
-  ...         if info is None:
-  ...             info = self.groups.principalInfo(id)
-  ...             if info is None:
-  ...                raise PrincipalLookupError(id)
-  ...         principal = Principal(self.prefix+info.id, 
-  ...                               info.title, info.description)
-  ...         setGroupsForPrincipal(PrincipalCreatedEvent(self, principal))
-  ...         return principal
-
-This class doesn't really implement the full `IAuthentication` interface, but
-it implements the `getPrincipal` method used by groups. It works very much
-like the pluggable authentication utility.  It creates principals on demand. It
-calls `setGroupsForPrincipal`, which is normally called as an event subscriber,
-when principals are created. In order for `setGroupsForPrincipal` to find out
-group folder, we have to register it as a utility:
-
-  >>> from zope.app.testing import ztapi
-  >>> from zope.app.authentication.interfaces import IAuthenticatorPlugin
-  >>> ztapi.provideUtility(IAuthenticatorPlugin, groups)
-
-We will create and register a new principals utility:
-
-  >>> principals = Principals(groups)
-  >>> ztapi.provideUtility(IAuthentication, principals)
-
-Now we can set the principals on the group:
-
-  >>> g1.principals = ['auth.p1', 'auth.p2']
-  >>> g1.principals
-  ('auth.p1', 'auth.p2')
-
-Adding principals fires an event.
-
-  >>> getEvents(interfaces.IPrincipalsAddedToGroup)[-1]
-  <PrincipalsAddedToGroup ['auth.p1', 'auth.p2'] u'auth.group.g1'>
-
-We can now look up groups for the principals:
-
-  >>> groups.getGroupsForPrincipal('auth.p1')
-  (u'group.g1',)
-
-Note that the group id is a concatenation of the group-folder prefix
-and the name of the group-information object within the folder.
-
-If we delete a group:
-
-  >>> del groups['g1']
-
-then the groups folder loses the group information for that group's
-principals:
-
-  >>> groups.getGroupsForPrincipal('auth.p1')
-  ()
-
-but the principal information on the group is unchanged:
-
-  >>> g1.principals
-  ('auth.p1', 'auth.p2')
-
-It also fires an event showing that the principals are removed from the group
-(g1 is group information, not a zope.security.interfaces.IGroup).
-
-  >>> getEvents(interfaces.IPrincipalsRemovedFromGroup)[-1]
-  <PrincipalsRemovedFromGroup ['auth.p1', 'auth.p2'] u'auth.group.g1'>
-
-Adding the group sets the folder principal information.  Let's use a
-different group name:
-
-  >>> groups['G1'] = g1
-
-  >>> groups.getGroupsForPrincipal('auth.p1')
-  (u'group.G1',)
-
-Here we see that the new name is reflected in the group information.
-
-An event is fired, as usual.
-
-  >>> getEvents(interfaces.IPrincipalsAddedToGroup)[-1]
-  <PrincipalsAddedToGroup ['auth.p1', 'auth.p2'] u'auth.group.G1'>
-
-In terms of member events (principals added and removed from groups), we have
-now seen that events are fired when a group information object is added and
-when it is removed from a group folder; and we have seen that events are fired
-when a principal is added to an already-registered group.  Events are also
-fired when a principal is removed from an already-registered group.  Let's
-quickly see some more examples.
-
-  >>> g1.principals = ('auth.p1', 'auth.p3', 'auth.p4')
-  >>> getEvents(interfaces.IPrincipalsAddedToGroup)[-1]
-  <PrincipalsAddedToGroup ['auth.p3', 'auth.p4'] u'auth.group.G1'>
-  >>> getEvents(interfaces.IPrincipalsRemovedFromGroup)[-1]
-  <PrincipalsRemovedFromGroup ['auth.p2'] u'auth.group.G1'>
-  >>> g1.principals = ('auth.p1', 'auth.p2')
-  >>> getEvents(interfaces.IPrincipalsAddedToGroup)[-1]
-  <PrincipalsAddedToGroup ['auth.p2'] u'auth.group.G1'>
-  >>> getEvents(interfaces.IPrincipalsRemovedFromGroup)[-1]
-  <PrincipalsRemovedFromGroup ['auth.p3', 'auth.p4'] u'auth.group.G1'>
-
-Groups can contain groups:
-
-  >>> g2 = zope.app.authentication.groupfolder.GroupInformation("Group Two")
-  >>> groups['G2'] = g2
-  >>> g2.principals = ['auth.group.G1']
-
-  >>> groups.getGroupsForPrincipal('auth.group.G1')
-  (u'group.G2',)
-
-  >>> old = getEvents(interfaces.IPrincipalsAddedToGroup)[-1]
-  >>> old
-  <PrincipalsAddedToGroup ['auth.group.G1'] u'auth.group.G2'>
-
-Groups cannot contain cycles:
-
-  >>> g1.principals = ('auth.p1', 'auth.p2', 'auth.group.G2')
-  ... # doctest: +NORMALIZE_WHITESPACE
-  Traceback (most recent call last):
-  ...
-  GroupCycle: (u'auth.group.G1', 
-               ['auth.p2', u'auth.group.G1', u'auth.group.G2'])
-
-Trying to do so does not fire an event.
-
-  >>> getEvents(interfaces.IPrincipalsAddedToGroup)[-1] is old
-  True
-
-They need not be hierarchical:
-
-  >>> ga = zope.app.authentication.groupfolder.GroupInformation("Group A")
-  >>> groups['GA'] = ga
-
-  >>> gb = zope.app.authentication.groupfolder.GroupInformation("Group B")
-  >>> groups['GB'] = gb
-  >>> gb.principals = ['auth.group.GA']
-
-  >>> gc = zope.app.authentication.groupfolder.GroupInformation("Group C")
-  >>> groups['GC'] = gc
-  >>> gc.principals = ['auth.group.GA']
-
-  >>> gd = zope.app.authentication.groupfolder.GroupInformation("Group D")
-  >>> groups['GD'] = gd
-  >>> gd.principals = ['auth.group.GA', 'auth.group.GB']
-
-  >>> ga.principals = ['auth.p1']
-
-Group folders provide a very simple search interface.  They perform
-simple string searches on group titles and descriptions.
-
-  >>> list(groups.search({'search': 'grou'})) # doctest: +NORMALIZE_WHITESPACE
-  [u'group.G1', u'group.G2',
-   u'group.GA', u'group.GB', u'group.GC', u'group.GD']
-
-  >>> list(groups.search({'search': 'two'}))
-  [u'group.G2']
-
-They also support batching:
-
-  >>> list(groups.search({'search': 'grou'}, 2, 3))
-  [u'group.GA', u'group.GB', u'group.GC']
-
-
-If you don't supply a search key, no results will be returned:
-
-  >>> list(groups.search({}))
-  []
-
-Identifying groups
-------------------
-The function, `setGroupsForPrincipal`, is a subscriber to
-principal-creation events.  It adds any group-folder-defined groups to
-users in those groups:
-
-  >>> principal = principals.getPrincipal('auth.p1')
-
-  >>> principal.groups
-  [u'auth.group.G1', u'auth.group.GA']
-
-Of course, this applies to groups too:
-
-  >>> principal = principals.getPrincipal('auth.group.G1')
-  >>> principal.id
-  'auth.group.G1'
-
-  >>> principal.groups
-  [u'auth.group.G2']
-
-In addition to setting principal groups, the `setGroupsForPrincipal`
-function also declares the `IGroup` interface on groups:
-
-  >>> [iface.__name__ for iface in interface.providedBy(principal)]
-  ['IGroup', 'IGroupAwarePrincipal']
-
-  >>> [iface.__name__
-  ...  for iface in interface.providedBy(principals.getPrincipal('auth.p1'))]
-  ['IGroupAwarePrincipal']
-
-Special groups
---------------
-Two special groups, Authenticated, and Everyone may apply to users
-created by the pluggable-authentication utility.  There is a
-subscriber, specialGroups, that will set these groups on any non-group
-principals if IAuthenticatedGroup, or IEveryoneGroup utilities are
-provided.
-
-Lets define a group-aware principal:
-
-  >>> import zope.security.interfaces
-  >>> class GroupAwarePrincipal(Principal):
-  ...     interface.implements(zope.security.interfaces.IGroupAwarePrincipal)
-  ...     def __init__(self, id):
-  ...         Principal.__init__(self, id)
-  ...         self.groups = []
-
-If we notify the subscriber with this principal, nothing will happen
-because the groups haven't been defined:
-
-  >>> prin = GroupAwarePrincipal('x')
-  >>> event = interfaces.FoundPrincipalCreated(42, prin, {})
-  >>> zope.app.authentication.groupfolder.specialGroups(event)
-  >>> prin.groups
-  []
-
-Now, if we define the Everybody group:
-
-  >>> import zope.app.security.interfaces
-  >>> class EverybodyGroup(Principal):
-  ...     interface.implements(zope.app.security.interfaces.IEveryoneGroup)
-
-  >>> everybody = EverybodyGroup('all')
-  >>> ztapi.provideUtility(zope.app.security.interfaces.IEveryoneGroup,
-  ...                      everybody)
-
-Then the group will be added to the principal:
-
-  >>> zope.app.authentication.groupfolder.specialGroups(event)
-  >>> prin.groups
-  ['all']
-
-Similarly for the authenticated group:
-
-  >>> class AuthenticatedGroup(Principal):
-  ...     interface.implements(
-  ...         zope.app.security.interfaces.IAuthenticatedGroup)
-
-  >>> authenticated = AuthenticatedGroup('auth')
-  >>> ztapi.provideUtility(zope.app.security.interfaces.IAuthenticatedGroup,
-  ...                      authenticated)
-
-Then the group will be added to the principal:
-
-  >>> prin.groups = []
-  >>> zope.app.authentication.groupfolder.specialGroups(event)
-  >>> prin.groups.sort()
-  >>> prin.groups
-  ['all', 'auth']
-
-These groups are only added to non-group principals:
-
-  >>> prin.groups = []
-  >>> interface.directlyProvides(prin, zope.security.interfaces.IGroup)
-  >>> zope.app.authentication.groupfolder.specialGroups(event)
-  >>> prin.groups
-  []
-
-And they are only added to group aware principals:
-
-  >>> class SolitaryPrincipal:
-  ...     interface.implements(zope.security.interfaces.IPrincipal)
-  ...     id = title = description = ''
-
-  >>> event = interfaces.FoundPrincipalCreated(42, SolitaryPrincipal(), {})
-  >>> zope.app.authentication.groupfolder.specialGroups(event)
-  >>> prin.groups
-  []
-
-Member-aware groups
--------------------
-The groupfolder includes a subscriber that gives group principals the
-zope.security.interfaces.IGroupAware interface and an implementation thereof.
-This allows groups to be able to get and set their members.
-
-Given an info object and a group...
-
-    >>> class DemoGroupInformation(object):
-    ...     interface.implements(
-    ...         zope.app.authentication.groupfolder.IGroupInformation)
-    ...     def __init__(self, title, description, principals):
-    ...         self.title = title
-    ...         self.description = description
-    ...         self.principals = principals
-    ...
-    >>> i = DemoGroupInformation(
-    ...     'Managers', 'Taskmasters', ('joe', 'jane'))
-    ...
-    >>> info = zope.app.authentication.groupfolder.GroupInfo(
-    ...     'groups.managers', i)
-    >>> class DummyGroup(object):
-    ...     interface.implements(IGroupAwarePrincipal)
-    ...     def __init__(self, id, title=u'', description=u''):
-    ...         self.id = id
-    ...         self.title = title
-    ...         self.description = description
-    ...         self.groups = []
-    ...
-    >>> principal = DummyGroup('foo')
-    >>> zope.security.interfaces.IMemberAwareGroup.providedBy(principal)
-    False
-
-...when you call the subscriber, it adds the two pseudo-methods to the
-principal and makes the principal provide the IMemberAwareGroup interface.
-
-    >>> zope.app.authentication.groupfolder.setMemberSubscriber(
-    ...     interfaces.FoundPrincipalCreated(
-    ...         'dummy auth (ignored)', principal, info))
-    >>> principal.getMembers()
-    ('joe', 'jane')
-    >>> principal.setMembers(('joe', 'jane', 'jaimie'))
-    >>> principal.getMembers()
-    ('joe', 'jane', 'jaimie')
-    >>> zope.security.interfaces.IMemberAwareGroup.providedBy(principal)
-    True
-
-The two methods work with the value on the IGroupInformation object.
-
-    >>> i.principals == principal.getMembers()
-    True
-
-Limitation
-==========
-
-The current group-folder design has an important limitation!
-
-There is no point in assigning principals to a group 
-from a group folder unless the principal is from the same pluggable
-authentication utility.
-
-o If a principal is from a higher authentication utility, the user
-  will not get the group definition. Why? Because the principals
-  group assignments are set when the principal is authenticated. At
-  that point, the current site is the site containing the principal
-  definition. Groups defined in lower sites will not be consulted,
-
-o It is impossible to assign users from lower authentication
-  utilities because they can't be seen when managing the group,
-  from the site containing the group.
-
-A better design might be to store user-role assignments independent of
-the group definitions and to look for assignments during (url)
-traversal.  This could get quite complex though.
-
-While it is possible to have multiple authentication utilities long a
-URL path, it is generally better to stick to a simpler model in which
-there is only one authentication utility along a URL path (in addition
-to the global utility, which is used for bootstrapping purposes).

Deleted: zope.password/trunk/src/zope/password/groupfolder.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/groupfolder.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/groupfolder.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,66 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    i18n_domain="zope"
-    >
-
-  <class class=".groupfolder.GroupInformation">
-    <implements
-        interface="zope.annotation.interfaces.IAttributeAnnotatable"
-        />
-    <require
-        permission="zope.ManageServices"
-        interface=".groupfolder.IGroupInformation
-                   .groupfolder.IGroupContained"
-        set_schema=".groupfolder.IGroupInformation"
-        />
-  </class>
-
-  <class class=".groupfolder.GroupFolder">
-    <implements
-        interface=".groupfolder.IGroupFolder"
-        />
-    <require
-        permission="zope.ManageServices"
-        interface="zope.container.interfaces.IContainer
-                   zope.container.interfaces.INameChooser"
-        />
-  </class>
-
-  <adapter
-      provides="zope.container.interfaces.INameChooser"
-      for=".groupfolder.IGroupFolder"
-      factory=".idpicker.IdPicker"
-      />
-
-  <subscriber
-      for=".interfaces.IPrincipalCreated"
-      handler=".groupfolder.specialGroups"
-      />
-
-  <subscriber
-      for=".interfaces.IPrincipalCreated"
-      handler=".groupfolder.setGroupsForPrincipal"
-      />
-
-  <subscriber
-      handler=".groupfolder.setMemberSubscriber"
-      />
-
-  <include package=".browser" file="groupfolder.zcml" />
-
-  <!-- Registering documentation with API doc -->
-  <configure
-      xmlns:apidoc="http://namespaces.zope.org/apidoc"
-      xmlns:zcml="http://namespaces.zope.org/zcml"
-      zcml:condition="have apidoc">
-
-    <apidoc:bookchapter
-        id="groupfolder"
-        title="Group Folders"
-        doc_path="groupfolder.txt"
-        parent="security/authentication"
-        />
-
-  </configure>
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/httpplugins.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/httpplugins.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/httpplugins.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,142 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""PAS plugins related to HTTP
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-import base64
-from persistent import Persistent
-from zope.interface import implements, Interface
-from zope.publisher.interfaces.http import IHTTPRequest
-from zope.schema import TextLine
-
-from zope.container.contained import Contained
-from zope.app.authentication import interfaces
-
-
-class IHTTPBasicAuthRealm(Interface):
-    """HTTP Basic Auth Realm
-
-    Represents the realm string that is used during basic HTTP authentication
-    """
-
-    realm = TextLine(title=u'Realm',
-                     description=u'HTTP Basic Authentication Realm',
-                     required=True,
-                     default=u'Zope')
-
-
-class HTTPBasicAuthCredentialsPlugin(Persistent, Contained):
-
-    implements(interfaces.ICredentialsPlugin, IHTTPBasicAuthRealm)
-
-    realm = 'Zope'
-
-    protocol = 'http auth'
-
-    def extractCredentials(self, request):
-        """Extracts HTTP basic auth credentials from a request.
-
-        First we need to create a request that contains some credentials.
-
-          >>> from zope.publisher.browser import TestRequest
-          >>> request = TestRequest(
-          ...     environ={'HTTP_AUTHORIZATION': u'Basic bWdyOm1ncnB3'})
-
-        Now create the plugin and get the credentials.
-
-          >>> plugin = HTTPBasicAuthCredentialsPlugin()
-          >>> plugin.extractCredentials(request)
-          {'login': u'mgr', 'password': u'mgrpw'}
-
-        Make sure we return `None`, if no authentication header has been
-        specified.
-
-          >>> print plugin.extractCredentials(TestRequest())
-          None
-
-        Also, this plugin can *only* handle basic authentication.
-
-          >>> request = TestRequest(environ={'HTTP_AUTHORIZATION': 'foo bar'})
-          >>> print plugin.extractCredentials(TestRequest())
-          None
-
-        This plugin only works with HTTP requests.
-
-          >>> from zope.publisher.base import TestRequest
-          >>> print plugin.extractCredentials(TestRequest('/'))
-          None
-
-        """
-        if not IHTTPRequest.providedBy(request):
-            return None
-
-        if request._auth:
-            if request._auth.lower().startswith(u'basic '):
-                credentials = request._auth.split()[-1]
-                login, password = base64.decodestring(credentials).split(':')
-                return {'login': login.decode('utf-8'),
-                        'password': password.decode('utf-8')}
-        return None
-
-    def challenge(self, request):
-        """Issues an HTTP basic auth challenge for credentials.
-
-        The challenge is issued by setting the appropriate response headers.
-        To illustrate, we'll create a plugin:
-
-          >>> plugin = HTTPBasicAuthCredentialsPlugin()
-
-        The plugin adds its challenge to the HTTP response.
-
-          >>> from zope.publisher.browser import TestRequest
-          >>> request = TestRequest()
-          >>> response = request.response
-          >>> plugin.challenge(request)
-          True
-          >>> response._status
-          401
-          >>> response.getHeader('WWW-Authenticate', literal=True)
-          'basic realm="Zope"'
-
-        Notice that the realm is quoted, as per RFC 2617.
-
-        The plugin only works with HTTP requests.
-
-          >>> from zope.publisher.base import TestRequest
-          >>> request = TestRequest('/')
-          >>> response = request.response
-          >>> print plugin.challenge(request)
-          False
-
-        """
-        if not IHTTPRequest.providedBy(request):
-            return False
-        request.response.setHeader("WWW-Authenticate",
-                                   'basic realm="%s"' % self.realm,
-                                   literal=True)
-        request.response.setStatus(401)
-        return True
-
-    def logout(self, request):
-        """Always returns False as logout is not supported by basic auth.
-
-          >>> plugin = HTTPBasicAuthCredentialsPlugin()
-          >>> from zope.publisher.browser import TestRequest
-          >>> plugin.logout(TestRequest())
-          False
-
-        """
-        return False

Deleted: zope.password/trunk/src/zope/password/httpplugins.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/httpplugins.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/httpplugins.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,25 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    i18n_domain="zope"
-    >
-
-  <utility
-      name="Zope Realm Basic-Auth"
-      provides=".interfaces.ICredentialsPlugin"
-      factory=".httpplugins.HTTPBasicAuthCredentialsPlugin"
-      />
-
-  <class class=".httpplugins.HTTPBasicAuthCredentialsPlugin">
-    <implements
-        interface="zope.annotation.interfaces.IAttributeAnnotatable"
-        />
-    <require
-        permission="zope.ManageServices"
-        interface=".httpplugins.IHTTPBasicAuthRealm"
-        set_schema=".httpplugins.IHTTPBasicAuthRealm"
-        />
-  </class>
-
-  <include package=".browser" file="httpplugins.zcml" />
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/i18n.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/i18n.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/i18n.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,22 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 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.
-#
-##############################################################################
-"""Customization of zope.i18n for the Zope application server
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-# import this as _ to create i18n messages in the zope domain
-from zope.i18nmessageid import MessageFactory
-ZopeMessageFactory = MessageFactory('zope')

Deleted: zope.password/trunk/src/zope/password/idpicker.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/idpicker.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/idpicker.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,109 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (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.
-#
-##############################################################################
-"""Helper base class that picks principal ids
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-import re
-from zope.exceptions.interfaces import UserError
-from zope.container.contained import NameChooser
-from zope.app.authentication.i18n import ZopeMessageFactory as _
-
-ok = re.compile('[!-~]+$').match
-class IdPicker(NameChooser):
-    """Helper base class that picks principal ids.
-
-    Add numbers to ids given by users to make them unique.
-
-    The Id picker is a variation on the name chooser that picks numeric
-    ids when no name is given.
-
-      >>> from zope.app.authentication.idpicker import IdPicker
-      >>> IdPicker({}).chooseName('', None)
-      u'1'
-
-      >>> IdPicker({'1': 1}).chooseName('', None)
-      u'2'
-
-      >>> IdPicker({'2': 1}).chooseName('', None)
-      u'1'
-
-      >>> IdPicker({'1': 1}).chooseName('bob', None)
-      u'bob'
-
-      >>> IdPicker({'bob': 1}).chooseName('bob', None)
-      u'bob1'
-
-    """
-    def chooseName(self, name, object):
-        i = 0
-        name = unicode(name)
-        orig = name
-        while (not name) or (name in self.context):
-            i += 1
-            name = orig+str(i)
-
-        self.checkName(name, object)
-        return name
-
-    def checkName(self, name, object):
-        """Limit ids
-
-        Ids can only contain printable, non-space, 7-bit ASCII strings:
-
-        >>> from zope.app.authentication.idpicker import IdPicker
-        >>> IdPicker({}).checkName(u'1', None)
-        True
-
-        >>> IdPicker({}).checkName(u'bob', None)
-        True
-
-        >>> IdPicker({}).checkName(u'bob\xfa', None)
-        ... # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-        ...
-        UserError: Ids must contain only printable
-        7-bit non-space ASCII characters
-
-        >>> IdPicker({}).checkName(u'big bob', None)
-        ... # doctest: +NORMALIZE_WHITESPACE
-        Traceback (most recent call last):
-        ...
-        UserError: Ids must contain only printable
-        7-bit non-space ASCII characters
-
-        Ids also can't be over 100 characters long:
-
-        >>> IdPicker({}).checkName(u'x' * 100, None)
-        True
-
-        >>> IdPicker({}).checkName(u'x' * 101, None)
-        Traceback (most recent call last):
-        ...
-        UserError: Ids can't be more than 100 characters long.
-
-        """
-        NameChooser.checkName(self, name, object)
-        if not ok(name):
-            raise UserError(
-                _("Ids must contain only printable 7-bit non-space"
-                  " ASCII characters")
-                )
-        if len(name) > 100:
-            raise UserError(
-                _("Ids can't be more than 100 characters long.")
-                )
-        return True

Modified: zope.password/trunk/src/zope/password/interfaces.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/interfaces.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/interfaces.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2004 Zope Corporation and Contributors.
+# Copyright (c) 2009 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -11,141 +11,12 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Pluggable Authentication Utility Interfaces
+"""Password manager interface
 
 $Id$
 """
-__docformat__ = "reStructuredText"
-
 import zope.interface
-import zope.schema
-import zope.security.interfaces
-from zope.app.authentication.i18n import ZopeMessageFactory as _
-from zope.app.security.interfaces import ILogout
-from zope.container.constraints import contains, containers
-from zope.container.interfaces import IContainer
 
-
-class IPlugin(zope.interface.Interface):
-    """A plugin for a pluggable authentication component."""
-
-
-class IPluggableAuthentication(ILogout, IContainer):
-    """Provides authentication services with the help of various plugins.
-    
-    IPluggableAuthentication implementations will also implement
-    zope.app.security.interfaces.IAuthentication.  The `authenticate` method
-    of this interface in an IPluggableAuthentication should annotate the
-    IPrincipalInfo with the credentials plugin and authentication plugin used.
-    The `getPrincipal` method should annotate the IPrincipalInfo with the
-    authentication plugin used.
-    """
-
-    contains(IPlugin)
-
-    credentialsPlugins = zope.schema.List(
-        title=_('Credentials Plugins'),
-        description=_("""Used for extracting credentials.
-        Names may be of ids of non-utility ICredentialsPlugins contained in
-        the IPluggableAuthentication, or names of registered
-        ICredentialsPlugins utilities.  Contained non-utility ids mask 
-        utility names."""),
-        value_type=zope.schema.Choice(vocabulary='CredentialsPlugins'),
-        default=[],
-        )
-
-    authenticatorPlugins = zope.schema.List(
-        title=_('Authenticator Plugins'),
-        description=_("""Used for converting credentials to principals.
-        Names may be of ids of non-utility IAuthenticatorPlugins contained in
-        the IPluggableAuthentication, or names of registered
-        IAuthenticatorPlugins utilities.  Contained non-utility ids mask 
-        utility names."""),
-        value_type=zope.schema.Choice(vocabulary='AuthenticatorPlugins'),
-        default=[],
-        )
-
-    def getCredentialsPlugins():
-        """Return iterable of (plugin name, actual credentials plugin) pairs.
-        Looks up names in credentialsPlugins as contained ids of non-utility
-        ICredentialsPlugins first, then as registered ICredentialsPlugin
-        utilities.  Names that do not resolve are ignored."""
-
-    def getAuthenticatorPlugins():
-        """Return iterable of (plugin name, actual authenticator plugin) pairs.
-        Looks up names in authenticatorPlugins as contained ids of non-utility
-        IAuthenticatorPlugins first, then as registered IAuthenticatorPlugin
-        utilities.  Names that do not resolve are ignored."""
-
-    prefix = zope.schema.TextLine(
-        title=_('Prefix'),
-        default=u'',
-        required=True,
-        readonly=True,
-        )
-
-    def logout(request):
-        """Performs a logout by delegating to its authenticator plugins."""
-
-
-class ICredentialsPlugin(IPlugin):
-    """Handles credentials extraction and challenges per request."""
-
-    containers(IPluggableAuthentication)
-
-    challengeProtocol = zope.interface.Attribute(
-        """A challenge protocol used by the plugin.
-
-        If a credentials plugin works with other credentials pluggins, it
-        and the other cooperating plugins should specify a common (non-None)
-        protocol. If a plugin returns True from its challenge method, then
-        other credentials plugins will be called only if they have the same
-        protocol.
-        """)
-
-    def extractCredentials(request):
-        """Ties to extract credentials from a request.
-
-        A return value of None indicates that no credentials could be found.
-        Any other return value is treated as valid credentials.
-        """
-
-    def challenge(request):
-        """Possibly issues a challenge.
-
-        This is typically done in a protocol-specific way.
-
-        If a challenge was issued, return True, otherwise return False.
-        """
-
-    def logout(request):
-        """Possibly logout.
-
-        If a logout was performed, return True, otherwise return False.
-        """
-
-class IAuthenticatorPlugin(IPlugin):
-    """Authenticates a principal using credentials.
-
-    An authenticator may also be responsible for providing information
-    about and creating principals.
-    """
-    containers(IPluggableAuthentication)
-
-    def authenticateCredentials(credentials):
-        """Authenticates credentials.
-
-        If the credentials can be authenticated, return an object that provides
-        IPrincipalInfo. If the plugin cannot authenticate the credentials,
-        returns None.
-        """
-
-    def principalInfo(id):
-        """Returns an IPrincipalInfo object for the specified principal id.
-
-        If the plugin cannot find information for the id, returns None.
-        """
-
 class IPasswordManager(zope.interface.Interface):
     """Password manager."""
 
@@ -154,196 +25,3 @@
 
     def checkPassword(storedPassword, password):
         """Return whether the password coincide with the storedPassword."""
-
-class IPrincipalInfo(zope.interface.Interface):
-    """Minimal information about a principal."""
-
-    id = zope.interface.Attribute("The principal id.")
-
-    title = zope.interface.Attribute("The principal title.")
-
-    description = zope.interface.Attribute("A description of the principal.")
-
-    credentialsPlugin = zope.interface.Attribute(
-        """Plugin used to generate the credentials for this principal info.
-        
-        Optional.  Should be set in IPluggableAuthentication.authenticate.
-        """)
-
-    authenticatorPlugin = zope.interface.Attribute(
-        """Plugin used to authenticate the credentials for this principal info.
-        
-        Optional.  Should be set in IPluggableAuthentication.authenticate and
-        IPluggableAuthentication.getPrincipal.
-        """)
-
-class IPrincipal(zope.security.interfaces.IGroupClosureAwarePrincipal):
-
-    groups = zope.schema.List(
-        title=_("Groups"),
-        description=_(
-            """ids of groups to which the principal directly belongs.
-
-            Plugins may append to this list.  Mutating the list only affects
-            the life of the principal object, and does not persist (so
-            persistently adding groups to a principal should be done by working
-            with a plugin that mutates this list every time the principal is
-            created, like the group folder in this package.)
-            """),
-        value_type=zope.schema.TextLine(),
-        required=False)
-
-class IPrincipalFactory(zope.interface.Interface):
-    """A principal factory."""
-
-    def __call__(authentication):
-        """Creates a principal.
-
-        The authentication utility that called the factory is passed
-        and should be included in the principal-created event.
-        """
-
-
-class IFoundPrincipalFactory(IPrincipalFactory):
-    """A found principal factory."""
-
-
-class IAuthenticatedPrincipalFactory(IPrincipalFactory):
-    """An authenticated principal factory."""
-
-
-class IPrincipalCreated(zope.interface.Interface):
-    """A principal has been created."""
-
-    principal = zope.interface.Attribute("The principal that was created")
-
-    authentication = zope.interface.Attribute(
-        "The authentication utility that created the principal")
-
-    info = zope.interface.Attribute("An object providing IPrincipalInfo.")
-
-
-class IAuthenticatedPrincipalCreated(IPrincipalCreated):
-    """A principal has been created by way of an authentication operation."""
-
-    request = zope.interface.Attribute(
-        "The request the user was authenticated against")
-
-
-class AuthenticatedPrincipalCreated:
-    """
-    >>> from zope.interface.verify import verifyObject
-    >>> event = AuthenticatedPrincipalCreated("authentication", "principal",
-    ...     "info", "request")
-    >>> verifyObject(IAuthenticatedPrincipalCreated, event)
-    True
-    """
-
-    zope.interface.implements(IAuthenticatedPrincipalCreated)
-
-    def __init__(self, authentication, principal, info, request):
-        self.authentication = authentication
-        self.principal = principal
-        self.info = info
-        self.request = request
-
-
-class IFoundPrincipalCreated(IPrincipalCreated):
-    """A principal has been created by way of a search operation."""
-
-
-class FoundPrincipalCreated:
-    """
-    >>> from zope.interface.verify import verifyObject
-    >>> event = FoundPrincipalCreated("authentication", "principal",
-    ...     "info")
-    >>> verifyObject(IFoundPrincipalCreated, event)
-    True
-    """
-
-    zope.interface.implements(IFoundPrincipalCreated)
-
-    def __init__(self, authentication, principal, info):
-        self.authentication = authentication
-        self.principal = principal
-        self.info = info
-
-
-class IQueriableAuthenticator(zope.interface.Interface):
-    """Indicates the authenticator provides a search UI for principals."""
-
-
-class IQuerySchemaSearch(zope.interface.Interface):
-    """An interface for searching using schema-constrained input."""
-
-    schema = zope.interface.Attribute("""
-        The schema that constrains the input provided to the search method.
-
-        A mapping of name/value pairs for each field in this schema is used
-        as the query argument in the search method.
-        """)
-
-    def search(query, start=None, batch_size=None):
-        """Returns an iteration of principal IDs matching the query.
-
-        query is a mapping of name/value pairs for fields specified by the
-        schema.
-
-        If the start argument is provided, then it should be an
-        integer and the given number of initial items should be
-        skipped.
-
-        If the batch_size argument is provided, then it should be an
-        integer and no more than the given number of items should be
-        returned.
-        """
-
-class IGroupAdded(zope.interface.Interface):
-    """A group has been added."""
-
-    group = zope.interface.Attribute("""The group that was defined""")
-
-
-class GroupAdded:
-    """
-    >>> from zope.interface.verify import verifyObject
-    >>> event = GroupAdded("group")
-    >>> verifyObject(IGroupAdded, event)
-    True
-    """
-
-    zope.interface.implements(IGroupAdded)
-
-    def __init__(self, group):
-        self.group = group
-
-    def __repr__(self):
-        return "<GroupAdded %r>" % self.group.id
-
-class IPrincipalsAddedToGroup(zope.interface.Interface):
-    group_id = zope.interface.Attribute(
-        'the id of the group to which the principal was added')
-    principal_ids = zope.interface.Attribute(
-        'an iterable of one or more ids of principals added')
-
-class IPrincipalsRemovedFromGroup(zope.interface.Interface):
-    group_id = zope.interface.Attribute(
-        'the id of the group from which the principal was removed')
-    principal_ids = zope.interface.Attribute(
-        'an iterable of one or more ids of principals removed')
-
-class AbstractMembersChanged(object):
-
-    def __init__(self, principal_ids, group_id):
-        self.principal_ids = principal_ids
-        self.group_id = group_id
-
-    def __repr__(self):
-        return "<%s %r %r>" % (
-            self.__class__.__name__, sorted(self.principal_ids), self.group_id)
-
-class PrincipalsAddedToGroup(AbstractMembersChanged):
-    zope.interface.implements(IPrincipalsAddedToGroup)
-
-class PrincipalsRemovedFromGroup(AbstractMembersChanged):
-    zope.interface.implements(IPrincipalsRemovedFromGroup)

Modified: zope.password/trunk/src/zope/password/password.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/password.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/password.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2004 Zope Corporation and Contributors.
+# Copyright (c) 2009 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -17,6 +17,11 @@
 """
 __docformat__ = 'restructuredtext'
 
+from base64 import urlsafe_b64encode
+from base64 import urlsafe_b64decode
+from os import urandom
+from random import randint
+from codecs import getencoder
 try:
     from hashlib import md5, sha1
 except ImportError:
@@ -24,19 +29,9 @@
     from md5 import new as md5
     from sha import new as sha1
 
-from base64 import urlsafe_b64encode
-from base64 import urlsafe_b64decode
-from os import urandom
-from random import randint
-from codecs import getencoder
+from zope.interface import implements
+from zope.password.interfaces import IPasswordManager
 
-from zope.interface import implements, classProvides
-from zope.schema.interfaces import IVocabularyFactory
-from zope.app.component.vocabulary import UtilityVocabulary
-
-from zope.app.authentication.interfaces import IPasswordManager
-
-
 _encoder = getencoder("utf-8")
 
 
@@ -68,30 +63,47 @@
         return storedPassword == self.encodePassword(password)
 
 
-class MD5PasswordManager(PlainTextPasswordManager):
-    """MD5 password manager.
+class SSHAPasswordManager(PlainTextPasswordManager):
+    """SSHA password manager.
 
-    Note: use of salt in this password manager is purely
-    cosmetical. Use SSHA if you want increased security.
+    SSHA is basically SHA1-encoding which also incorporates a salt
+    into the encoded string. This way, stored passwords are more
+    robust against dictionary attacks of attackers that could get
+    access to lists of encoded passwords.
+
+    SSHA is regularly used in LDAP databases and we should be
+    compatible with passwords used there.
     
     >>> from zope.interface.verify import verifyObject
 
-    >>> manager = MD5PasswordManager()
+    >>> manager = SSHAPasswordManager()
     >>> verifyObject(IPasswordManager, manager)
     True
 
     >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
     >>> encoded = manager.encodePassword(password, salt="")
     >>> encoded
-    '{MD5}86dddccec45db4599f1ac00018e54139'
+    '{SSHA}BLTuxxVMXzouxtKVb7gLgNxzdAI='
+
     >>> manager.checkPassword(encoded, password)
     True
     >>> manager.checkPassword(encoded, password + u"wrong")
     False
 
+    Using the `slappasswd` utility to encode ``secret``, we get
+    ``{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv`` as seeded hash.
+
+    Our password manager generates the same value when seeded with the
+    same salt, so we can be sure, our output is compatible with
+    standard LDAP tools that also use SSHA::
+    
+    >>> from base64 import urlsafe_b64decode
+    >>> salt = urlsafe_b64decode('XkOZbw==')
+    >>> encoded = manager.encodePassword('secret', salt)
+    >>> encoded
+    '{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv'
+    
     >>> encoded = manager.encodePassword(password)
-    >>> encoded[-32:]
-    '86dddccec45db4599f1ac00018e54139'
     >>> manager.checkPassword(encoded, password)
     True
     >>> manager.checkPassword(encoded, password + u"wrong")
@@ -105,41 +117,42 @@
 
     def encodePassword(self, password, salt=None):
         if salt is None:
-            salt = "%08x" % randint(0, 0xffffffff)
-        return '{MD5}%s%s' % (salt, md5(_encoder(password)[0]).hexdigest())
+            salt = urandom(4)
+        hash = sha1(_encoder(password)[0])
+        hash.update(salt)
+        return '{SSHA}' + urlsafe_b64encode(
+            hash.digest() + salt)
 
     def checkPassword(self, storedPassword, password):
-        if storedPassword.startswith('{MD5}'):
-            salt = storedPassword[5:-32]
-            return storedPassword == self.encodePassword(password, salt)
-        salt = storedPassword[:-32]
-        return storedPassword == self.encodePassword(password, salt)[5:]
+        byte_string = urlsafe_b64decode(storedPassword[6:])
+        salt = byte_string[20:]
+        return storedPassword == self.encodePassword(password, salt)
 
 
-class SHA1PasswordManager(PlainTextPasswordManager):
-    """SHA1 password manager.
+class MD5PasswordManager(PlainTextPasswordManager):
+    """MD5 password manager.
 
     Note: use of salt in this password manager is purely
     cosmetical. Use SSHA if you want increased security.
     
     >>> from zope.interface.verify import verifyObject
 
-    >>> manager = SHA1PasswordManager()
+    >>> manager = MD5PasswordManager()
     >>> verifyObject(IPasswordManager, manager)
     True
 
     >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
     >>> encoded = manager.encodePassword(password, salt="")
     >>> encoded
-    '{SHA1}04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
+    '{MD5}86dddccec45db4599f1ac00018e54139'
     >>> manager.checkPassword(encoded, password)
     True
     >>> manager.checkPassword(encoded, password + u"wrong")
     False
 
     >>> encoded = manager.encodePassword(password)
-    >>> encoded[-40:]
-    '04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
+    >>> encoded[-32:]
+    '86dddccec45db4599f1ac00018e54139'
     >>> manager.checkPassword(encoded, password)
     True
     >>> manager.checkPassword(encoded, password + u"wrong")
@@ -154,56 +167,40 @@
     def encodePassword(self, password, salt=None):
         if salt is None:
             salt = "%08x" % randint(0, 0xffffffff)
-        return '{SHA1}%s%s' % (salt, sha1(_encoder(password)[0]).hexdigest())
+        return '{MD5}%s%s' % (salt, md5(_encoder(password)[0]).hexdigest())
 
     def checkPassword(self, storedPassword, password):
-        if storedPassword.startswith('{SHA1}'):
-            salt = storedPassword[6:-40]
+        if storedPassword.startswith('{MD5}'):
+            salt = storedPassword[5:-32]
             return storedPassword == self.encodePassword(password, salt)
-        salt = storedPassword[:-40]
-        return storedPassword == self.encodePassword(password, salt)[6:]
+        salt = storedPassword[:-32]
+        return storedPassword == self.encodePassword(password, salt)[5:]
 
-class SSHAPasswordManager(PlainTextPasswordManager):
-    """SSHA password manager.
 
-    SSHA is basically SHA1-encoding which also incorporates a salt
-    into the encoded string. This way, stored passwords are more
-    robust against dictionary attacks of attackers that could get
-    access to lists of encoded passwords.
+class SHA1PasswordManager(PlainTextPasswordManager):
+    """SHA1 password manager.
 
-    SSHA is regularly used in LDAP databases and we should be
-    compatible with passwords used there.
+    Note: use of salt in this password manager is purely
+    cosmetical. Use SSHA if you want increased security.
     
     >>> from zope.interface.verify import verifyObject
 
-    >>> manager = SSHAPasswordManager()
+    >>> manager = SHA1PasswordManager()
     >>> verifyObject(IPasswordManager, manager)
     True
 
     >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
     >>> encoded = manager.encodePassword(password, salt="")
     >>> encoded
-    '{SSHA}BLTuxxVMXzouxtKVb7gLgNxzdAI='
-
+    '{SHA1}04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
     >>> manager.checkPassword(encoded, password)
     True
     >>> manager.checkPassword(encoded, password + u"wrong")
     False
 
-    Using the `slappasswd` utility to encode ``secret``, we get
-    ``{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv`` as seeded hash.
-
-    Our password manager generates the same value when seeded with the
-    same salt, so we can be sure, our output is compatible with
-    standard LDAP tools that also use SSHA::
-    
-    >>> from base64 import urlsafe_b64decode
-    >>> salt = urlsafe_b64decode('XkOZbw==')
-    >>> encoded = manager.encodePassword('secret', salt)
-    >>> encoded
-    '{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv'
-    
     >>> encoded = manager.encodePassword(password)
+    >>> encoded[-40:]
+    '04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
     >>> manager.checkPassword(encoded, password)
     True
     >>> manager.checkPassword(encoded, password + u"wrong")
@@ -217,29 +214,12 @@
 
     def encodePassword(self, password, salt=None):
         if salt is None:
-            salt = urandom(4)
-        hash = sha1(_encoder(password)[0])
-        hash.update(salt)
-        return '{SSHA}' + urlsafe_b64encode(
-            hash.digest() + salt)
+            salt = "%08x" % randint(0, 0xffffffff)
+        return '{SHA1}%s%s' % (salt, sha1(_encoder(password)[0]).hexdigest())
 
     def checkPassword(self, storedPassword, password):
-        byte_string = urlsafe_b64decode(storedPassword[6:])
-        salt = byte_string[20:]
-        return storedPassword == self.encodePassword(password, salt)
-
-# Simple registry used by mkzopeinstance script
-managers = [
-    ("Plain Text", PlainTextPasswordManager()), # default
-    ("MD5", MD5PasswordManager()),
-    ("SHA1", SHA1PasswordManager()),
-    ("SSHA", SSHAPasswordManager()),
-]
-
-
-class PasswordManagerNamesVocabulary(UtilityVocabulary):
-    """Vocabulary of password managers."""
-
-    classProvides(IVocabularyFactory)
-    interface = IPasswordManager
-    nameOnly = True
+        if storedPassword.startswith('{SHA1}'):
+            salt = storedPassword[6:-40]
+            return storedPassword == self.encodePassword(password, salt)
+        salt = storedPassword[:-40]
+        return storedPassword == self.encodePassword(password, salt)[6:]

Deleted: zope.password/trunk/src/zope/password/password.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/password.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/password.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,47 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    i18n_domain="zope"
-    >
-
-  <utility
-      component=".password.PasswordManagerNamesVocabulary"
-      name="Password Manager Names"
-      />
-
-  <class class=".password.PlainTextPasswordManager">
-    <allow interface=".interfaces.IPasswordManager" />
-  </class>
-
-  <utility
-      name="Plain Text"
-      provides=".interfaces.IPasswordManager"
-      factory=".password.PlainTextPasswordManager"
-      />
-
-  <class class=".password.MD5PasswordManager">
-    <allow interface=".interfaces.IPasswordManager" />
-  </class>
-
-  <utility
-      name="MD5"
-      provides=".interfaces.IPasswordManager"
-      factory=".password.MD5PasswordManager"
-      />
-
-  <class class=".password.SHA1PasswordManager">
-    <allow interface=".interfaces.IPasswordManager" />
-  </class>
-
-  <utility
-      name="SHA1"
-      provides=".interfaces.IPasswordManager"
-      factory=".password.SHA1PasswordManager"
-      />
-
-  <utility
-      name="SSHA"
-      provides=".interfaces.IPasswordManager"
-      factory=".password.SSHAPasswordManager"
-      />
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/placelesssetup.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/placelesssetup.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/placelesssetup.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,35 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""Pluggable Authentication Service Placeless Setup
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-
-from zope.app.testing import ztapi
-from zope.app.authentication.interfaces import IPasswordManager
-from zope.app.authentication.password import PlainTextPasswordManager
-from zope.app.authentication.password import MD5PasswordManager
-from zope.app.authentication.password import SHA1PasswordManager
-from zope.app.authentication.password import SSHAPasswordManager
-
-
-class PlacelessSetup(object):
-
-    def setUp(self):
-        ztapi.provideUtility(IPasswordManager, PlainTextPasswordManager(),
-            "Plain Text")
-        ztapi.provideUtility(IPasswordManager, MD5PasswordManager(), "MD5")
-        ztapi.provideUtility(IPasswordManager, SHA1PasswordManager(), "SHA1")
-        ztapi.provideUtility(IPasswordManager, SSHAPasswordManager(), "SSHA")

Deleted: zope.password/trunk/src/zope/password/principalfolder.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/principalfolder.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/principalfolder.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,565 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-"""ZODB-based Authentication Source
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-
-from persistent import Persistent
-from zope import interface
-from zope import component
-from zope.event import notify
-from zope.schema import Text, TextLine, Password, Choice
-from zope.publisher.interfaces import IRequest
-
-from zope.container.interfaces import DuplicateIDError
-from zope.container.contained import Contained
-from zope.container.constraints import contains, containers
-from zope.container.btree import BTreeContainer
-from zope.app.authentication.i18n import ZopeMessageFactory as _
-from zope.app.security.interfaces import IAuthentication
-
-from zope.app.authentication import interfaces
-
-
-class IInternalPrincipal(interface.Interface):
-    """Principal information"""
-
-    login = TextLine(
-        title=_("Login"),
-        description=_("The Login/Username of the principal. "
-                      "This value can change."))
-
-    def setPassword(password, passwordManagerName=None):
-        pass
-
-    password = Password(
-        title=_("Password"),
-        description=_("The password for the principal."))
-
-    passwordManagerName = Choice(
-        title=_("Password Manager"),
-        vocabulary="Password Manager Names",
-        description=_("The password manager will be used"
-            " for encode/check the password"),
-        default="SSHA",
-        # TODO: The password manager name may be changed only
-        # if the password changed
-        readonly=True
-        )
-
-    title = TextLine(
-        title=_("Title"),
-        description=_("Provides a title for the principal."))
-
-    description = Text(
-        title=_("Description"),
-        description=_("Provides a description for the principal."),
-        required=False,
-        missing_value='',
-        default=u'')
-
-
-class IInternalPrincipalContainer(interface.Interface):
-    """A container that contains internal principals."""
-
-    prefix = TextLine(
-        title=_("Prefix"),
-        description=_(
-        "Prefix to be added to all principal ids to assure "
-        "that all ids are unique within the authentication service"),
-        missing_value=u"",
-        default=u'',
-        readonly=True)
-
-    def getIdByLogin(login):
-        """Return the principal id currently associated with login.
-
-        The return value includes the container prefix, but does not
-        include the PAU prefix.
-
-        KeyError is raised if no principal is associated with login.
-
-        """
-
-    contains(IInternalPrincipal)
-
-
-class IInternalPrincipalContained(interface.Interface):
-    """Principal information"""
-
-    containers(IInternalPrincipalContainer)
-
-
-class ISearchSchema(interface.Interface):
-    """Search Interface for this Principal Provider"""
-
-    search = TextLine(
-        title=_("Search String"),
-        description=_("A Search String"),
-        required=False,
-        default=u'',
-        missing_value=u'')
-
-
-class InternalPrincipal(Persistent, Contained):
-    """An internal principal for Persistent Principal Folder."""
-
-    interface.implements(IInternalPrincipal, IInternalPrincipalContained)
-
-    # If you're searching for self._passwordManagerName, or self._password
-    # probably you just need to evolve the database to new generation
-    # at /++etc++process/@@generations.html
-
-    # NOTE: All changes needs to be synchronized with the evolver at
-    # zope.app.zopeappgenerations.evolve2
-
-    def __init__(self, login, password, title, description=u'',
-            passwordManagerName="SSHA"):
-        self._login = login
-        self._passwordManagerName = passwordManagerName
-        self.password = password
-        self.title = title
-        self.description = description
-
-    def getPasswordManagerName(self):
-        return self._passwordManagerName
-
-    passwordManagerName = property(getPasswordManagerName)
-
-    def _getPasswordManager(self):
-        return component.getUtility(
-            interfaces.IPasswordManager, self.passwordManagerName)
-
-    def getPassword(self):
-        return self._password
-
-    def setPassword(self, password, passwordManagerName=None):
-        if passwordManagerName is not None:
-            self._passwordManagerName = passwordManagerName
-        passwordManager = self._getPasswordManager()
-        self._password = passwordManager.encodePassword(password)
-
-    password = property(getPassword, setPassword)
-
-    def checkPassword(self, password):
-        passwordManager = self._getPasswordManager()
-        return passwordManager.checkPassword(self.password, password)
-
-    def getPassword(self):
-        return self._password
-
-    def getLogin(self):
-        return self._login
-
-    def setLogin(self, login):
-        oldLogin = self._login
-        self._login = login
-        if self.__parent__ is not None:
-            try:
-                self.__parent__.notifyLoginChanged(oldLogin, self)
-            except ValueError:
-                self._login = oldLogin
-                raise
-
-    login = property(getLogin, setLogin)
-
-
-class PrincipalInfo(object):
-    """An implementation of IPrincipalInfo used by the principal folder.
-
-    A principal info is created with id, login, title, and description:
-
-      >>> info = PrincipalInfo('users.foo', 'foo', 'Foo', 'An over-used term.')
-      >>> info
-      PrincipalInfo('users.foo')
-      >>> info.id
-      'users.foo'
-      >>> info.login
-      'foo'
-      >>> info.title
-      'Foo'
-      >>> info.description
-      'An over-used term.'
-
-    """
-    interface.implements(interfaces.IPrincipalInfo)
-
-    def __init__(self, id, login, title, description):
-        self.id = id
-        self.login = login
-        self.title = title
-        self.description = description
-
-    def __repr__(self):
-        return 'PrincipalInfo(%r)' % self.id
-
-
-class PrincipalFolder(BTreeContainer):
-    """A Persistent Principal Folder and Authentication plugin.
-
-    See principalfolder.txt for details.
-    """
-
-    interface.implements(interfaces.IAuthenticatorPlugin,
-                         interfaces.IQuerySchemaSearch,
-                         IInternalPrincipalContainer)
-
-    schema = ISearchSchema
-
-    def __init__(self, prefix=''):
-        self.prefix = unicode(prefix)
-        super(PrincipalFolder, self).__init__()
-        self.__id_by_login = self._newContainerData()
-
-    def notifyLoginChanged(self, oldLogin, principal):
-        """Notify the Container about changed login of a principal.
-
-        We need this, so that our second tree can be kept up-to-date.
-        """
-        # A user with the new login already exists
-        if principal.login in self.__id_by_login:
-            raise ValueError('Principal Login already taken!')
-
-        del self.__id_by_login[oldLogin]
-        self.__id_by_login[principal.login] = principal.__name__
-
-    def __setitem__(self, id, principal):
-        """Add principal information.
-
-        Create a Principal Folder
-
-            >>> pf = PrincipalFolder()
-
-        Create a principal with 1 as id
-        Add a login attr since __setitem__ is in need of one
-
-            >>> principal = Principal(1)
-            >>> principal.login = 1
-
-        Add the principal within the Principal Folder
-
-            >>> pf.__setitem__(u'1', principal)
-
-        Try to add another principal with the same id.
-        It should raise a DuplicateIDError
-
-            >>> try:
-            ...     pf.__setitem__(u'1', principal)
-            ... except DuplicateIDError, e:
-            ...     pass
-            >>>
-        """
-        # A user with the new login already exists
-        if principal.login in self.__id_by_login:
-            raise DuplicateIDError('Principal Login already taken!')
-
-        super(PrincipalFolder, self).__setitem__(id, principal)
-        self.__id_by_login[principal.login] = id
-
-    def __delitem__(self, id):
-        """Remove principal information."""
-        principal = self[id]
-        super(PrincipalFolder, self).__delitem__(id)
-        del self.__id_by_login[principal.login]
-
-    def authenticateCredentials(self, credentials):
-        """Return principal info if credentials can be authenticated
-        """
-        if not isinstance(credentials, dict):
-            return None
-        if not ('login' in credentials and 'password' in credentials):
-            return None
-        id = self.__id_by_login.get(credentials['login'])
-        if id is None:
-            return None
-        internal = self[id]
-        if not internal.checkPassword(credentials["password"]):
-            return None
-        return PrincipalInfo(self.prefix + id, internal.login, internal.title,
-                             internal.description)
-
-    def principalInfo(self, id):
-        if id.startswith(self.prefix):
-            internal = self.get(id[len(self.prefix):])
-            if internal is not None:
-                return PrincipalInfo(id, internal.login, internal.title,
-                                     internal.description)
-
-    def getIdByLogin(self, login):
-        return self.prefix + self.__id_by_login[login]
-
-    def search(self, query, start=None, batch_size=None):
-        """Search through this principal provider."""
-        search = query.get('search')
-        if search is None:
-            return
-        search = search.lower()
-        n = 1
-        for i, value in enumerate(self.values()):
-            if (search in value.title.lower() or
-                search in value.description.lower() or
-                search in value.login.lower()):
-                if not ((start is not None and i < start)
-                        or (batch_size is not None and n > batch_size)):
-                    n += 1
-                    yield self.prefix + value.__name__
-
-class Principal(object):
-    """A group-aware implementation of zope.security.interfaces.IPrincipal.
-
-    A principal is created with an ID:
-
-      >>> p = Principal(1)
-      >>> p
-      Principal(1)
-      >>> p.id
-      1
-
-    title and description may also be provided:
-
-      >>> p = Principal('george', 'George', 'A site member.')
-      >>> p
-      Principal('george')
-      >>> p.id
-      'george'
-      >>> p.title
-      'George'
-      >>> p.description
-      'A site member.'
-
-    The `groups` is a simple list, filled in by plugins.
-
-      >>> p.groups
-      []
-
-    The `allGroups` attribute is a readonly iterable of the full closure of the
-    groups in the `groups` attribute--that is, if the principal is a direct
-    member of the 'Administrators' group, and the 'Administrators' group is
-    a member of the 'Reviewers' group, then p.groups would be 
-    ['Administrators'] and list(p.allGroups) would be
-    ['Administrators', 'Reviewers'].
-
-    To illustrate this, we'll need to set up a dummy authentication utility,
-    and a few principals.  Our main principal will also gain some groups, as if
-    plugins had added the groups to the list.  This is all setup--skip to the
-    next block to actually see `allGroups` in action.
-    
-      >>> p.groups.extend(
-      ...     ['content_administrators', 'zope_3_project',
-      ...      'list_administrators', 'zpug'])
-      >>> editor = Principal('editors', 'Content Editors')
-      >>> creator = Principal('creators', 'Content Creators')
-      >>> reviewer = Principal('reviewers', 'Content Reviewers')
-      >>> reviewer.groups.extend(['editors', 'creators'])
-      >>> usermanager = Principal('user_managers', 'User Managers')
-      >>> contentAdmin = Principal(
-      ...     'content_administrators', 'Content Administrators')
-      >>> contentAdmin.groups.extend(['reviewers', 'user_managers'])
-      >>> zope3Dev = Principal('zope_3_project', 'Zope 3 Developer')
-      >>> zope3ListAdmin = Principal(
-      ...     'zope_3_list_admin', 'Zope 3 List Administrators')
-      >>> zope3ListAdmin.groups.append('zope_3_project') # duplicate, but
-      ... # should only appear in allGroups once
-      >>> listAdmin = Principal('list_administrators', 'List Administrators')
-      >>> listAdmin.groups.append('zope_3_list_admin')
-      >>> zpugMember = Principal('zpug', 'ZPUG Member')
-      >>> martians = Principal('martians', 'Martians') # not in p's allGroups
-      >>> group_data = dict((p.id, p) for p in (
-      ...     editor, creator, reviewer, usermanager, contentAdmin,
-      ...     zope3Dev, zope3ListAdmin, listAdmin, zpugMember, martians))
-      >>> class DemoAuth(object):
-      ...     interface.implements(IAuthentication)
-      ...     def getPrincipal(self, id):
-      ...         return group_data[id]
-      ...
-      >>> demoAuth = DemoAuth()
-      >>> component.provideUtility(demoAuth)
-
-    Now, we have a user with the following groups (lowest level are p's direct
-    groups, and lines show membership):
-
-      editors  creators
-         \------/
-             |                                     zope_3_project (duplicate)
-          reviewers  user_managers                          |
-               \---------/                           zope_3_list_admin
-                    |                                       |
-          content_administrators   zope_3_project   list_administrators   zpug
-
-    The allGroups value includes all of the shown groups, and with
-    'zope_3_project' only appearing once.
-
-      >>> p.groups # doctest: +NORMALIZE_WHITESPACE
-      ['content_administrators', 'zope_3_project', 'list_administrators',
-       'zpug']
-      >>> list(p.allGroups) # doctest: +NORMALIZE_WHITESPACE
-      ['content_administrators', 'reviewers', 'editors', 'creators',
-       'user_managers', 'zope_3_project', 'list_administrators',
-       'zope_3_list_admin', 'zpug']
-    """
-    interface.implements(interfaces.IPrincipal)
-
-    def __init__(self, id, title=u'', description=u''):
-        self.id = id
-        self.title = title
-        self.description = description
-        self.groups = []
-
-    def __repr__(self):
-        return 'Principal(%r)' % self.id
-
-    @property
-    def allGroups(self):
-        if self.groups:
-            seen = set()
-            principals = component.getUtility(IAuthentication)
-            stack = [iter(self.groups)]
-            while stack:
-                try:
-                    group_id = stack[-1].next()
-                except StopIteration:
-                    stack.pop()
-                else:
-                    if group_id not in seen:
-                        yield group_id
-                        seen.add(group_id)
-                        group = principals.getPrincipal(group_id)
-                        stack.append(iter(group.groups))
-
-class AuthenticatedPrincipalFactory(object):
-    """Creates 'authenticated' principals.
-
-    An authenticated principal is created as a result of an authentication
-    operation.
-
-    To use the factory, create it with the info (interfaces.IPrincipalInfo) of
-    the principal to create and a request:
-
-      >>> info = PrincipalInfo('users.mary', 'mary', 'Mary', 'The site admin.')
-      >>> from zope.publisher.base import TestRequest
-      >>> request = TestRequest('/')
-      >>> factory = AuthenticatedPrincipalFactory(info, request)
-
-    The factory must be called with a pluggable-authentication object:
-
-      >>> class Auth:
-      ...     prefix = 'auth.'
-      >>> auth = Auth()
-
-      >>> principal = factory(auth)
-
-    The factory uses the pluggable authentication and the info to
-    create a principal with the same ID, title, and description:
-
-      >>> principal.id
-      'auth.users.mary'
-      >>> principal.title
-      'Mary'
-      >>> principal.description
-      'The site admin.'
-
-    It also fires an AuthenticatedPrincipalCreatedEvent:
-
-      >>> from zope.component.eventtesting import getEvents
-      >>> [event] = getEvents(interfaces.IAuthenticatedPrincipalCreated)
-      >>> event.principal is principal, event.authentication is auth
-      (True, True)
-      >>> event.info
-      PrincipalInfo('users.mary')
-      >>> event.request is request
-      True
-
-    Listeners can subscribe to this event to perform additional operations
-    when the authenticated principal is created.
-
-    For information on how factories are used in the authentication process,
-    see README.txt.
-    """
-    component.adapts(interfaces.IPrincipalInfo, IRequest)
-
-    interface.implements(interfaces.IAuthenticatedPrincipalFactory)
-
-    def __init__(self, info, request):
-        self.info = info
-        self.request = request
-
-    def __call__(self, authentication):
-        principal = Principal(authentication.prefix + self.info.id,
-                              self.info.title,
-                              self.info.description)
-        notify(interfaces.AuthenticatedPrincipalCreated(
-            authentication, principal, self.info, self.request))
-        return principal
-
-
-class FoundPrincipalFactory(object):
-    """Creates 'found' principals.
-
-    A 'found' principal is created as a result of a principal lookup.
-
-    To use the factory, create it with the info (interfaces.IPrincipalInfo) of
-    the principal to create:
-
-      >>> info = PrincipalInfo('users.sam', 'sam', 'Sam', 'A site user.')
-      >>> factory = FoundPrincipalFactory(info)
-
-    The factory must be called with a pluggable-authentication object:
-
-      >>> class Auth:
-      ...     prefix = 'auth.'
-      >>> auth = Auth()
-
-      >>> principal = factory(auth)
-
-    The factory uses the pluggable-authentication object and the info
-    to create a principal with the same ID, title, and description:
-
-      >>> principal.id
-      'auth.users.sam'
-      >>> principal.title
-      'Sam'
-      >>> principal.description
-      'A site user.'
-
-    It also fires a FoundPrincipalCreatedEvent:
-
-      >>> from zope.component.eventtesting import getEvents
-      >>> [event] = getEvents(interfaces.IFoundPrincipalCreated)
-      >>> event.principal is principal, event.authentication is auth
-      (True, True)
-      >>> event.info
-      PrincipalInfo('users.sam')
-
-    Listeners can subscribe to this event to perform additional operations
-    when the 'found' principal is created.
-
-    For information on how factories are used in the authentication process,
-    see README.txt.
-    """
-    component.adapts(interfaces.IPrincipalInfo)
-
-    interface.implements(interfaces.IFoundPrincipalFactory)
-
-    def __init__(self, info):
-        self.info = info
-
-    def __call__(self, authentication):
-        principal = Principal(authentication.prefix + self.info.id,
-                              self.info.title,
-                              self.info.description)
-        notify(interfaces.FoundPrincipalCreated(authentication,
-                                                principal, self.info))
-        return principal

Deleted: zope.password/trunk/src/zope/password/principalfolder.txt
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/principalfolder.txt	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/principalfolder.txt	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,170 +0,0 @@
-================
-Principal Folder
-================
-
-Principal folders contain principal-information objects that contain principal
-information. We create an internal principal using the `InternalPrincipal`
-class:
-
-  >>> from zope.app.authentication.principalfolder import InternalPrincipal
-  >>> p1 = InternalPrincipal('login1', '123', "Principal 1",
-  ...     passwordManagerName="SHA1")
-  >>> p2 = InternalPrincipal('login2', '456', "The Other One")
-
-and add them to a principal folder:
-
-  >>> from zope.app.authentication.principalfolder import PrincipalFolder
-  >>> principals = PrincipalFolder('principal.')
-  >>> principals['p1'] = p1
-  >>> principals['p2'] = p2
-
-Authentication
---------------
-
-Principal folders provide the `IAuthenticatorPlugin` interface. When we
-provide suitable credentials:
-
-  >>> from zope.testing.doctestunit import pprint
-  >>> principals.authenticateCredentials({'login': 'login1', 'password': '123'})
-  PrincipalInfo(u'principal.p1')
-
-We get back a principal id and supplementary information, including the
-principal title and description.  Note that the principal id is a concatenation
-of the principal-folder prefix and the name of the principal-information object
-within the folder.
-
-None is returned if the credentials are invalid:
-
-  >>> principals.authenticateCredentials({'login': 'login1',
-  ...                                     'password': '1234'})
-  >>> principals.authenticateCredentials(42)
-
-Search
-------
-
-Principal folders also provide the IQuerySchemaSearch interface.  This
-supports both finding principal information based on their ids:
-
-  >>> principals.principalInfo('principal.p1')
-  PrincipalInfo('principal.p1')
-
-  >>> principals.principalInfo('p1')
-
-and searching for principals based on a search string:
-
-  >>> list(principals.search({'search': 'other'}))
-  [u'principal.p2']
-
-  >>> list(principals.search({'search': 'OTHER'}))
-  [u'principal.p2']
-
-  >>> list(principals.search({'search': ''}))
-  [u'principal.p1', u'principal.p2']
-
-  >>> list(principals.search({'search': 'eek'}))
-  []
-
-  >>> list(principals.search({}))
-  []
-
-If there are a large number of matches:
-
-  >>> for i in range(20):
-  ...     i = str(i)
-  ...     p = InternalPrincipal('l'+i, i, "Dude "+i)
-  ...     principals[i] = p
-
-  >>> pprint(list(principals.search({'search': 'D'})))
-  [u'principal.0',
-   u'principal.1',
-   u'principal.10',
-   u'principal.11',
-   u'principal.12',
-   u'principal.13',
-   u'principal.14',
-   u'principal.15',
-   u'principal.16',
-   u'principal.17',
-   u'principal.18',
-   u'principal.19',
-   u'principal.2',
-   u'principal.3',
-   u'principal.4',
-   u'principal.5',
-   u'principal.6',
-   u'principal.7',
-   u'principal.8',
-   u'principal.9']
-
-We can use batching parameters to specify a subset of results:
-
-  >>> pprint(list(principals.search({'search': 'D'}, start=17)))
-  [u'principal.7',
-   u'principal.8',
-   u'principal.9']
-
-  >>> pprint(list(principals.search({'search': 'D'}, batch_size=5)))
-  [u'principal.0',
-   u'principal.1',
-   u'principal.10',
-   u'principal.11',
-   u'principal.12']
-
-  >>> pprint(list(principals.search({'search': 'D'}, start=5, batch_size=5)))
-  [u'principal.13',
-   u'principal.14',
-   u'principal.15',
-   u'principal.16',
-   u'principal.17']
-
-There is an additional method that allows requesting the principal id
-associated with a login id.  The method raises KeyError when there is
-no associated principal::
-
-  >>> principals.getIdByLogin("not-there")
-  Traceback (most recent call last):
-  KeyError: 'not-there'
-
-If there is a matching principal, the id is returned::
-
-  >>> principals.getIdByLogin("login1")
-  u'principal.p1'
-
-Changing credentials
---------------------
-
-Credentials can be changed by modifying principal-information objects:
-
-  >>> p1.login = 'bob'
-  >>> p1.password = 'eek'
-
-  >>> principals.authenticateCredentials({'login': 'bob', 'password': 'eek'})
-  PrincipalInfo(u'principal.p1')
-
-  >>> principals.authenticateCredentials({'login': 'login1',
-  ...                                     'password': 'eek'})
-
-  >>> principals.authenticateCredentials({'login': 'bob',
-  ...                                     'password': '123'})
-
-
-It is an error to try to pick a login name that is already taken:
-
-  >>> p1.login = 'login2'
-  Traceback (most recent call last):
-  ...
-  ValueError: Principal Login already taken!
-
-If such an attempt is made, the data are unchanged:
-
-  >>> principals.authenticateCredentials({'login': 'bob', 'password': 'eek'})
-  PrincipalInfo(u'principal.p1')
-
-Removing principals
--------------------
-
-Of course, if a principal is removed, we can no-longer authenticate it:
-
-  >>> del principals['p1']
-  >>> principals.authenticateCredentials({'login': 'bob',
-  ...                                     'password': 'eek'})

Deleted: zope.password/trunk/src/zope/password/principalfolder.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/principalfolder.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/principalfolder.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,59 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    i18n_domain="zope"
-    >
-
-  <class class=".principalfolder.InternalPrincipal">
-    <require
-        permission="zope.ManageServices"
-        interface=".principalfolder.IInternalPrincipal"
-        set_schema=".principalfolder.IInternalPrincipal"
-        />
-  </class>
-
-  <class class=".principalfolder.PrincipalFolder">
-
-    <implements
-        interface="zope.annotation.interfaces.IAttributeAnnotatable"
-        />
-
-    <require
-        permission="zope.ManageServices"
-        interface="zope.container.interfaces.IContainer"
-        />
-
-    <require
-        permission="zope.ManageServices"
-        attributes="prefix"
-        />
-
-  </class>
-
-  <adapter
-      provides="zope.container.interfaces.INameChooser"
-      for=".principalfolder.IInternalPrincipalContainer"
-      factory=".idpicker.IdPicker"
-      />
-
-  <adapter factory=".principalfolder.FoundPrincipalFactory" />
-
-  <adapter factory=".principalfolder.AuthenticatedPrincipalFactory" />
-
-  <include package=".browser" file="principalfolder.zcml" />
-
-  <!-- Registering documentation with API doc -->
-  <configure
-      xmlns:apidoc="http://namespaces.zope.org/apidoc"
-      xmlns:zcml="http://namespaces.zope.org/zcml"
-      zcml:condition="have apidoc">
-
-    <apidoc:bookchapter
-        id="principalfolder"
-        title="Principal Folder"
-        doc_path="principalfolder.txt"
-        parent="security/authentication"
-        />
-
-  </configure>
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/session.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/session.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/session.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,301 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 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.
-#
-##############################################################################
-""" Implementations of the session-based and cookie-based extractor and
-    challenge plugins.
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-import transaction
-from persistent import Persistent
-from urllib import urlencode
-
-from zope.interface import implements, Interface
-from zope.schema import TextLine
-from zope.publisher.interfaces.http import IHTTPRequest
-from zope.session.interfaces import ISession
-from zope.traversing.browser.absoluteurl import absoluteURL
-
-from zope.app.component import hooks
-from zope.container.contained import Contained
-from zope.app.authentication.interfaces import ICredentialsPlugin
-
-class ISessionCredentials(Interface):
-    """ Interface for storing and accessing credentials in a session.
-
-        We use a real class with interface here to prevent unauthorized
-        access to the credentials.
-    """
-
-    def __init__(login, password):
-        pass
-
-    def getLogin():
-        """Return login name."""
-
-    def getPassword():
-        """Return password."""
-
-
-class SessionCredentials(object):
-    """Credentials class for use with sessions.
-
-    A session credential is created with a login and a password:
-
-      >>> cred = SessionCredentials('scott', 'tiger')
-
-    Logins are read using getLogin:
-      >>> cred.getLogin()
-      'scott'
-
-    and passwords with getPassword:
-
-      >>> cred.getPassword()
-      'tiger'
-
-    """
-    implements(ISessionCredentials)
-
-    def __init__(self, login, password):
-        self.login = login
-        self.password = password
-
-    def getLogin(self): return self.login
-
-    def getPassword(self): return self.password
-
-    def __str__(self): return self.getLogin() + ':' + self.getPassword()
-
-
-class IBrowserFormChallenger(Interface):
-    """A challenger that uses a browser form to collect user credentials."""
-
-    loginpagename = TextLine(
-        title=u'Loginpagename',
-        description=u"""Name of the login form used by challenger.
-
-        The form must provide 'login' and 'password' input fields.
-        """,
-        default=u'loginForm.html')
-
-    loginfield = TextLine(
-        title=u'Loginfield',
-        description=u"Field of the login page in which is looked for the login user name.",
-        default=u"login")
-
-    passwordfield = TextLine(
-        title=u'Passwordfield',
-        description=u"Field of the login page in which is looked for the password.",
-        default=u"password")
-
-
-class SessionCredentialsPlugin(Persistent, Contained):
-    """A credentials plugin that uses Zope sessions to get/store credentials.
-
-    To illustrate how a session plugin works, we'll first setup some session
-    machinery:
-
-      >>> from zope.session.session import RAMSessionDataContainer
-      >>> from tests import sessionSetUp
-      >>> sessionSetUp(RAMSessionDataContainer)
-
-    This lets us retrieve the same session info from any test request, which
-    simulates what happens when a user submits a session ID as a cookie.
-
-    We also need a session plugin:
-
-      >>> plugin = SessionCredentialsPlugin()
-
-    A session plugin uses an ISession component to store the last set of
-    credentials it gets from a request. Credentials can be retrieved from
-    subsequent requests using the session-stored credentials.
-
-    Our test environment is initially configured without credentials:
-
-      >>> from tests import sessionSetUp
-      >>> from zope.publisher.browser import TestRequest
-      >>> request = TestRequest()
-      >>> print plugin.extractCredentials(request)
-      None
-
-    We must explicitly provide credentials once so the plugin can store
-    them in a session:
-
-      >>> request = TestRequest(login='scott', password='tiger')
-      >>> plugin.extractCredentials(request)
-      {'login': 'scott', 'password': 'tiger'}
-
-    Subsequent requests now have access to the credentials even if they're
-    not explicitly in the request:
-
-      >>> plugin.extractCredentials(TestRequest())
-      {'login': 'scott', 'password': 'tiger'}
-
-    We can always provide new credentials explicitly in the request:
-
-      >>> plugin.extractCredentials(TestRequest(
-      ...     login='harry', password='hirsch'))
-      {'login': 'harry', 'password': 'hirsch'}
-
-    and these will be used on subsequent requests:
-
-      >>> plugin.extractCredentials(TestRequest())
-      {'login': 'harry', 'password': 'hirsch'}
-
-    We can also change the fields from which the credentials are extracted:
-
-      >>> plugin.loginfield = "my_new_login_field"
-      >>> plugin.passwordfield = "my_new_password_field"
-
-    Now we build a request that uses the new fields:
-
-      >>> request = TestRequest(my_new_login_field='luke', my_new_password_field='the_force')
-
-    The plugin now extracts the credentials information from these new fields:
-
-      >>> plugin.extractCredentials(request)
-      {'login': 'luke', 'password': 'the_force'}
-
-    Finally, we clear the session credentials using the logout method:
-
-      >>> plugin.logout(TestRequest())
-      True
-      >>> print plugin.extractCredentials(TestRequest())
-      None
-
-    """
-    implements(ICredentialsPlugin, IBrowserFormChallenger)
-
-    loginpagename = 'loginForm.html'
-    loginfield = 'login'
-    passwordfield = 'password'
-
-    def extractCredentials(self, request):
-        """Extracts credentials from a session if they exist."""
-        if not IHTTPRequest.providedBy(request):
-            return None
-        session = ISession(request)
-        sessionData = session.get(
-            'zope.app.authentication.browserplugins')
-        login = request.get(self.loginfield, None)
-        password = request.get(self.passwordfield, None)
-        credentials = None
-
-        if login and password:
-            credentials = SessionCredentials(login, password)
-        elif not sessionData:
-            return None
-        sessionData = session[
-            'zope.app.authentication.browserplugins']
-        if credentials:
-            sessionData['credentials'] = credentials
-        else:
-            credentials = sessionData.get('credentials', None)
-        if not credentials:
-            return None
-        return {'login': credentials.getLogin(),
-                'password': credentials.getPassword()}
-
-    def challenge(self, request):
-        """Challenges by redirecting to a login form.
-
-        To illustrate, we'll create a test request:
-
-          >>> from zope.publisher.browser import TestRequest
-          >>> request = TestRequest()
-
-        and confirm its response's initial status and 'location' header:
-
-          >>> request.response.getStatus()
-          599
-          >>> request.response.getHeader('location')
-
-        When we issue a challenge using a session plugin:
-
-          >>> plugin = SessionCredentialsPlugin()
-          >>> plugin.challenge(request)
-          True
-
-        we get a redirect:
-
-          >>> request.response.getStatus()
-          302
-          >>> request.response.getHeader('location')
-          'http://127.0.0.1/@@loginForm.html?camefrom=%2F'
-
-        The plugin redirects to the page defined by the loginpagename
-        attribute:
-
-          >>> plugin.loginpagename = 'mylogin.html'
-          >>> plugin.challenge(request)
-          True
-          >>> request.response.getHeader('location')
-          'http://127.0.0.1/@@mylogin.html?camefrom=%2F'
-
-        It also provides the request URL as a 'camefrom' GET style parameter.
-        To illustrate, we'll pretend we've traversed a couple names:
-
-          >>> env = {
-          ...     'REQUEST_URI': '/foo/bar/folder/page%201.html?q=value',
-          ...     'QUERY_STRING': 'q=value'
-          ...     }
-          >>> request = TestRequest(environ=env)
-          >>> request._traversed_names = [u'foo', u'bar']
-          >>> request._traversal_stack = [u'page 1.html', u'folder']
-          >>> request['REQUEST_URI']
-          '/foo/bar/folder/page%201.html?q=value'
-
-        When we challenge:
-
-          >>> plugin.challenge(request)
-          True
-
-        We see the 'camefrom' points to the requested URL:
-
-          >>> request.response.getHeader('location') # doctest: +ELLIPSIS
-          '.../@@mylogin.html?camefrom=%2Ffoo%2Fbar%2Ffolder%2Fpage+1.html%3Fq%3Dvalue'
-
-        This can be used by the login form to redirect the user back to the
-        originating URL upon successful authentication.
-        """
-        if not IHTTPRequest.providedBy(request):
-            return False
-
-        site = hooks.getSite()
-        # We need the traversal stack to complete the 'camefrom' parameter
-        stack = request.getTraversalStack()
-        stack.reverse()
-        # Better to add the query string, if present
-        query = request.get('QUERY_STRING')
-
-        camefrom = '/'.join([request.getURL(path_only=True)] + stack)
-        if query:
-            camefrom = camefrom + '?' + query
-        url = '%s/@@%s?%s' % (absoluteURL(site, request),
-                              self.loginpagename,
-                              urlencode({'camefrom': camefrom}))
-        request.response.redirect(url)
-        return True
-
-    def logout(self, request):
-        """Performs logout by clearing session data credentials."""
-        if not IHTTPRequest.providedBy(request):
-            return False
-
-        sessionData = ISession(request)[
-            'zope.app.authentication.browserplugins']
-        sessionData['credentials'] = None
-        transaction.commit()
-        return True

Deleted: zope.password/trunk/src/zope/password/session.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/session.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/session.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,28 +0,0 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    i18n_domain="zope"
-    >
-
-  <utility
-      name="Session Credentials"
-      provides=".interfaces.ICredentialsPlugin"
-      factory=".session.SessionCredentialsPlugin"
-      />
-
-  <class class=".session.SessionCredentialsPlugin">
-
-    <implements
-        interface="zope.annotation.interfaces.IAttributeAnnotatable"
-        />
-
-    <require
-        permission="zope.ManageServices"
-        interface=".session.IBrowserFormChallenger"
-        set_schema=".session.IBrowserFormChallenger"
-        />
-
-  </class>
-
-  <include package=".browser" file="session.zcml" />
-
-</configure>

Deleted: zope.password/trunk/src/zope/password/testing.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/testing.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/testing.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,26 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2007 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.
-#
-##############################################################################
-"""zope.app.authentication common test related classes/functions/objects.
-
-$Id$
-"""
-
-__docformat__ = "reStructuredText"
-
-import os
-from zope.app.testing.functional import ZCMLLayer
-
-AppAuthenticationLayer = ZCMLLayer(
-    os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'),
-    __name__, 'AppAuthenticationLayer', allow_teardown=True)

Copied: zope.password/trunk/src/zope/password/testing.py (from rev 97555, zope.app.authentication/trunk/src/zope/app/authentication/placelesssetup.py)
===================================================================
--- zope.password/trunk/src/zope/password/testing.py	                        (rev 0)
+++ zope.password/trunk/src/zope/password/testing.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# Copyright (c) 2009 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.
+#
+##############################################################################
+"""Setup password managers as utilities
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from zope.component import provideUtility
+from zope.password.interfaces import IPasswordManager
+from zope.password.password import PlainTextPasswordManager
+from zope.password.password import MD5PasswordManager
+from zope.password.password import SHA1PasswordManager
+from zope.password.password import SSHAPasswordManager
+
+
+def setUpPasswordManagers():
+    provideUtility(PlainTextPasswordManager(), IPasswordManager, 'Plain Text')
+    provideUtility(SSHAPasswordManager(), IPasswordManager, 'SSHA')
+    provideUtility(MD5PasswordManager(), IPasswordManager, 'MD5')
+    provideUtility(SHA1PasswordManager(), IPasswordManager, 'SHA1')

Modified: zope.password/trunk/src/zope/password/tests.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/tests.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/tests.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2004 Zope Corporation and Contributors.
+# Copyright (c) 2009 Zope Corporation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -11,123 +11,15 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Pluggable Authentication Service Tests
+"""Password Managers Tests
 
 $Id$
 """
-__docformat__ = "reStructuredText"
-
 import unittest
-
 from zope.testing import doctest
-from zope.interface import implements
-from zope.component import provideUtility, provideAdapter
-from zope.component.eventtesting import getEvents, clearEvents
-from zope.publisher.interfaces import IRequest
 
-from zope.app.testing import placelesssetup, ztapi
-from zope.app.testing.setup import placefulSetUp, placefulTearDown
-from zope.session.interfaces import \
-        IClientId, IClientIdManager, ISession, ISessionDataContainer
-from zope.session.session import \
-        ClientId, Session, PersistentSessionDataContainer
-from zope.session.http import CookieClientIdManager
 
-from zope.publisher import base
-from zope.app.authentication.session import SessionCredentialsPlugin
-
-
-class TestClientId(object):
-    implements(IClientId)
-    def __new__(cls, request):
-        return 'dummyclientidfortesting'
-
-def siteSetUp(test):
-    placefulSetUp(site=True)
-
-def siteTearDown(test):
-    placefulTearDown()
-
-def sessionSetUp(session_data_container_class=PersistentSessionDataContainer):
-    placelesssetup.setUp()
-    ztapi.provideAdapter(IRequest, IClientId, TestClientId)
-    ztapi.provideAdapter(IRequest, ISession, Session)
-    ztapi.provideUtility(IClientIdManager, CookieClientIdManager())
-    sdc = session_data_container_class()
-    ztapi.provideUtility(ISessionDataContainer, sdc, '')
-
-def nonHTTPSessionTestCaseSetUp(sdc_class=PersistentSessionDataContainer):
-    # I am getting an error with ClientId and not TestClientId
-    placelesssetup.setUp()
-    ztapi.provideAdapter(IRequest, IClientId, ClientId)
-    ztapi.provideAdapter(IRequest, ISession, Session)
-    ztapi.provideUtility(IClientIdManager, CookieClientIdManager())
-    sdc = sdc_class()
-    ztapi.provideUtility(ISessionDataContainer, sdc, '')
-
-
-class NonHTTPSessionTestCase(unittest.TestCase):
-    # Small test suite to catch an error with non HTTP protocols, like FTP
-    # and SessionCredentialsPlugin.
-    def setUp(self):
-        nonHTTPSessionTestCaseSetUp()
-
-    def tearDown(self):
-        placefulTearDown()
-
-    def test_exeractCredentials(self):
-        plugin = SessionCredentialsPlugin()
-
-        self.assertEqual(plugin.extractCredentials(base.TestRequest('/')), None)
-
-    def test_challenge(self):
-        plugin = SessionCredentialsPlugin()
-
-        self.assertEqual(plugin.challenge(base.TestRequest('/')), False)
-
-    def test_logout(self):
-        plugin = SessionCredentialsPlugin()
-
-        self.assertEqual(plugin.logout(base.TestRequest('/')), False)
-
-
 def test_suite():
     return unittest.TestSuite((
-        doctest.DocTestSuite('zope.app.authentication.interfaces'),
-        doctest.DocTestSuite('zope.app.authentication.password'),
-        doctest.DocTestSuite('zope.app.authentication.generic'),
-        doctest.DocTestSuite('zope.app.authentication.httpplugins'),
-        doctest.DocTestSuite('zope.app.authentication.ftpplugins'),
-        doctest.DocTestSuite('zope.app.authentication.groupfolder'),
-        doctest.DocFileSuite('principalfolder.txt',
-                             setUp=placelesssetup.setUp,
-                             tearDown=placelesssetup.tearDown),
-        doctest.DocTestSuite('zope.app.authentication.principalfolder',
-                             setUp=placelesssetup.setUp,
-                             tearDown=placelesssetup.tearDown),
-        doctest.DocTestSuite('zope.app.authentication.idpicker'),
-        doctest.DocTestSuite('zope.app.authentication.session',
-                             setUp=siteSetUp,
-                             tearDown=siteTearDown),
-        doctest.DocFileSuite('README.txt',
-                             setUp=siteSetUp,
-                             tearDown=siteTearDown,
-                             globs={'provideUtility': provideUtility,
-                                    'provideAdapter': provideAdapter,
-                                    'getEvents': getEvents,
-                                    'clearEvents': clearEvents,
-                                    'subscribe': ztapi.subscribe,
-                                    }),
-        doctest.DocFileSuite('groupfolder.txt',
-                             setUp=placelesssetup.setUp,
-                             tearDown=placelesssetup.tearDown,
-                             ),
-        doctest.DocFileSuite('vocabulary.txt',
-                             setUp=placelesssetup.setUp,
-                             tearDown=placelesssetup.tearDown,
-                             ),
-        unittest.makeSuite(NonHTTPSessionTestCase),
+        doctest.DocTestSuite('zope.password.password'),
         ))
-
-if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')

Deleted: zope.password/trunk/src/zope/password/vocabulary.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/vocabulary.py	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/vocabulary.py	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,96 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 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.
-#
-##############################################################################
-"""Plugin Vocabulary.
-
-This vocabulary provides terms for authentication utility plugins.
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-
-import zope.dublincore.interfaces
-from zope import interface, component, i18n
-from zope.schema import vocabulary
-from zope.schema.interfaces import IVocabularyFactory
-
-from zope.app.authentication.i18n import ZopeMessageFactory as _
-
-from zope.app.authentication import interfaces
-
-UTILITY_TITLE = _(
-    'zope.app.authentication.vocabulary-utility-plugin-title',
-    '${name} (a utility)')
-CONTAINED_TITLE = _(
-    'zope.app.authentication.vocabulary-contained-plugin-title',
-    '${name} (in contents)')
-MISSING_TITLE = _(
-    'zope.app.authentication.vocabulary-missing-plugin-title',
-    '${name} (not found; deselecting will remove)')
-
-def _pluginVocabulary(context, interface, attr_name):
-    """Vocabulary that provides names of plugins of a specified interface.
-
-    Given an interface, the options should include the unique names of all of
-    the plugins that provide the specified interface for the current context--
-    which is expected to be a pluggable authentication utility, hereafter
-    referred to as a PAU).
-
-    These plugins may be objects contained within the PAU ("contained
-    plugins"), or may be utilities registered for the specified
-    interface, found in the context of the PAU ("utility plugins").
-    Contained plugins mask utility plugins of the same name.
-
-    The vocabulary also includes the current values of the PAU even if they do
-    not correspond to a contained or utility plugin.
-    """
-    terms = {}
-    isPAU = interfaces.IPluggableAuthentication.providedBy(context)
-    if isPAU:
-        for k, v in context.items():
-            if interface.providedBy(v):
-                dc = zope.dublincore.interfaces.IDCDescriptiveProperties(
-                    v, None)
-                if dc is not None and dc.title:
-                    title = dc.title
-                else:
-                    title = k
-                terms[k] = vocabulary.SimpleTerm(
-                    k, k.encode('base64').strip(), i18n.Message(
-                        CONTAINED_TITLE, mapping={'name': title}))
-    utils = component.getUtilitiesFor(interface, context)
-    for nm, util in utils:
-        if nm not in terms:
-            terms[nm] = vocabulary.SimpleTerm(
-                nm, nm.encode('base64').strip(), i18n.Message(
-                    UTILITY_TITLE, mapping={'name': nm}))
-    if isPAU:
-        for nm in set(getattr(context, attr_name)):
-            if nm not in terms:
-                terms[nm] = vocabulary.SimpleTerm(
-                    nm, nm.encode('base64').strip(), i18n.Message(
-                        MISSING_TITLE, mapping={'name': nm}))
-    return vocabulary.SimpleVocabulary(
-        [term for nm, term in sorted(terms.items())])
-
-def authenticatorPlugins(context):
-    return _pluginVocabulary(
-        context, interfaces.IAuthenticatorPlugin, 'authenticatorPlugins')
-
-interface.alsoProvides(authenticatorPlugins, IVocabularyFactory)
-
-def credentialsPlugins(context):
-    return _pluginVocabulary(
-        context, interfaces.ICredentialsPlugin, 'credentialsPlugins')
-
-interface.alsoProvides(credentialsPlugins, IVocabularyFactory)

Deleted: zope.password/trunk/src/zope/password/vocabulary.txt
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/vocabulary.txt	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/vocabulary.txt	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1,203 +0,0 @@
-============
-Vocabularies
-============
-
-The vocabulary module provides vocabularies for the authenticator plugins and
-the credentials plugins.
-
-The options should include the unique names of all of the plugins that provide
-the appropriate interface (interfaces.ICredentialsPlugin or
-interfaces.IAuthentiatorPlugin, respectively) for the current context-- which
-is expected to be a pluggable authentication utility, hereafter referred to as
-a PAU.
-
-These names may be for objects contained within the PAU ("contained
-plugins"), or may be utilities registered for the specified interface,
-found in the context of the PAU ("utility plugins").  Contained
-plugins mask utility plugins of the same name.  They also may be names
-currently selected in the PAU that do not actually have a
-corresponding plugin at this time.
-
-Here is a short example of how the vocabulary should work.  Let's say we're
-working with authentication plugins.  We'll create some faux
-authentication plugins, and register some of them as utilities and put
-others in a faux PAU.
-
-    >>> from zope.app.authentication import interfaces
-    >>> from zope import interface, component
-    >>> class DemoPlugin(object):
-    ...     interface.implements(interfaces.IAuthenticatorPlugin)
-    ...     def __init__(self, name):
-    ...         self.name = name
-    ...
-    >>> utility_plugins = dict(
-    ...     (i, DemoPlugin(u'Plugin %d' % i)) for i in range(4))
-    >>> contained_plugins = dict(
-    ...     (i, DemoPlugin(u'Plugin %d' % i)) for i in range(1, 5))
-    >>> sorted(utility_plugins.keys())
-    [0, 1, 2, 3]
-    >>> for p in utility_plugins.values():
-    ...     component.provideUtility(p, name=p.name)
-    ...
-    >>> sorted(contained_plugins.keys()) # 1 will mask utility plugin 1
-    [1, 2, 3, 4]
-    >>> class DemoAuth(dict):
-    ...     interface.implements(interfaces.IPluggableAuthentication)
-    ...     def __init__(self, *args, **kwargs):
-    ...         super(DemoAuth, self).__init__(*args, **kwargs)
-    ...         self.authenticatorPlugins = (u'Plugin 3', u'Plugin X')
-    ...         self.credentialsPlugins = (u'Plugin 4', u'Plugin X')
-    ...
-    >>> auth = DemoAuth((p.name, p) for p in contained_plugins.values())
-
-    >>> @component.adapter(interface.Interface)
-    ... @interface.implementer(component.IComponentLookup)
-    ... def getSiteManager(context):
-    ...     return component.getGlobalSiteManager()
-    ...
-    >>> component.provideAdapter(getSiteManager)
-
-We are now ready to create a vocabulary that we can use.  The context is
-our faux authentication utility, `auth`.
-
-    >>> from zope.app.authentication import vocabulary
-    >>> vocab = vocabulary.authenticatorPlugins(auth)
-
-Iterating over the vocabulary results in all of the terms, in a relatively
-arbitrary order of their names.  (This vocabulary should typically use a
-widget that sorts values on the basis of localized collation order of the
-term titles.)
-
-    >>> [term.value for term in vocab] # doctest: +NORMALIZE_WHITESPACE
-    [u'Plugin 0', u'Plugin 1', u'Plugin 2', u'Plugin 3', u'Plugin 4',
-     u'Plugin X']
-
-Similarly, we can use `in` to test for the presence of values in the
-vocabulary.
-
-    >>> ['Plugin %s' % i in vocab for i in range(-1, 6)]
-    [False, True, True, True, True, True, False]
-    >>> 'Plugin X' in vocab
-    True
-
-The length reports the expected value.
-
-    >>> len(vocab)
-    6
-
-One can get a term for a given value using `getTerm()`; its token, in
-turn, should also return the same effective term from `getTermByToken`.
-
-    >>> values = ['Plugin 0', 'Plugin 1', 'Plugin 2', 'Plugin 3', 'Plugin 4',
-    ...           'Plugin X']
-    >>> for val in values:
-    ...     term = vocab.getTerm(val)
-    ...     assert term.value == val
-    ...     term2 = vocab.getTermByToken(term.token)
-    ...     assert term2.token == term.token
-    ...     assert term2.value == val
-    ...
-
-The terms have titles, which are message ids that show the plugin title or id
-and whether the plugin is a utility or just contained in the auth utility.
-We'll give one of the plugins a dublin core title just to show the
-functionality.
-
-    >>> import zope.dublincore.interfaces
-    >>> class ISpecial(interface.Interface):
-    ...     pass
-    ...
-    >>> interface.directlyProvides(contained_plugins[1], ISpecial)
-    >>> class DemoDCAdapter(object):
-    ...     interface.implements(
-    ...         zope.dublincore.interfaces.IDCDescriptiveProperties)
-    ...     component.adapts(ISpecial)
-    ...     def __init__(self, context):
-    ...         pass
-    ...     title = u'Special Title'
-    ...
-    >>> component.provideAdapter(DemoDCAdapter)
-
-We need to regenerate the vocabulary, since it calculates all of its data at
-once.
-
-    >>> vocab = vocabulary.authenticatorPlugins(auth)
-
-Now we'll check the titles.  We'll have to translate them to see what we
-expect.
-
-    >>> from zope import i18n
-    >>> import pprint
-    >>> pprint.pprint([i18n.translate(term.title) for term in vocab])
-    [u'Plugin 0 (a utility)',
-     u'Special Title (in contents)',
-     u'Plugin 2 (in contents)',
-     u'Plugin 3 (in contents)',
-     u'Plugin 4 (in contents)',
-     u'Plugin X (not found; deselecting will remove)']
-
-credentialsPlugins
-------------------
-
-For completeness, we'll do the same review of the credentialsPlugins.
-
-    >>> class DemoPlugin(object):
-    ...     interface.implements(interfaces.ICredentialsPlugin)
-    ...     def __init__(self, name):
-    ...         self.name = name
-    ...
-    >>> utility_plugins = dict(
-    ...     (i, DemoPlugin(u'Plugin %d' % i)) for i in range(4))
-    >>> contained_plugins = dict(
-    ...     (i, DemoPlugin(u'Plugin %d' % i)) for i in range(1, 5))
-    >>> for p in utility_plugins.values():
-    ...     component.provideUtility(p, name=p.name)
-    ...
-    >>> auth = DemoAuth((p.name, p) for p in contained_plugins.values())
-    >>> vocab = vocabulary.credentialsPlugins(auth)
-
-Iterating over the vocabulary results in all of the terms, in a relatively
-arbitrary order of their names.  (This vocabulary should typically use a
-widget that sorts values on the basis of localized collation order of the term
-titles.) Similarly, we can use `in` to test for the presence of values in the
-vocabulary. The length reports the expected value.
-
-    >>> [term.value for term in vocab] # doctest: +NORMALIZE_WHITESPACE
-    [u'Plugin 0', u'Plugin 1', u'Plugin 2', u'Plugin 3', u'Plugin 4',
-     u'Plugin X']
-    >>> ['Plugin %s' % i in vocab for i in range(-1, 6)]
-    [False, True, True, True, True, True, False]
-    >>> 'Plugin X' in vocab
-    True
-    >>> len(vocab)
-    6
-
-One can get a term for a given value using `getTerm()`; its token, in
-turn, should also return the same effective term from `getTermByToken`.
-
-    >>> values = ['Plugin 0', 'Plugin 1', 'Plugin 2', 'Plugin 3', 'Plugin 4',
-    ...           'Plugin X']
-    >>> for val in values:
-    ...     term = vocab.getTerm(val)
-    ...     assert term.value == val
-    ...     term2 = vocab.getTermByToken(term.token)
-    ...     assert term2.token == term.token
-    ...     assert term2.value == val
-    ...
-
-The terms have titles, which are message ids that show the plugin title or id
-and whether the plugin is a utility or just contained in the auth utility.
-We'll give one of the plugins a dublin core title just to show the
-functionality. We need to regenerate the vocabulary, since it calculates all
-of its data at once. Then we'll check the titles.  We'll have to translate
-them to see what we expect.
-
-    >>> interface.directlyProvides(contained_plugins[1], ISpecial)
-    >>> vocab = vocabulary.credentialsPlugins(auth)
-    >>> pprint.pprint([i18n.translate(term.title) for term in vocab])
-    [u'Plugin 0 (a utility)',
-     u'Special Title (in contents)',
-     u'Plugin 2 (in contents)',
-     u'Plugin 3 (in contents)',
-     u'Plugin 4 (in contents)',
-     u'Plugin X (not found; deselecting will remove)']

Deleted: zope.password/trunk/src/zope/password/zope.app.authentication-configure.zcml
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/zope.app.authentication-configure.zcml	2009-03-06 09:38:55 UTC (rev 97555)
+++ zope.password/trunk/src/zope/password/zope.app.authentication-configure.zcml	2009-03-06 11:47:04 UTC (rev 97560)
@@ -1 +0,0 @@
-<include package="zope.app.authentication" />



More information about the Checkins mailing list