You were still describing why the change is safe, instead of focusing on
what could go wrong. I updated the section.
** Description changed:
[ Impact ]
* Local OAuth2 authentication fails if the JWT aud claim is an array.
From RFC7519:
> In the general case, the "aud" value is an array of case-sensitive strings,
> each containing a StringOrURI value. In the special case when the JWT has
> one audience, the "aud" value MAY be a single case-sensitive string
> containing a StringOrURI value.
* Many IdPs (Keycloak, for example) can be configured to send "aud" as an
array if the token is meant for multiple audiences.
* The inability to parse array claims breaks compatibility with compliant
IdPs.
[ Test Plan ]
* On a fresh Ubuntu Noble LXC container, run the following script as
root.
echo initial setup
apt update && apt install -y python3-jwt python3-cryptography openssl
dovecot-core
echo key generation and dictionary setup
mkdir -p /etc/dovecot/keys/default/RS256/
openssl genrsa -out /etc/dovecot/keys/test.pem 2048
openssl rsa -in /etc/dovecot/keys/test.pem -pubout -out
/etc/dovecot/keys/default/RS256/default
find /etc/dovecot/keys -type d -exec chmod 755 {} \;
chmod 644 /etc/dovecot/keys/default/RS256/default
echo writing minimal dovecot configuration:
cat << EOF > /etc/dovecot/dovecot.conf
auth_debug = yes
auth_debug_passwords = yes
auth_mechanisms = xoauth2 oauthbearer plain
passdb {
driver = oauth2
mechanisms = xoauth2 oauthbearer plain
args = /etc/dovecot/dovecot-oauth2.conf.ext
}
userdb {
driver = static
args = uid=1000 gid=1000 home=/tmp/%u
}
EOF
cat << EOF > /etc/dovecot/dovecot-oauth2.conf.ext
introspection_mode = local
client_id = dovecot
local_validation_key_dict = fs:posix:prefix=/etc/dovecot/keys/
username_attribute = sub
EOF
systemctl restart dovecot
echo generating test JWT
cat << EOF > gen-jwt.py
import jwt, time, os
aud = 'dovecot' if 'SINGLE' in os.environ else ['dovecot',
'https://example.com']
with open('/etc/dovecot/keys/test.pem', 'rb') as f:
key = f.read()
payload = {
'iss': 'https://example.com',
'sub': '[email protected]',
'aud': aud,
'exp': int(time.time()) + 3600,
}
print(jwt.encode(payload, key, algorithm='RS256'))
EOF
echo trying to authenticate (single aud)
doveadm auth test [email protected] "$(SINGLE=1 python3 gen-jwt.py)"
echo trying to authenticate (multiple aud)
doveadm auth test [email protected] "$(python3 gen-jwt.py)"
[ Where problems could occur ]
- * This is an upstream change and was already fixed in the release branch for
- 2.3.21.
+ Problems with this change would manifest themselves in the oauth2 code,
+ which is the area touched by this fix, particularly with jwt tokens.
+ These could range from regressions (single aud tokens that were working
+ before now break), to new bugs in handling multiple auds. The test plan
+ covers both scenarios to try to mitigate this.
- * The code also handles the scenario where "aud" is a single string, so
- clients using JWTs with a single "aud" don't break. The test plan above
- demonstrates this.
-
- * Unlikely that this change breaks oauth authentication: the same patch is
- present in the 2.4.X release series and I couldn't find any bugs reported.
[ Other Info ]
* Fixed upstream in 2.4.0 and local JWT validation was introduced in 2.3.11,
so this could only possibly affect Jammy and Noble.
* However, the "aud" field validation was only added in 63e0c9e, which is
only
present in 2.3.21.1.
* When running the test plan above on a Jammy system, authentication
works.
[ Original Bug Description ]
Description: Ubuntu 24.04.1 LTS
Release: 24.04
dovecot-core/noble-updates 1:2.3.21+dfsg1-2ubuntu6.1
On Ubuntu’s Dovecot build, local OAuth2/JWT validation fails if the JWT
aud claim is a JSON array. Dovecot logs:
Local validation failed: client_id set but aud is missing
This happens even though aud is present (as an array):
{ "aud": ["dovecot", "https://checkin.thga.de"], ... }
Upstream Dovecot release-2.3.21 uses an array-aware accessor:
get_field_multiple(tree, "aud")
Source: src/lib-oauth2/oauth2-jwt.c (release-2.3.21 branch)
But Ubuntu appears to be built from code corresponding to the 2.3.21 tag
where it uses:
get_field(tree, "aud")
Source: src/lib-oauth2/oauth2-jwt.c (2.3.21 tag)
With get_field(), aud arrays are not handled, so aud is treated as
missing.
** Description changed:
[ Impact ]
* Local OAuth2 authentication fails if the JWT aud claim is an array.
From RFC7519:
> In the general case, the "aud" value is an array of case-sensitive strings,
> each containing a StringOrURI value. In the special case when the JWT has
> one audience, the "aud" value MAY be a single case-sensitive string
> containing a StringOrURI value.
* Many IdPs (Keycloak, for example) can be configured to send "aud" as an
array if the token is meant for multiple audiences.
* The inability to parse array claims breaks compatibility with compliant
IdPs.
[ Test Plan ]
* On a fresh Ubuntu Noble LXC container, run the following script as
root.
echo initial setup
apt update && apt install -y python3-jwt python3-cryptography openssl
dovecot-core
echo key generation and dictionary setup
mkdir -p /etc/dovecot/keys/default/RS256/
openssl genrsa -out /etc/dovecot/keys/test.pem 2048
openssl rsa -in /etc/dovecot/keys/test.pem -pubout -out
/etc/dovecot/keys/default/RS256/default
find /etc/dovecot/keys -type d -exec chmod 755 {} \;
chmod 644 /etc/dovecot/keys/default/RS256/default
echo writing minimal dovecot configuration:
cat << EOF > /etc/dovecot/dovecot.conf
auth_debug = yes
auth_debug_passwords = yes
auth_mechanisms = xoauth2 oauthbearer plain
passdb {
driver = oauth2
mechanisms = xoauth2 oauthbearer plain
args = /etc/dovecot/dovecot-oauth2.conf.ext
}
userdb {
driver = static
args = uid=1000 gid=1000 home=/tmp/%u
}
EOF
cat << EOF > /etc/dovecot/dovecot-oauth2.conf.ext
introspection_mode = local
client_id = dovecot
local_validation_key_dict = fs:posix:prefix=/etc/dovecot/keys/
username_attribute = sub
EOF
systemctl restart dovecot
echo generating test JWT
cat << EOF > gen-jwt.py
import jwt, time, os
aud = 'dovecot' if 'SINGLE' in os.environ else ['dovecot',
'https://example.com']
with open('/etc/dovecot/keys/test.pem', 'rb') as f:
key = f.read()
payload = {
'iss': 'https://example.com',
'sub': '[email protected]',
'aud': aud,
'exp': int(time.time()) + 3600,
}
print(jwt.encode(payload, key, algorithm='RS256'))
EOF
echo trying to authenticate (single aud)
doveadm auth test [email protected] "$(SINGLE=1 python3 gen-jwt.py)"
echo trying to authenticate (multiple aud)
doveadm auth test [email protected] "$(python3 gen-jwt.py)"
[ Where problems could occur ]
Problems with this change would manifest themselves in the oauth2 code,
which is the area touched by this fix, particularly with jwt tokens.
These could range from regressions (single aud tokens that were working
before now break), to new bugs in handling multiple auds. The test plan
- covers both scenarios to try to mitigate this.
-
+ covers both scenarios to try to mitigate this. Other authentication
+ mechanisms should remain unchanged.
[ Other Info ]
* Fixed upstream in 2.4.0 and local JWT validation was introduced in 2.3.11,
so this could only possibly affect Jammy and Noble.
* However, the "aud" field validation was only added in 63e0c9e, which is
only
present in 2.3.21.1.
* When running the test plan above on a Jammy system, authentication
works.
[ Original Bug Description ]
Description: Ubuntu 24.04.1 LTS
Release: 24.04
dovecot-core/noble-updates 1:2.3.21+dfsg1-2ubuntu6.1
On Ubuntu’s Dovecot build, local OAuth2/JWT validation fails if the JWT
aud claim is a JSON array. Dovecot logs:
Local validation failed: client_id set but aud is missing
This happens even though aud is present (as an array):
{ "aud": ["dovecot", "https://checkin.thga.de"], ... }
Upstream Dovecot release-2.3.21 uses an array-aware accessor:
get_field_multiple(tree, "aud")
Source: src/lib-oauth2/oauth2-jwt.c (release-2.3.21 branch)
But Ubuntu appears to be built from code corresponding to the 2.3.21 tag
where it uses:
get_field(tree, "aud")
Source: src/lib-oauth2/oauth2-jwt.c (2.3.21 tag)
With get_field(), aud arrays are not handled, so aud is treated as
missing.
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2142200
Title:
dovecot-core: OAuth2 JWT validation fails with client_id set but aud
is missing when aud claim is an array
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/dovecot/+bug/2142200/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs