Author: Maurits van Rees



Since Plone 4.0 you can configure Plone to allow users to login with
their email address, using a setting in the Security control panel.
This works fine out of the box.  Some improvements would be useful
though that need some more careful consideration before being added to
core Plone.  That is where this package comes in.

This is a temporary package with some fixes for when you want to use
the email address of a user as login name in Plone 4.  It also
introduces a few hooks for determining the user id and login name of a
new user.

Plone version

This package is tested with Plone 4.1, 4.2 and 4.3.  It will not work
in 4.0.

For Plone 3, you must use the ``collective.emaillogin`` package.


We need a newer version of ``Products.PluggableAuthService`` than is
available currently in the latest Plone versions.  Assuming you are
using buildout for your Plone site, you need to add a line to a
versions section::

  Products.PluggableAuthService = 1.10.0

Any version newer than this is fine as well.  If your Plone version
already has this version or a newer one pinned, then you do not need
to add this line.

What does this package do?

Clearer separation between user id and login name

The validation of the ``register`` browser view uses two methods to
get a user id and login name::

    # Generate a nice user id and store that in the data.
    user_id = self.generate_user_id(data)
    # Generate a nice login name and store that in the data.
    login_name = self.generate_login_name(data)

After this, the ``data`` dictionary will have keys ``user_id`` and
``login_name`` set accordingly.

We avoid as much as possible the use of ``username`` as a variable,
because no one ever knows if that is meant as a user id or as a login
name.  In standard Plone this is always the same, but this need not be
true, especially when using the email address as login name.

These changes are intended to be merged to ````.

Control over user ids

An ``IUserIdGenerator`` interface is defined.  This is used in the new
``generate_user_id`` method of the ``register`` browser view (also
used when adding a new user as admin).  Two sample implementations::

  def uuid_userid_generator(data=None):
      # Return a uuid, independent of the data.
      # This is available in in the patches.
      from zope.component import getUtility
      from plone.uuid.interfaces import IUUIDGenerator
      generator = getUtility(IUUIDGenerator)
      return generator()

  def login_name_as_userid_generator(data):
      # We like to keep it simple.
      return data.get('username')

In ``generate_user_id`` we try a few options for coming up with a good
user id:

1. We query a utility, so integrators can register a hook to
   generate a user id using their own logic::

     generator = queryUtility(IUserIdGenerator)
     if generator:
         userid = generator(data)
         if userid:
             data['user_id'] = userid
             return userid

2. If ``use_uuid_as_userid`` is set in the site_properties, we
   generate a uuid.  This is a new property introduced by this
   package and can be set in the Security control panel.

3. If a username is given and we do not use email as login,
   then we simply return that username as the user id.

4. We create a user id based on the full name, if that is
   passed.  This may result in an id like ``bob-jones-2``.

When the email address is used as login name, we originally
used the email address as user id as well.  This has a few
possible downsides, which are the main reasons for the new,
pluggable approach:

- It does not work for some valid email addresses.

- Exposing the email address in this way may not be wanted.

- When the user later changes his email address, the user id
  will still be his old address.  It works, but may be

Another possibility would be to simply generate a uuid, but that is