Cyrus Authentication - An Overview
A lot of questions and problems when using Cyrus IMAPd revolve around user authentication. This is largely owed to the fact that several technologies come to play when a user logs into IMAPd and documentation is scattered around these different subjects. Keywords are SASL, PAM, etc.
Authentication only relates to verify
who a user is, and does not strictly relates to decide
what a user can do, that's a matter of Authorization.
Logging in to Cyrus IMAPd
When it comes to authentication, Cyrus IMAPd does not have any kind of a built-in user database itself. Instead all it does is to delegate the authentication of a user to an authentication service and expects an answer from the authentication service, which will either be:
- authentication failed: IMAPd will close the connection
- authenticated as userid: start the IMAP session for that userid
Depending on your environment, you will have entirely different needs for the credentials database against which Cyrus IMAPd checks logins. In an in-house environment you might even be looking for not having to log in at all but use some kind of SSO mechanism to authenticate against Cyrus IMAPd, making sure users don't have to use a username / password at all. You might also be looking at delegating the password checking to any kind of external system, for example via RADIUS, so make use of a hardware token generating one-time passwords. A very common scenario in a lot of places is that you might want to use a plain LDAP or
ActiveDirectory? as your credentials database. Note that LDAP authentication does hold a number of interesting challenges as such. More on that later.
Even if your ultimate goal is to keep your users in an LDAP database, which is a popular choice these days, you still have the option to have different layers in between your LDAP database and Cyrus IMAPd, again depending on that you are trying to achieve. The takeaway from that is: There is hardly a right or wrong way of setting this up; there might only be more and less complicated as well as more or less suitable ways of designing this.
SASL
SASL stands for Simple Authentication and Security Layer, despite the fact that some people object to the acronym's first 'S'. You can think of SASL as glue between
- an application, Cyrus IMAPd in this case, wanting to authenticate a user
- the client wanting to access the application, the user's MUA (Mail User Agent)
- the network in between
For some more details on SASL visit
Configuring Cyrus IMAPd's user authentication means nothing but configuring the SASL layer. Therefore you find very little documentation on configuring Cyrus IMAPd's authentication as all the relevant information is over in the SASL library documentation. But as the SASL library is not designed just for IMAPd but with any abritrary application in mind, examples in the SASL library documentation are not IMAP specific.
In this text the author does not care as much about keeping things separate as providing a practical, hands-on overview of configuration choices and their potential side effects.
For the remainder of the document, it's important to understand the interwoven nature of collaboration between the chosen SASL
mechanism and the chosen
password checking service. The term
password checking service as such is never mentioned in the SASL documentation itself, but this is basically what it is. The corresponding parameter in SASL config is called
pwcheck (see the
sasl_pwcheck_method option in imapd.conf).
You can choose between three available services:
- pwcheck
- saslauthd
- auxprop
Naming is somewhat confusing here. All of them are implementations of the "check the password for a given user" service, and each uses an entirely different approach to achieve this. So the value pwcheck for the parameter pwcheck is one of three choices. And by the way, it's the pwcheck service which is using the mechanism, not vice versa. This is
not a two-stage process where the mechanism would be responsible for getting a username / password combination from the client to the server, that the checking service embarking on that. This would not work for some combinations of mechanisms and password checking services.
- The pwcheck daemon solves the problem that the IMAPd process usually runs under a user id which does not have access to the /etc/shadow passwords file. Therefore access to that file is outsourced to a purpose built daemon that comes with the SASL library distribution and mediates between the IMAPd process and the /etc/shadow file. In other words, you need pwcheck=pwcheck only if you want to use /etc/passwd and /etc/shadow as your user credentials database.
- The saslauthd is a similar construct to the pwcheck daemon (note it's pwcheck, not pwcheckd), built as well to de-couple processes for separation of privilege. In contrast to the pwcheck (daemon) it has a wider range of databases it can use.
- The auxprop service should better be renamed to db service. All it provides is a generic database query interface to which you can feed a username and it goes to a database and fetches the plain text password for you. In order to make that happen, the auxprop plugin itself needs a further plugin which connects to a specific database. One available database backend is ldabdb which connects to an OpenLDAP? server to query the password. Once the auxprop service knows the plain password it will consult the mechanism to come to a yes / no conclusion about the outcome of the authentication. In other words, with auxprop and the PLAIN mech, this is going to be a simple string comparison. With a CRAM-MD5 mechanism, it will use the plain text password on the server to caculate the challenge and then send it to the client...
Note that the auxprop mechanism together with its backend database plugin run entirely in-process. In the case of Cyrus IMAPd it is executed in the imapd process. Only pwcheck and saslauthd involve separate processes.
A SASL
mechanism (short: mech) is a technique used for a challenge-response dialog over a (potentially insecure) network. The simplest mechanisms are
ANONYMOUS (no credentials needed at all) and
PLAIN which is nothing but exchanging a username and password in plain text. Popular choices in practice are
CRAM-MD5 and
DIGEST-MD5. Mechanisms are implemented as plugins, so any new mechanism can be added to the system by providing an appropriate SASL plugin. Please remember that this is still only about how a username and password are transmitted (or not transmitted but otherwise proofed) across the network. This does not yet say anything about the credentials database against which the information is checked. The mechanism of your choice is specified with the
sasl_mech_list option in imapd.conf.
Why some combinations of SASLs mechanisms and SASL password checking services are incompatible by design
There are some mechanisms which rely on the server having access to the plain password of the user in order to calculate a challenge from it by applying some crypto algorithms. This is incompatible with authentication services which will not reveal the plain text password using any means, maybe because they don't even have it. This does happen if you use an LDAP database to store your user credentials and choose to store not the plain passwords but hashes (MD5 or otherwise) of them.
Source of lots of confusion: LDAP
While the whole thing sounds quite logical up to here, many administrators start struggling when it comes to setting up authentication against LDAP properly. There are indeed at least two different approaches for how to set this up. And again, there's no right or wrong, just "it depends".
To use LDAP for authentication, you can either:
- retrieve the user's userPassword attribute from the corresponding LDAP object and then use that password in the SASL library code to do password checking using the chosen mechanism. Think of this as the auxprop way of doing LDAP authentication.
- try to bind to the LDAP directory using the credentials you have been given and have LDAP decide on success or failure. This cannot be done from an auxprop plugins using their API. An auxprop plugin is not supposed to reply with success or failure but hand back a plain text password. Therefore this method, where authentication is pretty much delegated to the LDAP server, means you can only use this from saslauthd.
There are pros and cons to each approach. Sometimes you might not have a choice of which way to go.
- If you don't control the LDAP server, you might not be able to retrieve the plain text password from it, which would basically force you into pwcheck = saslauthd. This will most likely be the case if the LDAP server is a corporate directory which is used for lots of other applications as well. Even worse, if the LDAP server had existed long before you tried to use it from SASL and it stored user passwords as hashes (MD5 or other) it won't even have the plain text passwords anymore as MD5 is a unidirectional algorithm.
- Using pwcheck=saslauthd precludes you from using any canon_user plugins. (This is to be checked.)
While using saslauthd with an LDAP server configured as a backend works fine, in theory, there would be no need for the extra complexity of running a separate process. In theory, nothing would be wrong with a pwcheck=ldap service which could easily run in-process, it's just non-existant.
LDAP and saslauthd configuration sample
In order to further clarify how to use a (perhaps already existing) LDAP server as your credentials database, following are working examples of relevant sections of imapd.conf and saslauthd.conf:
imapd.conf
sasl_pwcheck_method: saslauthd
sasl_mech_list: PLAIN
saslauthd.conf
ldap_servers: ldap://your.ldap-host.tld
ldap_version: 3
ldap_timeout: 10
ldap_time_limit: 10
ldap_search_base: o=what-ever-you-may-have,dc=your-domain,dc=tld
ldap_bind_dn: cn=your-ldap-admin-name,dc=your-domain,dc=tld
ldap_password: your-ldap-admin-password
ldap_scope: sub
ldap_uidattr: the-attribute-name-in-which-you-store-usernames, es: uid
ldap_filter_mode: yes
ldap_filter: (uid=%u%R)
Using such a configuration, Cyrus delegates user authentication to saslauthd (using PLAINtext) which, in turn, delegates to the LDAP server for user and password verification (again, over an insecure channel in this example). You must provide saslauthd with credentials (ldap_bind_dn, ldap_password) for an LDAP user authorized to access the userPassword attribute for any LDAP user, usually (but not necesarily) an administrator -- please refer to your LDAP server documentation.
--
TorstenSchlabach - 08 Jun 2007