From e2cb17cf9ca1d5c05ec2786f41b796e18e823544 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Fri, 16 Jun 2023 18:03:21 +0100 Subject: [PATCH] Avoid calling OIDC UserInfo endpoint if UserInfo is cached --- .../oidc/runtime/OidcIdentityProvider.java | 22 +++++++++++++------ .../it/keycloak/CodeFlowUserInfoResource.java | 4 +--- .../keycloak/CodeFlowAuthorizationTest.java | 13 ++++++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java index 2202a7cc74ae4..5d61792865d2c 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcIdentityProvider.java @@ -447,7 +447,7 @@ private Uni refreshJwksAndVerifyTokenUni(TenantConfigCo .recoverWithUni(f -> introspectTokenUni(resolvedContext, token)); } - private Uni introspectTokenUni(TenantConfigContext resolvedContext, String token) { + private Uni introspectTokenUni(TenantConfigContext resolvedContext, final String token) { TokenIntrospectionCache tokenIntrospectionCache = tenantResolver.getTokenIntrospectionCache(); Uni tokenIntrospectionUni = tokenIntrospectionCache == null ? null : tokenIntrospectionCache @@ -456,7 +456,12 @@ private Uni introspectTokenUni(TenantConfigContext reso tokenIntrospectionUni = newTokenIntrospectionUni(resolvedContext, token); } else { tokenIntrospectionUni = tokenIntrospectionUni.onItem().ifNull() - .switchTo(newTokenIntrospectionUni(resolvedContext, token)); + .switchTo(new Supplier>() { + @Override + public Uni get() { + return newTokenIntrospectionUni(resolvedContext, token); + } + }); } return tokenIntrospectionUni.onItem().transform(t -> new TokenVerificationResult(null, t)); } @@ -501,10 +506,8 @@ private Uni getUserInfoUni(RoutingContext vertxContext, TokenAuthentic } LOG.debug("Requesting UserInfo"); - String accessToken = vertxContext.get(OidcConstants.ACCESS_TOKEN_VALUE); - if (accessToken == null) { - accessToken = request.getToken().getToken(); - } + String contextAccessToken = vertxContext.get(OidcConstants.ACCESS_TOKEN_VALUE); + final String accessToken = contextAccessToken != null ? contextAccessToken : request.getToken().getToken(); UserInfoCache userInfoCache = tenantResolver.getUserInfoCache(); Uni userInfoUni = userInfoCache == null ? null @@ -513,7 +516,12 @@ private Uni getUserInfoUni(RoutingContext vertxContext, TokenAuthentic userInfoUni = newUserInfoUni(resolvedContext, accessToken); } else { userInfoUni = userInfoUni.onItem().ifNull() - .switchTo(newUserInfoUni(resolvedContext, accessToken)); + .switchTo(new Supplier>() { + @Override + public Uni get() { + return newUserInfoUni(resolvedContext, accessToken); + } + }); } return userInfoUni; } diff --git a/integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/CodeFlowUserInfoResource.java b/integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/CodeFlowUserInfoResource.java index a653e097e346f..ddc772b6febea 100644 --- a/integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/CodeFlowUserInfoResource.java +++ b/integration-tests/oidc-wiremock/src/main/java/io/quarkus/it/keycloak/CodeFlowUserInfoResource.java @@ -31,11 +31,9 @@ public class CodeFlowUserInfoResource { @GET @Path("/code-flow-user-info-only") public String access() { - int cacheSize = tokenCache.getCacheSize(); - tokenCache.clearCache(); return identity.getPrincipal().getName() + ":" + userInfo.getPreferredUserName() + ":" + accessToken.getName() + ", cache size: " - + cacheSize; + + tokenCache.getCacheSize(); } @GET diff --git a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java index 0a3536eeb0db0..2fd589694bcf7 100644 --- a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java +++ b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java @@ -3,8 +3,10 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.containing; import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.matching; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -214,9 +216,11 @@ public void testCodeFlowUserInfo() throws Exception { defineCodeFlowAuthorizationOauth2TokenStub(); doTestCodeFlowUserInfo("code-flow-user-info-only", 300); + clearCache(); doTestCodeFlowUserInfo("code-flow-user-info-github", 360); + clearCache(); doTestCodeFlowUserInfo("code-flow-user-info-dynamic-github", 301); - + clearCache(); doTestCodeFlowUserInfoCashedInIdToken(); } @@ -256,6 +260,13 @@ private void doTestCodeFlowUserInfo(String tenantId, long internalIdTokenLifetim page = form.getInputByValue("login").click(); assertEquals("alice:alice:alice, cache size: 1", page.getBody().asNormalizedText()); + page = webClient.getPage("http://localhost:8081/" + tenantId); + assertEquals("alice:alice:alice, cache size: 1", page.getBody().asNormalizedText()); + page = webClient.getPage("http://localhost:8081/" + tenantId); + assertEquals("alice:alice:alice, cache size: 1", page.getBody().asNormalizedText()); + + wireMockServer.verify(1, getRequestedFor(urlPathMatching("/auth/realms/quarkus/protocol/openid-connect/userinfo"))); + wireMockServer.resetRequests(); JsonObject idTokenClaims = decryptIdToken(webClient, tenantId); assertNull(idTokenClaims.getJsonObject(OidcUtils.USER_INFO_ATTRIBUTE));