Skip to content

feat: move doveauth from dictproxy to lua/http as recommended by dovecot 2.4 - #1049

Merged
hpk42 merged 2 commits into
mainfrom
hpk/luahttpauth
Sep 1, 2026
Merged

hpk42 merged 2 commits into
mainfrom
hpk/luahttpauth

Conversation

@hpk42

@hpk42 hpk42 commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

dovecot 2.4 is dropping userdb/passdb lookups via dictproxy, and recommends lua

This PR moves password verification to lua, and keeps creating addresses in python via a http request, so that doveauth.py keeps owning the creation checks, and nothing changes there.

The new auth.lua code is extensively tested and deploying it to an existing relay host works fine for me, and passes all tests.

@hpk42
hpk42 temporarily deployed to staging.chatmail.at/doc/relay/ August 31, 2026 09:18 — with GitHub Actions Inactive

@missytake missytake left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! This already works with dovecot 2.3? looking forward to trying it out tomorrow.

lua isn't that bad it seems, I can read most of it. Hope the parts of the syntax which are not super intuitive don't contain surprises.

-- Entry points called by dovecot

function script_init()
http_client = dovecot.http.client({timeout = 5000, max_attempts = 1})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the timeout so high?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

glad you asked!

a) it's milliseconds

b) the dovecot 2.3 documentation and the dovecot 2.3.21 source code somewhat disagree about the name, it is request_timeout_msecs and i fixed it here. The docs have the function signature wrong.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, good to know :D so that's the kind of thing you need to watch out for with lua?^^

@hpk42 hpk42 Sep 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. I could have noticed because the docs when they describe the args use request_timeout_msecs. Usually dovecot docs are high quality. Only the function signature name was wrong.

if not create(req.user, password) then
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, {}
end
elseif req:password_verify(hash, password) ~= 1 then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is req:password_verify() a built-in lua function in dovecot? Or where is it implemented?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, if I understand it correctly, doveauth encrypts the password during create, dovecot verifies the password during lookup, and doveauth verifies the password only in rare cases when a user was accidentally created already while create/ is called? Just asking again to verify.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that's exactly how it goes. Dovecot has a builtin function to verify passwords, so logging in with existing accounts usually does not touch doveauth.py. But due to SMTP/IMAP logins being potentially concurrent, we need to have the python side also verify if it detects concurrency. Should be a rare happening, and doesn't matter as both sides agree on how to verify passwords.

@hpk42
hpk42 temporarily deployed to staging.chatmail.at/doc/relay/ September 1, 2026 07:46 — with GitHub Actions Inactive
@hpk42
hpk42 temporarily deployed to staging.chatmail.at/doc/relay/ September 1, 2026 11:11 — with GitHub Actions Inactive
@hpk42
hpk42 requested a review from j-g00da September 1, 2026 11:53
@missytake

Copy link
Copy Markdown
Contributor

Deployed on nine successfully.

1. existing logins are now verified by lua only

2. non-existing logins are delegated to the new Python doveauth http /create endpoint

Using Lua and http this way makes doveauth more compatible to dovecot 2.4
on doveauth.py being down, users would "AUTHENTIFICATIONFAILED"
while they now get:

    IMAP failed to login as tovnlbmsz@_lua0.localchat: no response:
    code: None, info: Some("[UNAVAILABLE] Temporary authentication
    failure. [lua0-localchat:2026-09-01 11:00:17]")
@hpk42
hpk42 merged commit 2eb0ef5 into main Sep 1, 2026
9 checks passed
@hpk42
hpk42 deleted the hpk/luahttpauth branch September 1, 2026 20:56

This branch was successfully deployed

1 active deployment
staging.chatmail.at/doc/relay/ — d2b5f7b7 Deployed Sep 1, 2026 by hpk42 via build #429
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants