fix: Correctly support multiple Dovecot PassDBs (#3812)
* fix: Dovecot PassDB should restrict allowed auth mechanisms This prevents PassDBs incompatible with certain auth mechanisms from logging failures which accidentally triggers Fail2Ban. Instead only allow the PassDB to be authenticated against when it's compatible with the auth mechanism used. * tests: Use `curl` for OAuth2 login test-cases instead of netcat `curl` provides this capability for both IMAP and SMTP authentication with a bearer token. It supports both `XOAUTH2` and `OAUTHBEARER` mechanisms, as these updated test-cases demonstrate. * chore: Add entry to `CHANGELOG.md`
This commit is contained in:
parent
d40a17f7e0
commit
611a66bf98
|
@ -6,6 +6,13 @@ All notable changes to this project will be documented in this file. The format
|
||||||
|
|
||||||
> **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes.
|
> **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
**Dovecot:**
|
||||||
|
- Restrict the auth mechanisms for PassDB configs we manage (oauth2, passwd-file, ldap) ([#3812](https://github.com/docker-mailserver/docker-mailserver/pull/3812))
|
||||||
|
- Prevents misleading auth failures from attempting to authenticate against a PassDB with incompatible auth mechanisms.
|
||||||
|
- When the new OAuth2 feature was enabled, it introduced false-positives with logged auth failures which triggered Fail2Ban to ban the IP.
|
||||||
|
|
||||||
## [v13.3.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.3.0)
|
## [v13.3.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.3.0)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# NOTE: This is effectively the same default LDAP config shipped by Dovecot
|
||||||
|
# The only difference is the addition of the passdb mechanisms field,
|
||||||
|
# which restricts what auth mechanisms are supported / expected.
|
||||||
|
# This prevents unnecessary auth failure logs triggering Fail2Ban when
|
||||||
|
# additional passdb are enabled (OAuth2).
|
||||||
|
|
||||||
|
passdb {
|
||||||
|
driver = ldap
|
||||||
|
mechanism = plain login
|
||||||
|
|
||||||
|
# Path for LDAP configuration file, see example-config/dovecot-ldap.conf.ext
|
||||||
|
args = /etc/dovecot/dovecot-ldap.conf.ext
|
||||||
|
}
|
||||||
|
|
||||||
|
userdb {
|
||||||
|
driver = ldap
|
||||||
|
args = /etc/dovecot/dovecot-ldap.conf.ext
|
||||||
|
|
||||||
|
# Default fields can be used to specify defaults that LDAP may override
|
||||||
|
#default_fields = home=/home/virtual/%u
|
||||||
|
}
|
|
@ -1,5 +1,12 @@
|
||||||
|
# Allow clients to use these additional mechanisms:
|
||||||
auth_mechanisms = $auth_mechanisms oauthbearer xoauth2
|
auth_mechanisms = $auth_mechanisms oauthbearer xoauth2
|
||||||
|
|
||||||
|
# Dovecot docs consider the oauth2 driver as a "success/failure" type PassDB:
|
||||||
|
# https://doc.dovecot.org/configuration_manual/authentication/password_databases_passdb/#success-failure-database
|
||||||
|
# Which implies it cannot be configured for the non-plaintext SASL mechanisms listed here:
|
||||||
|
# https://doc.dovecot.org/configuration_manual/authentication/authentication_mechanisms/#dovecot-supports-the-following-non-plaintext-mechanisms
|
||||||
|
# However that is not the case, these mechanisms are still valid to prevent trying other incompatible mechanisms (like `plain`).
|
||||||
|
|
||||||
passdb {
|
passdb {
|
||||||
driver = oauth2
|
driver = oauth2
|
||||||
mechanisms = xoauth2 oauthbearer
|
mechanisms = xoauth2 oauthbearer
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
passdb {
|
passdb {
|
||||||
driver = passwd-file
|
driver = passwd-file
|
||||||
|
mechanisms = plain login
|
||||||
args = scheme=SHA512-CRYPT username_format=%u /etc/dovecot/userdb
|
args = scheme=SHA512-CRYPT username_format=%u /etc/dovecot/userdb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# NOTE: This portion of config is only relevant for understanding what happens seamlesssly,
|
||||||
|
# DMS tests no longer use raw IMAP commands with netcat, thus none of this is relevant beyond reference for troubleshooting.
|
||||||
|
#
|
||||||
# /imap/xoauth2
|
# /imap/xoauth2
|
||||||
# Generate IMAP commands for authentication testing
|
# Generate IMAP commands for authentication testing
|
||||||
# Base64 encoded credentials can alternative be done via CLI with:
|
# Base64 encoded credentials can alternative be done via CLI with:
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
a0 NOOP See test/config/oauth2/Caddyfile to generate the below OAUTHBEARER string
|
|
||||||
a1 AUTHENTICATE OAUTHBEARER bixhPXVzZXIxQGxvY2FsaG9zdC5sb2NhbGRvbWFpbiwBaG9zdD1sb2NhbGhvc3QBcG9ydD0xNDMBYXV0aD1CZWFyZXIgRE1TX1lXTmpaWE56WDNSdmEyVnUBAQ==
|
|
||||||
a2 EXAMINE INBOX
|
|
||||||
a3 LOGOUT
|
|
|
@ -1,4 +0,0 @@
|
||||||
a0 NOOP See test/config/oauth2/Caddyfile to generate the below XOAUTH2 string
|
|
||||||
a1 AUTHENTICATE XOAUTH2 dXNlcj11c2VyMUBsb2NhbGhvc3QubG9jYWxkb21haW4BYXV0aD1CZWFyZXIgRE1TX1lXTmpaWE56WDNSdmEyVnUBAQ==
|
|
||||||
a2 EXAMINE INBOX
|
|
||||||
a3 LOGOUT
|
|
|
@ -58,21 +58,59 @@ function teardown_file() {
|
||||||
docker network rm "${DMS_TEST_NETWORK}"
|
docker network rm "${DMS_TEST_NETWORK}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "should authenticate with XOAUTH2 over IMAP" {
|
@test "should authenticate with XOAUTH2" {
|
||||||
_nc_wrapper 'auth/imap-oauth2-xoauth2.txt' '-w 1 0.0.0.0 143'
|
__should_login_successfully_with 'XOAUTH2'
|
||||||
__verify_successful_login 'XOAUTH2'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "should authenticate with OAUTHBEARER over IMAP" {
|
@test "should authenticate with OAUTHBEARER" {
|
||||||
_nc_wrapper 'auth/imap-oauth2-oauthbearer.txt' '-w 1 0.0.0.0 143'
|
__should_login_successfully_with 'OAUTHBEARER'
|
||||||
__verify_successful_login 'OAUTHBEARER'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function __verify_successful_login() {
|
function __should_login_successfully_with() {
|
||||||
local AUTH_METHOD=${1}
|
local AUTH_METHOD=${1}
|
||||||
|
# These values are the auth credentials checked against the Caddy `/userinfo` endpoint:
|
||||||
|
local USER_ACCOUNT='user1@localhost.localdomain'
|
||||||
|
local ACCESS_TOKEN='DMS_YWNjZXNzX3Rva2Vu'
|
||||||
|
|
||||||
|
__verify_auth_with_imap
|
||||||
|
__verify_auth_with_smtp
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dovecot direct auth verification via IMAP:
|
||||||
|
function __verify_auth_with_imap() {
|
||||||
|
# NOTE: Include the `--verbose` option if you're troubleshooting and want to see the protocol exchange messages
|
||||||
|
# NOTE: `--user username:password` is valid for testing `PLAIN` auth mechanism, but you should prefer swaks instead.
|
||||||
|
_run_in_container curl --silent \
|
||||||
|
--login-options "AUTH=${AUTH_METHOD}" --oauth2-bearer "${ACCESS_TOKEN}" --user "${USER_ACCOUNT}" \
|
||||||
|
--url 'imap://localhost:143' -X 'LOGOUT'
|
||||||
|
|
||||||
|
__dovecot_logs_should_verify_success
|
||||||
|
}
|
||||||
|
|
||||||
|
# Postfix delegates by default to Dovecot via SASL:
|
||||||
|
# NOTE: This won't be compatible with LDAP if `ENABLE_SASLAUTHD=1` with `ldap` SASL mechanism:
|
||||||
|
function __verify_auth_with_smtp() {
|
||||||
|
# NOTE: `--upload-file` with some mail content seems required for using curl to test OAuth2 authentication.
|
||||||
|
# TODO: Replace with swaks and early exit option when it supports XOAUTH2 + OAUTHBEARER:
|
||||||
|
_run_in_container curl --silent \
|
||||||
|
--login-options "AUTH=${AUTH_METHOD}" --oauth2-bearer "${ACCESS_TOKEN}" --user "${USER_ACCOUNT}" \
|
||||||
|
--url 'smtp://localhost:587' --mail-from "${USER_ACCOUNT}" --mail-rcpt "${USER_ACCOUNT}" --upload-file - <<< 'RFC 5322 content - not important'
|
||||||
|
|
||||||
|
# Postfix specific auth logs:
|
||||||
|
_run_in_container grep 'postfix/submission/smtpd' /var/log/mail.log
|
||||||
|
assert_output --partial "sasl_method=${AUTH_METHOD}, sasl_username=${USER_ACCOUNT}"
|
||||||
|
|
||||||
|
# Dovecot logs should still be checked as it is handling the actual auth process under the hood:
|
||||||
|
__dovecot_logs_should_verify_success
|
||||||
|
}
|
||||||
|
|
||||||
|
function __dovecot_logs_should_verify_success() {
|
||||||
# Inspect the relevant Dovecot logs to catch failure / success:
|
# Inspect the relevant Dovecot logs to catch failure / success:
|
||||||
_run_in_container grep 'dovecot:' /var/log/mail.log
|
_run_in_container grep 'dovecot:' /var/log/mail.log
|
||||||
refute_output --partial 'oauth2 failed: Introspection failed'
|
refute_output --partial 'oauth2 failed: Introspection failed'
|
||||||
assert_output --partial "dovecot: imap-login: Login: user=<user1@localhost.localdomain>, method=${AUTH_METHOD}"
|
assert_output --partial "dovecot: imap-login: Login: user=<${USER_ACCOUNT}>, method=${AUTH_METHOD}"
|
||||||
|
|
||||||
|
# If another PassDB is enabled, it should not have been attempted with the XOAUTH2 / OAUTHBEARER mechanisms:
|
||||||
|
# dovecot: auth: passwd-file(${USER_ACCOUNT},127.0.0.1): Password mismatch (SHA1 of given password: d390c1) - trying the next passdb
|
||||||
|
refute_output --partial 'trying the next passdb'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue