mirror of
https://github.com/tomav/docker-mailserver
synced 2025-08-22 01:50:59 +00:00
* 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`
117 lines
4.4 KiB
Bash
117 lines
4.4 KiB
Bash
load "${REPOSITORY_ROOT}/test/helper/setup"
|
|
load "${REPOSITORY_ROOT}/test/helper/common"
|
|
|
|
BATS_TEST_NAME_PREFIX='[OAuth2] '
|
|
CONTAINER1_NAME='dms-test_oauth2'
|
|
CONTAINER2_NAME='dms-test_oauth2_provider'
|
|
|
|
function setup_file() {
|
|
export DMS_TEST_NETWORK='test-network-oauth2'
|
|
export DMS_DOMAIN='example.test'
|
|
export FQDN_MAIL="mail.${DMS_DOMAIN}"
|
|
export FQDN_OAUTH2="auth.${DMS_DOMAIN}"
|
|
|
|
# Link the test containers to separate network:
|
|
# NOTE: If the network already exists, test will fail to start.
|
|
docker network create "${DMS_TEST_NETWORK}"
|
|
|
|
# Setup local oauth2 provider service:
|
|
docker run --rm -d --name "${CONTAINER2_NAME}" \
|
|
--hostname "${FQDN_OAUTH2}" \
|
|
--network "${DMS_TEST_NETWORK}" \
|
|
--volume "${REPOSITORY_ROOT}/test/config/oauth2/Caddyfile:/etc/caddy/Caddyfile:ro" \
|
|
caddy:2.7
|
|
|
|
_run_until_success_or_timeout 20 bash -c "docker logs ${CONTAINER2_NAME} 2>&1 | grep 'serving initial configuration'"
|
|
|
|
#
|
|
# Setup DMS container
|
|
#
|
|
|
|
# Add OAuth2 configuration so that Dovecot can query our mocked identity provider (CONTAINER2)
|
|
local ENV_OAUTH2_CONFIG=(
|
|
--env ENABLE_OAUTH2=1
|
|
--env OAUTH2_INTROSPECTION_URL=http://auth.example.test/userinfo
|
|
)
|
|
|
|
export CONTAINER_NAME=${CONTAINER1_NAME}
|
|
local CUSTOM_SETUP_ARGUMENTS=(
|
|
"${ENV_OAUTH2_CONFIG[@]}"
|
|
|
|
--hostname "${FQDN_MAIL}"
|
|
--network "${DMS_TEST_NETWORK}"
|
|
)
|
|
|
|
_init_with_defaults
|
|
_common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
|
|
_wait_for_tcp_port_in_container 143
|
|
|
|
# Set default implicit container fallback for helpers:
|
|
export CONTAINER_NAME=${CONTAINER1_NAME}
|
|
|
|
# An initial connection needs to be made first, otherwise the auth attempts fail
|
|
_run_in_container_bash 'nc -vz 0.0.0.0 143'
|
|
}
|
|
|
|
function teardown_file() {
|
|
docker rm -f "${CONTAINER1_NAME}" "${CONTAINER2_NAME}"
|
|
docker network rm "${DMS_TEST_NETWORK}"
|
|
}
|
|
|
|
@test "should authenticate with XOAUTH2" {
|
|
__should_login_successfully_with 'XOAUTH2'
|
|
}
|
|
|
|
@test "should authenticate with OAUTHBEARER" {
|
|
__should_login_successfully_with 'OAUTHBEARER'
|
|
}
|
|
|
|
function __should_login_successfully_with() {
|
|
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:
|
|
_run_in_container grep 'dovecot:' /var/log/mail.log
|
|
refute_output --partial 'oauth2 failed: Introspection failed'
|
|
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'
|
|
}
|