Adding application-specific passwords to Dovecot when using system user accounts

I was looking to add application-specific passwords to my Dovecot-based mail server today. That is, allow login to my mail account using multiple passwords, and create new passwords that would be used only by a particular client. The idea is that you configure, say, each of your laptops and phones to use a different password for logging into your mail account. That way if a particular system is lost or stolen, or you worry the credentials stored on it might have been compromised in any other way, you can revoke just that system's password, without having to change the password used by all your other systems or for interactive login (e.g. via a webmail app). It also means you can change the password you use for interactive login without having to change all the stored passwords on your various devices.

There is a fairly well-known guide to doing this already, written by Daniel Siegel, but it had a couple of problems for me: it's based on virtual users, and it assumes you'll set all the passwords you want to use for a given account in the passwd file that contains the app-specific passwords.

This doesn't really work for my setup. I use real user accounts, and use FreeIPA for authentication / identity management. Basically, I have user foo configured in FreeIPA, my mail server is enrolled as a FreeIPA client, and Dovecot is configured to use the PAM password database and the passwd user database (this is what you get if you use the auth-system.conf.ext file packaged with dovecot).

If you're in a similar situation and want to add application-specific passwords to your existing configuration so you can log in using both the password configured in the local user database or FreeIPA and the application-specific password trick Daniel uses, it turns out it's very simple - all you have to do is add Daniel's passdb directive and the password file. Don't do anything else - don't add any userdb directive. So, just add this stanza to your config:

passdb {
  driver = passwd-file
  args = /etc/dovecot/app_specific_passwd
}

(or whatever filename you want to use, obviously) and populate the file as Daniel recommends but without the first line that sets the main password. e.g.:

mobile:{SHA512-CRYPT}123456789...::::::user=foo
webmail:{SHA512-CRYPT}0123abcd...::::::user=foo
tablet:{SHA512-CRYPT}987654321...::::::user=foo

make sure you get the number of colons in a row right - it's six. Don't literally include the ..., Daniel just used those to indicate the rest of the hashed password (not that anyone would make THAT mistake, cough cough). Generate the hashed passwords with doveadm pw -s SHA512-CRYPT (or whatever crypt scheme you want to use, of course). As long as foo is a valid user so far as your userdb is concerned - that is, when using the passwd userdb, so far as your NSS configuration is concerned, so just /etc/passwd in a simple configuration, but it could also pull from your FreeIPA server or whatever - you'll be able to login as 'mobile', 'webmail' or 'tablet' with the password specified, and you'll wind up authenticated as 'foo'.

I did this by creating a new file /etc/dovecot/conf.d/auth-appspecificpasswd.conf.ext and editing /etc/dovecot/conf.d/10-auth.conf to include it before auth-system.conf.ext:

!include auth-appspecificpasswd.conf.ext
!include auth-system.conf.ext

the result is that the app-specific password file will be tried before PAM - I like it that way around because the file check is much faster and also doesn't generate error messages when it fails. If you do it the other way around, app-specific password logins take longer and spam your logs with failure messages from the PAM check failing before the passwd-file check kicks in.

Comments

DK wrote on 2015-11-03 09:59:
You can actually use the same usernames in the passwd file as in FreeIPA. Dovecot will check the second passdb if the password in the first one doesn't match. A better way would be to use a small database as a passdb in dovecot and create a small (php) script which creates a random app specific password if the user requests one. For webmail you can also use a passdb which will only be used if the user logs in from localhost. In your webmail application you can use a plugin to authenticate with PAM or LDAP first (using OTP) and replace the user password with a static one. This also allows to use a seperate web based single sign on (OpenID, Shibboleth, ...). Example: passdb { driver = sql # sqlite table holding IP specific passwords which can be used for all users. Used by Webmail. # has to be a sql db, because of the query. # Fields: ip_adress, password # password_query = SELECT password, "%u" AS user \ # FROM users WHERE ip_address = '%r' args = /etc/dovecot/dovecot-ip-specific-sql.conf.ext } passdb { # mysql db which is used for app specific passwords, which the users can set themselves. # password_query = SELECT password, user FROM users WHERE user = '%u' driver = sql args = /etc/dovecot/dovecot-app-specific-sql.conf.ext } passdb { # FreeIPA login driver = pam args = failure_show_msg=yes cache_key=%u%r dovecot } You also need to provide a real userdb otherwise this might allow login to deactivated or non-existent users