LDAP
====

There are two ways to do LDAP authentication: password lookups and
authentication binds. Both of these have their own advantages.

Password lookups
----------------

This method is faster than authentication binds, because Dovecot needs to do
only a single LDAP binding when the connection opens. After that it can keep
sending LDAP requests asynchronously to the LDAP server.

Normally LDAP server doesn't give anyone access to users' userPassword field,
so you'll need to configure some administrator account which has access to them
(see<HowTo.DovecotOpenLdap.txt> for general LDAP configuration examples). With
OpenLDAP this can be done by modifying '/etc/ldap/slapd.conf':

---%<-------------------------------------------------------------------------
# there should already be something like this in the file:
access to attribute=userPassword
        by dn="<dovecot's dn>" read  # just add this line
        by anonymous auth
        by self write
        by * none
---%<-------------------------------------------------------------------------

Use the same dn in Dovecot's 'dn' setting.

The two important settings in password lookups are 'pass_filter' and
'pass_attrs'. 'pass_filter' specifies the LDAP filter how user is found from
the LDAP. You can use all the normal<variables> [Variables.txt]  like '%u' in
the filter.'pass_attrs' specifies a list of attributes that are returned from
the LDAP. If you set it to empty, all the attributes are returned.

'pass_attrs' is a comma separated list of '<ldap attribute>=<dovecot field>'
fields. If '=<dovecot field>' is omitted, they're treated equal. For example
'userPassword=password' means that "userPassword" LDAP attribute contains
Dovecot's "password" field.

Most importantly the 'pass_attrs' should return a "password" field which
contains the user's password. The next thing Dovecot needs to know is what
format the password is in. If all the passwords are in same format, you can use
'default_pass_scheme' to specify it. Otherwise each password needs to be
prefixed with "{password-scheme}", for example "{plain}plaintext-password". See
<Authentication.PasswordSchemes.txt> for a list of supported password schemes.

The next problem you have is that LDAP lookups are case-insensitive. Unless you
somehow normalize the username, it's possible that a user logging in as "user",
"User" and "uSer" are treated differently. The easiest way to handle this is to
tell Dovecot to change the username to the same case as it's in the LDAP
database. You can do this by returning "user" field in the 'pass_attrs'.

Besides "user" and "password" fields, the 'pass_attrs' may contain also other
special<extra fields> [PasswordDatabase.ExtraFields.txt].

So a typical configuration would look like:

---%<-------------------------------------------------------------------------
auth_bind = no
pass_attrs = uid=user,userPassword=password
pass_filter = (&(objectClass=posixAccount)(uid=%u))
default_pass_scheme = LDAP-MD5
---%<-------------------------------------------------------------------------

Authentication binds
--------------------

Authentication binds have two advantages:

 1. The LDAP server verifies the password, so Dovecot doesn't need to know what
    format the password is in the LDAP server.
 2. A bit more secure, as a security hole in Dovecot doesn't give attacker
    access to all the users' passwords.

The main downside is that it's somewhat slower because there can't be any LDAP
requests pending while the binding is in progress. So the LDAP request queue is
first flushed, then the binding to user is done, and finally binding is done
back to the default DN before any userdb LDAP requests can be done.

Because of the above extra binding it can be slightly faster if you use
separate LDAP connections for passdb and userdb. This can be done by specifying
different filenames in passdb's and userdb's args. The files themselves can be
identical or even symlinks to the same file, as long as the filename is
different.

You can enable authentication binds by setting 'auth_bind=yes'. Next Dovecot
needs to know what DN to use in the binding. There are two ways to configure
this: passdb lookup or userdn template.

passdb lookup
-------------

This is very similar to "Password lookups" described above, except that
'pass_attrs' doesn't need to return "password" field. The 'pass_filter' is used
to find the LDAP entry, and the DN is taken from the reply.

Just as with password lookups, the 'pass_attrs' may contain special <extra
fields> [PasswordDatabase.ExtraFields.txt].

A typical configuration would look like:

---%<-------------------------------------------------------------------------
auth_bind = yes
# returning "user" changes the username to be in same case as in LDAP database
pass_attrs = uid=user
pass_filter = (&(objectClass=posixAccount)(uid=%u))
---%<-------------------------------------------------------------------------

userdn template
---------------

Using the userdn template is faster because it avoids one LDAP lookup. However
with only IMAP/POP3 logins this can also be accomplished with prefetch userdb
(see below). Then again if you're also using SMTP AUTH, or something else which
doesn't do userdb lookup, this is again faster because no LDAP lookups need to
be done.

If you're using userdn template, 'pass_attrs' and 'pass_filter' settings are
completely ignored. That also means that you can't make passdb return any<extra
fields> [PasswordDatabase.ExtraFields.txt].

Note that all other examples have used 'pass_attrs = uid=user' to change
username's case to same as in the LDAP database. This can't be done with userdn
template, so you'll need to normalize the case some other way. The easiest way
is to use 'auth_username_format = %Lu' in dovecot.conf to make the username
always lowercased.

A typical configuration would look like:

---%<-------------------------------------------------------------------------
auth_bind = yes
auth_bind_userdn = cn=%u,ou=people,o=org
---%<-------------------------------------------------------------------------

User database lookups
---------------------

Usually your LDAP database contains also the userdb information. This means
user's UID, GID and home directory. If you're using only static UID and GID,
and your home directory can be specified with a template, you could use<static
userdb> [UserDatabase.Static.txt] instead. It is also a bit faster since it
avoids doing the userdb LDAP lookup.

Userdb lookups are always done using the default DN ('dn' setting) binding.
It's not possible to do the lookup using the user's DN (remember that
eg.<deliver> [LDA.txt] needs to do userdb lookups without knowing the user's
password).

The userdb lookups are configured in very much the same way as passdb lookups.
'user_filter' contains how to find the user entry (usually it's exactly the
same as 'pass_filter'). 'user_attrs' contains a comma separated list of '<ldap
attribute>=<dovecot field>' fields, just like described above for 'pass_attrs'.

The commonly returned userdb fields are uid, gid, home and mail. See
<UserDatabase.ExtraFields.txt> for more information about these and other
fields that can be returned.

If you're using a single UID and GID for all the users, you can specify them
globally instead of returning them from LDAP:

 * v1.0: 'user_global_uid' and 'user_global_gid' settings in
   'dovecot-ldap.conf'
 * v1.1: 'mail_uid' and 'mail_gid' settings in 'dovecot.conf'

Attribute templates
-------------------

v1.1+: You can mix static text with the LDAP value by using %$ in the value,
for example:

---%<-------------------------------------------------------------------------
# create a "quota_rule" key with value "*:bytes=<n>" where <n> value
# is taken from quotaBytes LDAP attribute.
user_attrs = quotaBytes=quota_rule=*:bytes=%$
---%<-------------------------------------------------------------------------

You can also add static fields that aren't looked up from LDAP (v1.1.rc5+):

---%<-------------------------------------------------------------------------
# create "mail" key with value "/var/vmail/%d/%n"
user_attrs = homeDirectory=home,=mail=/var/vmail/%d/%n
---%<-------------------------------------------------------------------------

You can combine static and LDAP values with the following syntax:

---%<-------------------------------------------------------------------------
# use sAMAccountName as username and deliver mail to
/var/spool/vmail/{sAMAccountName}
# and use static gid and uid
user_attrs = sAMAccountName=mail=maildir:/var/spool/vmail/%$,=gid=12,=uid=1001
---%<-------------------------------------------------------------------------

Connecting
----------

You can specify one or more LDAP servers using 'hosts' or 'uris' settings. The
URIs aren't supported by all the LDAP libraries. They're in format
scheme://host:port, eg. ldap://localhost.

SSL/TLS
-------

If your LDAP library supports TLS, you can enable it by setting 'tls=yes'.
FIXME: I'm not sure how the actual TLS configuration (certificates etc.) can be
done. The OpenLDAP library reads some configuration files which can be used to
do it.

Apparently it's also possible to use SSL by using ldaps scheme in the URI.

SASL binds
----------

It's possible to use SASL binds if your LDAP library supports them. See the
sasl_* settings in dovecot-ldap.conf. Note that SASL binds are currently
incompatible with authentication binds.

Active Directory
----------------

When connecting to AD, use port 3268.

Prefetching
-----------

If you want to avoid userdb lookups when logging in with IMAP/POP3, you can
make the passdb lookup return all the necessary userdb fields and use prefetch
userdb to use those fields. If you're using Dovecot's<deliver> [LDA.txt] you'll
still need to have the userdb lookups working.

Note: if you choose to do prefetching *and* authentication binding, you are
still going to be making two ldap queries and you'll be limiting yourself to a
single connection to ldap. It's probably not what you want: use userdb + passdb
instead (which will give you two connections to the ldap server).

See <UserDatabase.Prefetch.txt> for example configuration. 

(This file was created from the wiki on 2009-01-07 04:42)
