quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.82k stars 2.69k forks source link

OIDC token introspection fails due to path since 1.7 #11460

Closed sdaschner closed 4 years ago

sdaschner commented 4 years ago

The token introspection of the connected OIDC provider (Google Auth in my example) is not configured/discovered correctly anymore, when switching from 1.6.X to 1.7.X.

The error results in a failed future with Invalid path, which fails in OAuth2API#fetch, since before, the config used config.tokenPath (https://oauth2.googleapis.com/token in my example), and now uses config.introspectionPath (which is null). See OAuth2TokenImpl#refresh.

I've configured Google Auth as follows:

quarkus.oidc.auth-server-url=https://accounts.google.com
quarkus.oidc.application-type=web-app
quarkus.oidc.client-id=...
quarkus.oidc.credentials.client-secret.value=...
quarkus.oidc.authentication.scopes=openid,profile
quarkus.oidc.authentication.redirect-path=/
quarkus.oidc.authentication.force-redirect-https-scheme=true
quarkus.oidc.authentication.extra-params.access_type=offline
quarkus.oidc.authentication.extra-params.prompt=consent
quarkus.oidc.token.refresh-expired=true
...

What was the reasoning for changing the path in the token verification?

sberyozkin commented 4 years ago

Hi @sdaschner

I think what I said here explains this regression. If you add quarkus.oidc.authentication.verify-access-token=false to your original configuration then it will work. Let me summarize again what this property is about in the code flow process:

  1. ID and access tokens are fetched once the code flow is completed.
  2. Both of these tokens are kept in the session cookie
  3. ID token is the primary token which we verify on every user request, we get the roles from it, etc.
  4. Access token is not verified on every user request because the expectation is that if it is used then only for the propagation to the downstream services. So with quarkus.oidc.authentication.verify-access-token=true by default, if the access token is opaque/binary, not JWT, or JWT but signed with the JWK which is not available in the local JWK set, then the introspection request will follow which does not work if the discovery doc did not have the introspection path. I'll set this property to false OOB
sdaschner commented 4 years ago

Hi @sberyozkin, thanks for the explanation.

Does this only affect the verification, or also refreshing the access token?

In any way, I was wondering if one prefers keeping the verification, since this worked before, then upgrading to 1.7.0 is a blocker. I'll test with disabling the verification, but I'd require the refresh to work for my use case as well, as it does in 1.6.0...

sberyozkin commented 4 years ago

@sdaschner No, the access token was not verified before 1.7.0.Final, as I said, Quarkus OIDC views ID token as the master/principal token in the code flow, access token is only meant for the propagation by default. Refresh token code should still work.

sberyozkin commented 4 years ago

@sdaschner please see the linked PR. Note both ID and access token verification works in Keycloak with 1.7.0.Final but it looks like with Google (as well as with Azure) what happens is that either 1) AT is binary or 2) AT is JWT but the JWK key is not in the local key set, so in both cases the remote introspection attempt is done as the fallback and since neither Google nor Azure apparently support the OAuth2 introspection endpoint, the failure happens. Hence it is safer to disable this AT verification, it is really the downstream services which would have to verify it.

sberyozkin commented 4 years ago

@sdaschner I've checked Google account well-known config, it does not have an introspection endpoint, therefore it looks like the access token returned by Google is either opaque or signed by key with kid not matching any keys in the fetched JWK set. At this stage the side-effect of verifying the AT has to be fixed. I'd be still interested though to investigate why AT fails to verify. Can you please share the content of the q_session cookie in a working app ? Trim the content of each token there but if it is JWT then leave the 1st part so that I could check the algorithm. You can also try to debug Vertx code and see why its JWT class fails to verify the AT if it is JWT (no matching kid issue)

sdaschner commented 4 years ago

@sberyozkin Thanks for the explanation and the PR!

Setting quarkus.oidc.authentication.verify-access-token=false in 1.7.0.Final results in a NoSuchElementException, but building your PR SNAPSHOT version works for me, including refreshing the token. What's the release date for 1.7.1 (Final or a CR version)?