This documentation is for Dovecot v2.x, see wiki1 for v1.x documentation.

Lua based authentication

Since v2.3.0 you can implement passdb and userdb using Lua script.

Known bugs

Lua interface

For details about Dovecot Lua, see Design/Lua.

When used in authentication, additional module dovecot.auth is added, which contains constants for passdb and userdb.

List of constants

Also, it registers object struct auth_request* which lets access various parts of the auth request. You should use the loggers associated with auth_request when possible.

Auth request methods

Functions:

Subtables:

Members:

See Variables for details

Additionally you can access

Password database

Lua passdb supports two modes of function. It can behave as lookup database, or password verification database.

Lookup function signature is auth_passdb_lookup(request) and the password verification signature is auth_password_verify(request, password)

Both functions must return a tuple, which contains a return code, and also additionally string or table. Table must be in key-value format, it will be imported into auth request. The string must be in key=value format, except if return code indicates internal error, the second parameter can be used as error string.

If auth_verify_password is found, it's always used.

To configure passdb in dovecot, use

passdb {
   driver = lua
   args = file=/path/to/lua blocking=yes # default is yes
}

By default, dovecot runs Lua scripts in auth-worker processes. If you do not want this, you can disable blocking, and Lua script will be ran in auth process. This can degrade performance if your script is slow or makes external lookups.

User database

Lua userdb supports both single user lookup and iteration. Note that iteration will hold the whole user database in memory during iteration.

User lookup function signature is auth_userdb_lookup(request). The function must return a tuple, which contains a return code, and also additionally string or table. Table must be in key-value format, it will be imported into auth request. The string must be in key=value format, except if return code indicates internal error, the second parameter can be used as error string.

User iteration function signature is auth_userdb_iterate, which is expected to return table of usernames. Key names are ignored.

To configure userdb in dovecot, use

userdb {
   driver = lua
   args = file=/path/to/lua blocking=yes # default is yes
}

Examples

Skeleton

function auth_passdb_lookup(req)
  if req.user == "testuser1" then
    return dovecot.auth.PASSDB_RESULT_OK, "password=pass"
  end
  return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "no such user"
end

function auth_userdb_lookup(req)
  if req.user == "testuser1" then
    return dovecot.auth.USERDB_RESULT_OK, "uid=vmail gid=vmail"
  end
  return dovecot.auth.USERDB_RESULT_USER_UNKNOWN, "no such user"
end

function script_init()
  return 0
end

function script_deinit()
end

function auth_userdb_iterate()
  return {"testuser1"}
end

Simple username password database (such as opensmtpd)

The example uses whitespace separated username and password. As a special caution, the way Lua is used here means you can have multiple user password per line, instead of just one. This can be extended to more complicated separators or multiple fields per user.

If you only want to autenticate users, and don't care about user listing, you can use

function auth_passdb_lookup(req)
    for line in io.lines("/path/to/file") do
        for user, pass in string.gmatch(line, "(%w+)%s(.+)") do
            if (user == req.username) then
                -- you can add additional information here, like userdb_uid
                return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
            end
        end
    end
    return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, ""
end

If you also want to be able to list users, so that you could use doveadm cmd -A

local database = "/path/to/file"

function db_lookup(username)
    for line in io.lines(database) do
        for user, pass in string.gmatch(line, "(%w+)%s(.+)") do
            if (user == username) then
                return {result=0, password=pass}
            end
        end
    end
    return {result=-1}
end

function auth_passdb_lookup(req)
    res = db_lookup(req.username)
    if res.result == 0 then
        -- you can add additional information here for passdb
        return dovecot.auth.PASSDB_RESULT_OK, "password=" .. res.password
    end
    return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, ""
end

function auth_userdb_lookup(req)
    res = db_lookup(req.username)
    if res.result == 0 then
        -- you can add additional information here for userdb, like uid or home
        return dovecot.auth.USERDB_RESULT_OK, "uid=vmail gid=vmail"
    end
    return dovecot.auth.USERDB_RESULT_USER_UNKNOWN, ""
end

function auth_userdb_iterate()
   users = {}
   for line in io.lines(database) do
        for user in string.gmatch(line, "(%w+)%s.+") do
            table.insert(users, user)
        end
   end
   return users
end

AuthDatabase/Lua (last edited 2019-02-22 06:49:56 by AkiTuomi)