tests: OAuth2 - Minimize noise + Improve test assertion

Caddyfile can use an Access Token instead of a JWT. Much smaller and correct for this OAuth2 configuration. This new value has been documented inline.

Likewise the `sub` field returned is not important to this test. `email_verified` is kept as it may be helpful for further coverage testing.

The actual test-case has better assertions for success and failure by checking for Dovecot logs we expect instead of netcat response.

`oauth2` to `auth` for the Caddy container hostname is not necessary, just a more generic subdomain choice.
This commit is contained in:
polarathene 2024-01-19 17:23:47 +13:00
parent 7eb3fc6de0
commit c050c7290c
3 changed files with 16 additions and 11 deletions

View File

@ -3,6 +3,10 @@
# Dovecot will query the mocked `/userinfo` endpoint with the OAuth2 bearer token it was provided during login. # Dovecot will query the mocked `/userinfo` endpoint with the OAuth2 bearer token it was provided during login.
# If the session for the token is valid, a response returns an attribute to perform a UserDB lookup on (default: email). # If the session for the token is valid, a response returns an attribute to perform a UserDB lookup on (default: email).
# `DMS_YWNjZXNzX3Rva2Vu` is the access token our OAuth2 tests expect for an authorization request to be successful.
# - The token was created by base64 encoding the string `access_token`, followed by adding `DMS_` as a prefix.
# - Normally an access token is a short-lived value associated to a login session. The value does not encode any real data.
:80 { :80 {
# This is the `/userinfo` endpoint that Dovecot connects to with the OAuth2 setting (default: `introspection_mode = auth`). # This is the `/userinfo` endpoint that Dovecot connects to with the OAuth2 setting (default: `introspection_mode = auth`).
# Example: curl http://auth.example.test/userinfo -H 'Authorization: Bearer <token here>' # Example: curl http://auth.example.test/userinfo -H 'Authorization: Bearer <token here>'
@ -22,9 +26,7 @@
# /userinfo # /userinfo
:2000 { :2000 {
# OAuth2.0 Bearer token (paste into https://jwt.io/ to check it's contents). vars token "DMS_YWNjZXNzX3Rva2Vu"
# You should never need to edit this unless you REALLY need to change the issuer.
vars token "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vcHJvdmlkZXIuZXhhbXBsZS50ZXN0OjgwMDAvIiwic3ViIjoiODJjMWMzMzRkY2M2ZTMxMWFlNGFhZWJmZTk0NmM1ZTg1OGYwNTVhZmYxY2U1YTM3YWE3Y2M5MWFhYjE3ZTM1YyIsImF1ZCI6Im1haWxzZXJ2ZXIiLCJ1aWQiOiI4OU4zR0NuN1M1Y090WkZNRTVBeVhNbmxURFdVcnEzRmd4YWlyWWhFIn0.zuCytArbphhJn9XT_y9cBdGqDCNo68tBrtOwPIsuKNyF340SaOuZa0xarZofygytdDpLtYr56QlPTKImi-n1ZWrHkRZkwrQi5jQ-j_n2hEAL0vUToLbDnXYfc5q2w7z7X0aoCmiK8-fV7Kx4CVTM7riBgpElf6F3wNAIcX6R1ijUh6ISCL0XYsdogf8WUNZipXY-O4R7YHXdOENuOp3G48hWhxuUh9PsUqE5yxDwLsOVzCTqg9S5gxPQzF2eCN9J0I2XiIlLKvLQPIZ2Y_K7iYvVwjpNdgb4xhm9wuKoIVinYkF_6CwIzAawBWIDJAbix1IslkUPQMGbupTDtOgTiQ"
# Expects to match an authorization header with a specific bearer token: # Expects to match an authorization header with a specific bearer token:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes # https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
@ -38,8 +40,7 @@
respond <<EOF respond <<EOF
{ {
"email": "user1@localhost.localdomain", "email": "user1@localhost.localdomain",
"email_verified": true, "email_verified": true
"sub": "82c1c334dcc6e311ae4aaebfe946c5e858f055aff1ce5a37aa7cc91aab17e35c"
} }
EOF EOF
} }
@ -57,7 +58,7 @@
# and sending the `auth` value from the `credentials` variable as an HTTP Authorization header. # and sending the `auth` value from the `credentials` variable as an HTTP Authorization header.
:3000 { :3000 {
route { route {
vars token "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vcHJvdmlkZXIuZXhhbXBsZS50ZXN0OjgwMDAvIiwic3ViIjoiODJjMWMzMzRkY2M2ZTMxMWFlNGFhZWJmZTk0NmM1ZTg1OGYwNTVhZmYxY2U1YTM3YWE3Y2M5MWFhYjE3ZTM1YyIsImF1ZCI6Im1haWxzZXJ2ZXIiLCJ1aWQiOiI4OU4zR0NuN1M1Y090WkZNRTVBeVhNbmxURFdVcnEzRmd4YWlyWWhFIn0.zuCytArbphhJn9XT_y9cBdGqDCNo68tBrtOwPIsuKNyF340SaOuZa0xarZofygytdDpLtYr56QlPTKImi-n1ZWrHkRZkwrQi5jQ-j_n2hEAL0vUToLbDnXYfc5q2w7z7X0aoCmiK8-fV7Kx4CVTM7riBgpElf6F3wNAIcX6R1ijUh6ISCL0XYsdogf8WUNZipXY-O4R7YHXdOENuOp3G48hWhxuUh9PsUqE5yxDwLsOVzCTqg9S5gxPQzF2eCN9J0I2XiIlLKvLQPIZ2Y_K7iYvVwjpNdgb4xhm9wuKoIVinYkF_6CwIzAawBWIDJAbix1IslkUPQMGbupTDtOgTiQ" vars token "DMS_YWNjZXNzX3Rva2Vu"
vars user "user1@localhost.localdomain" vars user "user1@localhost.localdomain"
vars credentials "user={vars.user}\001auth=Bearer {vars.token}\001\001" vars credentials "user={vars.user}\001auth=Bearer {vars.token}\001\001"
} }

View File

@ -1,4 +1,4 @@
a0 NOOP See test/config/oauth2/provider.py to generate the below XOAUTH2 string a0 NOOP See test/config/oauth2/Caddyfile to generate the below XOAUTH2 string
a1 AUTHENTICATE XOAUTH2 dXNlcj11c2VyMUBsb2NhbGhvc3QubG9jYWxkb21haW4BYXV0aD1CZWFyZXIgZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKb2RIUndPaTh2Y0hKdmRtbGtaWEl1WlhoaGJYQnNaUzUwWlhOME9qZ3dNREF2SWl3aWMzVmlJam9pT0RKak1XTXpNelJrWTJNMlpUTXhNV0ZsTkdGaFpXSm1aVGswTm1NMVpUZzFPR1l3TlRWaFptWXhZMlUxWVRNM1lXRTNZMk01TVdGaFlqRTNaVE0xWXlJc0ltRjFaQ0k2SW0xaGFXeHpaWEoyWlhJaUxDSjFhV1FpT2lJNE9VNHpSME51TjFNMVkwOTBXa1pOUlRWQmVWaE5ibXhVUkZkVmNuRXpSbWQ0WVdseVdXaEZJbjAuenVDeXRBcmJwaGhKbjlYVF95OWNCZEdxRENObzY4dEJydE93UElzdUtOeUYzNDBTYU91WmEweGFyWm9meWd5dGREcEx0WXI1NlFsUFRLSW1pLW4xWldySGtSWmt3clFpNWpRLWpfbjJoRUFMMHZVVG9MYkRuWFlmYzVxMnc3ejdYMGFvQ21pSzgtZlY3S3g0Q1ZUTTdyaUJncEVsZjZGM3dOQUljWDZSMWlqVWg2SVNDTDBYWXNkb2dmOFdVTlppcFhZLU80UjdZSFhkT0VOdU9wM0c0OGhXaHh1VWg5UHNVcUU1eXhEd0xzT1Z6Q1RxZzlTNWd4UFF6RjJlQ045SjBJMlhpSWxMS3ZMUVBJWjJZX0s3aVl2VndqcE5kZ2I0eGhtOXd1S29JVmluWWtGXzZDd0l6QWF3QldJREpBYml4MUlzbGtVUFFNR2J1cFREdE9nVGlRAQE= a1 AUTHENTICATE XOAUTH2 dXNlcj11c2VyMUBsb2NhbGhvc3QubG9jYWxkb21haW4BYXV0aD1CZWFyZXIgRE1TX1lXTmpaWE56WDNSdmEyVnUBAQ==
a2 EXAMINE INBOX a2 EXAMINE INBOX
a3 LOGOUT a3 LOGOUT

View File

@ -9,7 +9,7 @@ function setup_file() {
export DMS_TEST_NETWORK='test-network-oauth2' export DMS_TEST_NETWORK='test-network-oauth2'
export DMS_DOMAIN='example.test' export DMS_DOMAIN='example.test'
export FQDN_MAIL="mail.${DMS_DOMAIN}" export FQDN_MAIL="mail.${DMS_DOMAIN}"
export FQDN_OAUTH2="oauth2.${DMS_DOMAIN}" export FQDN_OAUTH2="auth.${DMS_DOMAIN}"
# Link the test containers to separate network: # Link the test containers to separate network:
# NOTE: If the network already exists, test will fail to start. # NOTE: If the network already exists, test will fail to start.
@ -31,7 +31,7 @@ function setup_file() {
# Add OAUTH2 configuration so that Dovecot can reach out to our mock provider (CONTAINER2) # Add OAUTH2 configuration so that Dovecot can reach out to our mock provider (CONTAINER2)
local ENV_OAUTH2_CONFIG=( local ENV_OAUTH2_CONFIG=(
--env ENABLE_OAUTH2=1 --env ENABLE_OAUTH2=1
--env OAUTH2_INTROSPECTION_URL=http://oauth2.example.test/userinfo/ --env OAUTH2_INTROSPECTION_URL=http://auth.example.test/userinfo
) )
export CONTAINER_NAME=${CONTAINER1_NAME} export CONTAINER_NAME=${CONTAINER1_NAME}
@ -61,5 +61,9 @@ function teardown_file() {
_run_in_container_bash 'nc -vz 0.0.0.0 143' _run_in_container_bash 'nc -vz 0.0.0.0 143'
_nc_wrapper 'auth/imap-oauth2-auth.txt' '-w 1 0.0.0.0 143' _nc_wrapper 'auth/imap-oauth2-auth.txt' '-w 1 0.0.0.0 143'
assert_output --partial 'Examine completed'
# 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=<user1@localhost.localdomain>, method=XOAUTH2'
} }