OAUTH2 tokeninfo is doing a GET instead of a POST request
Hi,
I try to setup oauth2 authentication with dovecot 2.3.21.
The debug log of dovecot shows that it tries to do a HTTP GET request to the tokeninfo url with the token appended to the end of the URL. This gives a 404 error. The openidconnect server I use (keycloak) tells that this API endpoint conforms to https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint which specifies that the request has to be a HTTP POST request.
So dovecot is trying do to something (GET request) which the OIDC specification does not agree with (shall be POST request).
Here is the dovecot debug log of it: ---snip--- Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: http-client[1]: request [Req1: GET https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/tokeneyJhbGci<rest_omitted>...: Submitted (requests left=1) [...] Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1001, ret=1: SSLv3/TLS read server session ticket Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: where=0x1002, ret=1: SSL negotiation finished successfully Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1001, ret=1: SSL negotiation finished successfully Oct 17 12:11:19 imap syslogd: last message repeated 1 times Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1001, ret=1: SSLv3/TLS read server session ticket Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1002, ret=1: SSL negotiation finished successfully Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: http-client: conn <IP>:443 [1]: Got 404 response for request [Req1: GET https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/tokeneyJhbGci<rest_omitted> ---snip---
My passdb config (only showing the oauth part): ---snip--- passdb { driver = oauth2 mechanisms = oauthbearer xoauth2 args = /usr/local/etc/dovecot/auth-oauth2.token.conf.ext }
passdb { driver = oauth2 mechanisms = plain args = /usr/local/etc/dovecot/auth-oauth2.plain.conf.ext } ---snip---
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = post active_attribute = active active_value = true client_id = myid client_secret = mysecret use_grant_password = no debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = post active_attribute = active active_value = true client_id = myid client_secret = mysecret use_grant_password = yes debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
On https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I can not find any way to tell that the tokeninfo url shall do a POST request instead of a GET request.
I found something on reddit how to make it work with keycloak, but this seems to be a workaround, and not a proper fix... The first comment at https://www.reddit.com/r/selfhosted/comments/omwb2j/any_one_get_dovecot_keyc... makes this work for me.
The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
Bye, Alexander.
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
Also if you are using jwt, you can also opt to do local validation instead.
Aki
On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Hi,
I try to setup oauth2 authentication with dovecot 2.3.21.
The debug log of dovecot shows that it tries to do a HTTP GET request to the tokeninfo url with the token appended to the end of the URL. This gives a 404 error. The openidconnect server I use (keycloak) tells that this API endpoint conforms to https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint which specifies that the request has to be a HTTP POST request.
So dovecot is trying do to something (GET request) which the OIDC specification does not agree with (shall be POST request).
Here is the dovecot debug log of it: ---snip--- Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: http-client[1]: request [Req1: GET https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/tokeneyJhbGci<rest_omitted>...: Submitted (requests left=1) [...] Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1001, ret=1: SSLv3/TLS read server session ticket Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: where=0x1002, ret=1: SSL negotiation finished successfully Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1001, ret=1: SSL negotiation finished successfully Oct 17 12:11:19 imap syslogd: last message repeated 1 times Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1001, ret=1: SSLv3/TLS read server session ticket Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: oauth2.domain.tld: SSL: where=0x1002, ret=1: SSL negotiation finished successfully Oct 17 12:11:19 imap dovecot[81589]: auth: Debug: http-client: conn <IP>:443 [1]: Got 404 response for request [Req1: GET https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/tokeneyJhbGci<rest_omitted> ---snip---
My passdb config (only showing the oauth part): ---snip--- passdb { driver = oauth2 mechanisms = oauthbearer xoauth2 args = /usr/local/etc/dovecot/auth-oauth2.token.conf.ext }
passdb { driver = oauth2 mechanisms = plain args = /usr/local/etc/dovecot/auth-oauth2.plain.conf.ext } ---snip---
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = post active_attribute = active active_value = true client_id = myid client_secret = mysecret use_grant_password = no debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = post active_attribute = active active_value = true client_id = myid client_secret = mysecret use_grant_password = yes debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
On https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I can not find any way to tell that the tokeninfo url shall do a POST request instead of a GET request.
I found something on reddit how to make it work with keycloak, but this seems to be a workaround, and not a proper fix... The first comment at https://www.reddit.com/r/selfhosted/comments/omwb2j/any_one_get_dovecot_keyc... makes this work for me.
The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
Bye, Alexander.
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
Am 2023-10-23 08:43, schrieb Aki Tuomi:
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
If I comment out the tokeninfo_url (the rest the same as in the qorking config below in the quote), I get the error message "oauth2 failed: Introspection failed: No username returned" from dovecot.
Also if you are using jwt, you can also opt to do local validation instead.
How should a config look like for this? From https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I'm not sure what to do.
Would it be:
- introspection_mode = local
- local_validation_key_dict = ...
- switching the oidc provider to jwt
- downloading the cert from the oidc server and putting it into the key-dict ?
Do I still need the openid_configureation_url and introspection_url? client_secret can go in this case I assume.
Bye, Alexander.
Aki
On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote: [...] The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
On 24/10/2023 15:49 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-23 08:43, schrieb Aki Tuomi:
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
If I comment out the tokeninfo_url (the rest the same as in the qorking config below in the quote), I get the error message "oauth2 failed: Introspection failed: No username returned" from dovecot.
Also if you are using jwt, you can also opt to do local validation instead.
How should a config look like for this? From https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I'm not sure what to do.
Would it be:
- introspection_mode = local
- local_validation_key_dict = ...
- switching the oidc provider to jwt
- downloading the cert from the oidc server and putting it into the key-dict ?
Yep. As in the example in docs.
Do I still need the openid_configureation_url and introspection_url? client_secret can go in this case I assume.
You should probably leave client_id there. But you do not need the rest. openid_configuration_url is presented to clients as oidc discovery url.
Aki
Bye, Alexander.
Aki
On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote: [...] The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
Am 2023-10-24 15:14, schrieb Aki Tuomi:
On 24/10/2023 15:49 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-23 08:43, schrieb Aki Tuomi:
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
If I comment out the tokeninfo_url (the rest the same as in the qorking config below in the quote), I get the error message "oauth2 failed: Introspection failed: No username returned" from dovecot.
Also if you are using jwt, you can also opt to do local validation instead.
How should a config look like for this? From https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I'm not sure what to do.
Would it be:
- introspection_mode = local
- local_validation_key_dict = ...
- switching the oidc provider to jwt
- downloading the cert from the oidc server and putting it into the key-dict ?
Yep. As in the example in docs.
Doesn't work. Not even a trace in the debug log. The webmail package (roundcube) didn't finish the sasl auth: ---snip--- imap-login: Disconnected: Connection closed (client didn't finish SASL auth, waited 6 secs): user=<...@...>, method=XOAUTH2,... ---snip---
In the example there is "typ":"JWT" which I don't have: ---snip--- "keys": [ { "kid": "4ED...more...vi7umzYdS4", "kty": "RSA", "alg": "RS256", "use": "sig", "n": "pj0BLB...more...Q", "e": "AQAB", "x5c": [ "MIICoTCCA...much_more...o8M0a6VE=" ], "x5t": "yeW...more...z2mnh4", "x5t#S256": "f37pijf...more...VIF5FHMlYHbBn0" }, ---snip---
The above is from the "jwks_uri" endpoint as per the .well-known/openid-configuration. There is no other URL which lists "kid"s.
I created the /path/to/keys/RS256/4ED...more...vi7umzYdS4 with the content MIICoTCCA...much_more...o8M0a6VE= owned and accessible by the dovecot user.
There is a second key with: ---snip--- "alg": "RSA-OAEP", "use": "enc", ---snip--- As this is not listed as supported, I didn't create an entry in the dict for this.
Bye, Alexander.
Do I still need the openid_configureation_url and introspection_url? client_secret can go in this case I assume.
You should probably leave client_id there. But you do not need the rest. openid_configuration_url is presented to clients as oidc discovery url.
Aki
Bye, Alexander.
Aki
On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote: [...] The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
On 24/10/2023 17:25 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-24 15:14, schrieb Aki Tuomi:
On 24/10/2023 15:49 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-23 08:43, schrieb Aki Tuomi:
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
If I comment out the tokeninfo_url (the rest the same as in the qorking config below in the quote), I get the error message "oauth2 failed: Introspection failed: No username returned" from dovecot.
Also if you are using jwt, you can also opt to do local validation instead.
How should a config look like for this? From https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I'm not sure what to do.
Would it be:
- introspection_mode = local
- local_validation_key_dict = ...
- switching the oidc provider to jwt
- downloading the cert from the oidc server and putting it into the key-dict ?
Yep. As in the example in docs.
Doesn't work. Not even a trace in the debug log. The webmail package (roundcube) didn't finish the sasl auth: ---snip--- imap-login: Disconnected: Connection closed (client didn't finish SASL auth, waited 6 secs): user=<...@...>, method=XOAUTH2,... ---snip---
In the example there is "typ":"JWT" which I don't have: ---snip--- "keys": [ { "kid": "4ED...more...vi7umzYdS4", "kty": "RSA", "alg": "RS256", "use": "sig", "n": "pj0BLB...more...Q", "e": "AQAB", "x5c": [ "MIICoTCCA...much_more...o8M0a6VE=" ], "x5t": "yeW...more...z2mnh4", "x5t#S256": "f37pijf...more...VIF5FHMlYHbBn0" }, ---snip---
The above is from the "jwks_uri" endpoint as per the .well-known/openid-configuration. There is no other URL which lists "kid"s.
I created the /path/to/keys/RS256/4ED...more...vi7umzYdS4 with the content MIICoTCCA...much_more...o8M0a6VE= owned and accessible by the dovecot user.
There is a second key with: ---snip--- "alg": "RSA-OAEP", "use": "enc", ---snip--- As this is not listed as supported, I didn't create an entry in the dict for this.
Bye, Alexander.
Do I still need the openid_configureation_url and introspection_url? client_secret can go in this case I assume.
You should probably leave client_id there. But you do not need the rest. openid_configuration_url is presented to clients as oidc discovery url.
Aki
Bye, Alexander.
Aki
On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote: [...] The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
You sure there is nothing with auth_debug=yes? This sounds like the client did not want to even try oauth2. Did you enable XOAUTH2 and OAUTHBEARER mechanisms?
Aki
Am 2023-10-25 08:03, schrieb Aki Tuomi:
On 24/10/2023 17:25 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-24 15:14, schrieb Aki Tuomi:
On 24/10/2023 15:49 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-23 08:43, schrieb Aki Tuomi:
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
If I comment out the tokeninfo_url (the rest the same as in the qorking config below in the quote), I get the error message "oauth2 failed: Introspection failed: No username returned" from dovecot.
Also if you are using jwt, you can also opt to do local validation instead.
How should a config look like for this? From https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I'm not sure what to do.
Would it be:
- introspection_mode = local
- local_validation_key_dict = ...
- switching the oidc provider to jwt
- downloading the cert from the oidc server and putting it into the key-dict ?
Yep. As in the example in docs.
Doesn't work. Not even a trace in the debug log. The webmail package (roundcube) didn't finish the sasl auth: ---snip--- imap-login: Disconnected: Connection closed (client didn't finish SASL auth, waited 6 secs): user=<...@...>, method=XOAUTH2,... ---snip---
In the example there is "typ":"JWT" which I don't have: ---snip--- "keys": [ { "kid": "4ED...more...vi7umzYdS4", "kty": "RSA", "alg": "RS256", "use": "sig", "n": "pj0BLB...more...Q", "e": "AQAB", "x5c": [ "MIICoTCCA...much_more...o8M0a6VE=" ], "x5t": "yeW...more...z2mnh4", "x5t#S256": "f37pijf...more...VIF5FHMlYHbBn0" }, ---snip---
The above is from the "jwks_uri" endpoint as per the .well-known/openid-configuration. There is no other URL which lists "kid"s.
I created the /path/to/keys/RS256/4ED...more...vi7umzYdS4 with the content MIICoTCCA...much_more...o8M0a6VE= owned and accessible by the dovecot user.
There is a second key with: ---snip--- "alg": "RSA-OAEP", "use": "enc", ---snip--- As this is not listed as supported, I didn't create an entry in the dict for this.
Bye, Alexander.
Do I still need the openid_configureation_url and introspection_url? client_secret can go in this case I assume.
You should probably leave client_id there. But you do not need the rest. openid_configuration_url is presented to clients as oidc discovery url.
Aki
Bye, Alexander.
Aki
On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote: [...] The working but not really up to the OIDC spec dovecot config is:
auth-oauth2.token.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = no #debug = yes username_attribute = email pass_attrs = pass=%{oauth2:access_token} ---snip---
auth-oauth2.plain.conf.ext: ---snip--- openid_configuration_url = https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration #tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token tokeninfo_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... introspection_url = https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... introspection_mode = auth #active_attribute = active #active_value = true client_id = myid client_secret = mysecret use_grant_password = yes #debug = yes username_attribute = email pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 pass=%{oauth2:access_token} ---snip---
You sure there is nothing with auth_debug=yes? This sounds like the client did not want to even try oauth2. Did you enable XOAUTH2 and OAUTHBEARER mechanisms?
In jwt mode:
==> /var/log/debug.log <== Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: passwd-file(email,IP,<sessionhash>): Finished passdb lookup Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): Performing passdb lookup Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): cache miss Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): Attempting to locally validate token Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): Finished passdb lookup Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: xoauth2(email,IP,<sessionhash>): skipping passdb: mechanism filtered Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: auth(email,IP,<sessionhash>): Auth request finished
==> /var/log/maillog <== Oct 25 14:07:53 imap dovecot[79798]: auth: oauth2(email,IP,<sessionhash>): oauth2 failed: Local validation failed: client_id not found in aud field
Yes, both oauth machanisms are enabled.
This is my first try to use JWT, so far I have successfully used only the client id and secret approach with dovecot, wordpress, docuwiki, roundcube and other software. So I can not rule out I made a mistake in the JWT approach, but keycloak has the "client authenticator" setting "signed JWT" which then tells to generat a private key and cert from the "keys" tab, which I then did. I do not see this key referenced somewhere in https://auth.domain.tld/realms/MyRealm/protocol/openid-connect/certs and the dovecot oauth docs are not very clear to someone who is new to this stuff. I do not think I have to put the private key which I get from keycloak as a jks as a result of the key generation into dovecot (if I have, it is not clear to me what the path would be in dovecot). What it displays on the keys page after generating the key looks like a base64 encoded cert to me (starts with "MII", ands with "="), but I don't know if it corresponds to the public or private part of the cert, and where to put it into dovecot if it is the public part.
What I miss / don't know in dovecot is a way to see/understand what it is doing, e.g.
- fetching the .well-known url
- using X, Y, Z as urls for feature A, B, C
- using file /path/to/keys/A/B/C (found / not found) to do X
- this is the cleartext I try to match with content D, E, F
If I attach the FreeBSD ktrace (like "trace" in Linux) to the existing auth process to at least be able to see which files it tries to open, it seems to be too late to see which files it tries to open, nothing shows up except my static PW file which is a fallback for imap clients which don't use oauth, so it doesn't matter here). I haven't tried to start the entire dovecot stack with ktrace enabled, that would take much more time to wade through than I have for this right now.
Bye, Alexander.
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
On 25/10/2023 16:02 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-25 08:03, schrieb Aki Tuomi:
On 24/10/2023 17:25 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-24 15:14, schrieb Aki Tuomi:
On 24/10/2023 15:49 EEST Alexander Leidinger via dovecot <dovecot@dovecot.org> wrote:
Am 2023-10-23 08:43, schrieb Aki Tuomi:
Don't set tokeninfo url if you require POST query. It's not mandatory to set all endpoints.
If I comment out the tokeninfo_url (the rest the same as in the qorking config below in the quote), I get the error message "oauth2 failed: Introspection failed: No username returned" from dovecot.
Also if you are using jwt, you can also opt to do local validation instead.
How should a config look like for this? From https://doc.dovecot.org/configuration_manual/authentication/oauth2/ I'm not sure what to do.
Would it be:
- introspection_mode = local
- local_validation_key_dict = ...
- switching the oidc provider to jwt
- downloading the cert from the oidc server and putting it into the key-dict ?
Yep. As in the example in docs.
Doesn't work. Not even a trace in the debug log. The webmail package (roundcube) didn't finish the sasl auth: ---snip--- imap-login: Disconnected: Connection closed (client didn't finish SASL auth, waited 6 secs): user=<...@...>, method=XOAUTH2,... ---snip---
In the example there is "typ":"JWT" which I don't have: ---snip--- "keys": [ { "kid": "4ED...more...vi7umzYdS4", "kty": "RSA", "alg": "RS256", "use": "sig", "n": "pj0BLB...more...Q", "e": "AQAB", "x5c": [ "MIICoTCCA...much_more...o8M0a6VE=" ], "x5t": "yeW...more...z2mnh4", "x5t#S256": "f37pijf...more...VIF5FHMlYHbBn0" }, ---snip---
The above is from the "jwks_uri" endpoint as per the .well-known/openid-configuration. There is no other URL which lists "kid"s.
I created the /path/to/keys/RS256/4ED...more...vi7umzYdS4 with the content MIICoTCCA...much_more...o8M0a6VE= owned and accessible by the dovecot user.
There is a second key with: ---snip--- "alg": "RSA-OAEP", "use": "enc", ---snip--- As this is not listed as supported, I didn't create an entry in the dict for this.
Bye, Alexander.
Do I still need the openid_configureation_url and introspection_url? client_secret can go in this case I assume.
You should probably leave client_id there. But you do not need the rest. openid_configuration_url is presented to clients as oidc discovery url.
Aki
Bye, Alexander.
Aki
> On 17/10/2023 16:03 EEST Alexander Leidinger via dovecot > <dovecot@dovecot.org> wrote: [...] > The working but not really up to the OIDC spec dovecot config is: > > auth-oauth2.token.conf.ext: > ---snip--- > openid_configuration_url = > https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration > #tokeninfo_url = > https://oauth2.domain.tld/realms/MyRealm/Leidinger/protocol/openid-connect/t... > tokeninfo_url = > https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... > introspection_url = > https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... > introspection_mode = auth > #active_attribute = active > #active_value = true > client_id = myid > client_secret = mysecret > use_grant_password = no > #debug = yes > username_attribute = email > pass_attrs = pass=%{oauth2:access_token} > ---snip--- > > auth-oauth2.plain.conf.ext: > ---snip--- > openid_configuration_url = > https://oauth2.domain.tld/realms/MyRealm/.well-known/openid-configuration > #tokeninfo_url = > https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token > tokeninfo_url = > https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/userinfo?tr... > introspection_url = > https://oauth2.domain.tld/realms/MyRealm/protocol/openid-connect/token/intro... > introspection_mode = auth > #active_attribute = active > #active_value = true > client_id = myid > client_secret = mysecret > use_grant_password = yes > #debug = yes > username_attribute = email > pass_attrs = host=<IP of webmail> proxy=y proxy_mech=xoauth2 > pass=%{oauth2:access_token} > ---snip---
You sure there is nothing with auth_debug=yes? This sounds like the client did not want to even try oauth2. Did you enable XOAUTH2 and OAUTHBEARER mechanisms?
In jwt mode:
==> /var/log/debug.log <== Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: passwd-file(email,IP,<sessionhash>): Finished passdb lookup Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): Performing passdb lookup Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): cache miss Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): Attempting to locally validate token Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: oauth2(email,IP,<sessionhash>): Finished passdb lookup Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: xoauth2(email,IP,<sessionhash>): skipping passdb: mechanism filtered Oct 25 14:07:53 imap dovecot[79798]: auth: Debug: auth(email,IP,<sessionhash>): Auth request finished
==> /var/log/maillog <== Oct 25 14:07:53 imap dovecot[79798]: auth: oauth2(email,IP,<sessionhash>): oauth2 failed: Local validation failed: client_id not found in aud field
Yes, both oauth machanisms are enabled.
This is my first try to use JWT, so far I have successfully used only the client id and secret approach with dovecot, wordpress, docuwiki, roundcube and other software. So I can not rule out I made a mistake in the JWT approach, but keycloak has the "client authenticator" setting "signed JWT" which then tells to generat a private key and cert from the "keys" tab, which I then did. I do not see this key referenced somewhere in https://auth.domain.tld/realms/MyRealm/protocol/openid-connect/certs and the dovecot oauth docs are not very clear to someone who is new to this stuff. I do not think I have to put the private key which I get from keycloak as a jks as a result of the key generation into dovecot (if I have, it is not clear to me what the path would be in dovecot). What it displays on the keys page after generating the key looks like a base64 encoded cert to me (starts with "MII", ands with "="), but I don't know if it corresponds to the public or private part of the cert, and where to put it into dovecot if it is the public part.
What I miss / don't know in dovecot is a way to see/understand what it is doing, e.g.
- fetching the .well-known url
- using X, Y, Z as urls for feature A, B, C
- using file /path/to/keys/A/B/C (found / not found) to do X
- this is the cleartext I try to match with content D, E, F
If I attach the FreeBSD ktrace (like "trace" in Linux) to the existing auth process to at least be able to see which files it tries to open, it seems to be too late to see which files it tries to open, nothing shows up except my static PW file which is a fallback for imap clients which don't use oauth, so it doesn't matter here). I haven't tried to start the entire dovecot stack with ktrace enabled, that would take much more time to wade through than I have for this right now.
Bye, Alexander.
Seems your issue is
oauth2(email,IP,<sessionhash>): oauth2 failed: Local validation failed: client_id not found in aud field
This is a recently added thing, as oauth2 spec requires to check this. If you are using local validation, you can opt to leave client_id empty and this should go away.
alternatively you can use the client_id that will be present in aud field.
Aki
Am 2023-10-25 20:54, schrieb Aki Tuomi:
Seems your issue is
oauth2(email,IP,<sessionhash>): oauth2 failed: Local validation failed: client_id not found in aud field
This is a recently added thing, as oauth2 spec requires to check this.
If you are using local validation, you can opt to leave client_id empty and this should go away.
Correct guess. This let's mive it a bit further. Two issues: format
- local_validation_key_dict is not respected, it tries to lookup "shared/..." instead of my "/path/to/keys" (configured next to introspection_mode=local as in the docs)
- when I symlink shared to my configured dict location as a quick check, it finds the a file, but then complains about an unknown key
How is the content of shared/.../alg/id supposed to look like? In my case it contains "MII....=".
May I suggest to add a comment about client_id and how the content of the key file to look like to the docs?
Bye, Alexander.
-- http://www.Leidinger.net Alexander@Leidinger.net: PGP 0x8F31830F9F2772BF http://www.FreeBSD.org netchild@FreeBSD.org : PGP 0x8F31830F9F2772BF
participants (2)
-
Aki Tuomi
-
Alexander Leidinger