Open desirider opened 2 years ago
OAUTHBEARER
is intended to replace XOAUTH2
, but may take a while for that transition to be more widespread. Dovecot supports both.
XOAUTH2
(Googles widely adopted implementation, which alpine
mail client docs refer to as deprecated) and OAUTHBEARER
(the newer variant standardized by RFC 7628 in 2015).EDIT: Presently curl
will work as shown below, but only when used within the v13.3
DMS container. Newer versions of curl have a bug where only OAUTHBEARER
is used.
DMS recently added support for these in Dovecot with the v13.3 release.
AUTHENTICATE
example commands used to test auth against Dovecot:
compose.yaml
+ Caddyfile
usable without BATS, or equivalent setup in the related BATS test.If you need a popular production instance to test against, DMS makes this simple (it already bundles the latest swaks
from Github Releases):
# Normally this would provide TLS configured for both services, that's been omitted to keep the reproduction simple
services:
# Quick and easy mailserver setup with Postfix + Dovecot for testing OAuth2 support
dms:
image: docker.io/mailserver/docker-mailserver:13.3
container_name: dms-mail
hostname: mail.example.test
environment:
# Enable the OAuth2 support in Dovecot and configure it for our mocked service (caddy):
ENABLE_OAUTH2: 1
OAUTH2_INTROSPECTION_URL: http://auth.example.test/userinfo/
# Test authentication against these ports:
ports:
- "143:143" # IMAP STARTTLS (Dovecot)
- "587:587" # SMTP STARTTLS (Postfix)
configs:
- source: dms-accounts
target: /tmp/docker-mailserver/postfix-accounts.cf
# This would normally be a proper auth service, this is sufficient to mock out the required behaviour for testing
caddy-oauth2:
image: caddy:2.7
container_name: dms-oauth2
# Leverage Docker's internal DNS for the private network bridge it creates between services:
hostname: auth.example.test
ports:
- "80:80"
configs:
- source: mock-auth-service
target: /etc/caddy/Caddyfile
# Using the Docker Compose `configs.content` feature instead of volume mounting separate files.
# NOTE: This feature requires Docker Compose v2.23.1 (Nov 2023) or newer:
# https://github.com/compose-spec/compose-spec/pull/446
configs:
# Basic Caddyfile example, see a better documented equivalent at:
# https://github.com/docker-mailserver/docker-mailserver/blob/v13.3.0/test/config/oauth2/Caddyfile
mock-auth-service:
content: |
:80 {
@auth header Authorization "Bearer DMS_YWNjZXNzX3Rva2Vu"
handle @auth {
respond `{ "email": "john.doe@example.test", "email_verified": true }`
}
# Otherwise fail when expected auth header and value were not matched:
respond 401 {
close
}
}
# DMS expects an account to be configured to run, this config provides one
# You can add new accounts with `docker compose exec dms setup email add user@example.test bad-password`
# Login credentials:
# user: "john.doe@example.test" password: "secret"
# user: "jane.doe@example.test" password: "secret"
dms-accounts:
# NOTE: `$` needed to be repeated to escape it,
# which opts out of the `compose.yaml` variable interpolation feature.
content: |
john.doe@example.test|{SHA512-CRYPT}$$6$$sbgFRCmQ.KWS5ryb$$EsWrlYosiadgdUOxCBHY0DQ3qFbeudDhNMqHs6jZt.8gmxUwiLVy738knqkHD4zj4amkb296HFqQ3yDq4UXt8.
jane.doe@example.test|{SHA512-CRYPT}$$6$$o65y1ZXC4ooOPLwZ$$7TF1nYowEtNJpH6BwJBgdj2pPAxaCvhIKQA6ww5zdHm/AA7aemY9eoHC91DOgYNaKj1HLxSeWNDdvrp6mbtUY.
Generate the auth strings with base64 encoding via CLI if necessary:
Test commands (run on the host system after a docker compose up --force-recreate
):
# Testing against the mocked endpoint directly (which is what Dovecot is responsible for handling):
# - Within the DMS container this would be to http://auth.example.test/userinfo
# - Otherwise from the host system reach the caddy container via the published port on localhost
# In this case Dovecot is configured by default to validate successful auth by matching the
# returned `email` field against the `user` field (provided via the auth string).
curl http://localhost:80/userinfo -H 'Authorization: Bearer DMS_YWNjZXNzX3Rva2Vu' -w '\n'
# Response: { "email": "john.doe@example.test", "email_verified": true }
# Testing through Postfix SMTP AUTH via the proposed swaks options of this PR:
# `swaks` is also available within the container (at `/usr/local/bin/swaks`),
# use it via `docker compose exec dms swaks ...`
swaks --server localhost:587 \
--from john.doe@example.test \
--to jane.doe@example.test \
--auth XOAUTH2 \
-au john.doe@example.test \
-ap DMS_YWNjZXNzX3Rva2Vu
For comparison here is the equivalent with curl:
# Set `--login-options` to either 'AUTH=XOAUTH2' or 'AUTH=OAUTHBEARER'.
# Both are valid and the DMS container logs from Postfix will indicate the correct method like:
# `sasl_method=OAUTHBEARER, sasl_username=john.doe@example.test`
# The curl output itself also shows authentication success during the SMTP protocol.
#
# NOTE: If running on the host replace `mail.example.test` with `localhost`.
# NOTE: Technically `--upload-file` expects a proper input with RFC 5322 headers:
# https://everything.curl.dev/usingcurl/smtp
curl --silent --verbose \
--url 'smtp://mail.example.test:587' \
--user 'john.doe@example.test' \
--login-options 'AUTH=XOAUTH2' \
--oauth2-bearer 'DMS_YWNjZXNzX3Rva2Vu' \
--mail-from 'john.doe@example.test' \
--mail-rcpt 'jane.doe@example.test' \
--upload-file <<< 'Hello Jane!'
Hi John,
I've added and tested support for XOAUTH2 authorization protocol. Also added documentation, with Gmail as an example. The XOAUTH2 protocol requires an access token, and I am passing it via the -ap argument.
Tested it several times on my local machine.
Thanks, Desirider.