From b81f6524cfd139aeed19760cfafd483cd6851f18 Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Wed, 17 Aug 2022 14:55:47 +0100 Subject: [PATCH] Fix OidcSession#expiresIn and add a new method --- .../java/io/quarkus/oidc/OidcSession.java | 22 ++++++++++++++++++- .../quarkus/oidc/runtime/OidcSessionImpl.java | 13 ++++++++++- .../io/quarkus/it/keycloak/TenantHttps.java | 3 ++- .../io/quarkus/it/keycloak/CodeFlowTest.java | 13 +++++++++-- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcSession.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcSession.java index 66fe190fa95ba..941a368e28a5b 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcSession.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcSession.java @@ -1,5 +1,6 @@ package io.quarkus.oidc; +import java.time.Duration; import java.time.Instant; import org.eclipse.microprofile.jwt.JsonWebToken; @@ -18,10 +19,29 @@ public interface OidcSession { /** * Return an {@linkplain:Instant} indicating how long will it take for the current session to expire. * - * @return + * @deprecated This method shouldn't be used as it provides an instant corresponding to 1970-01-01T0:0:0Z plus the duration of the validity of the token, which is impractical. Please use either {@link #expiresAt()} or {@link #validFor()} depending on your requirements. This method will be removed in a later version of Quarkus. + * + * @return Instant */ + @Deprecated(forRemoval = true, since = "2.12.0") Instant expiresIn(); + /** + * Return an {@linkplain Instant} representing the current session's expiration time + * which is a number of seconds from the epoch of 1970-01-01T0:0:0Z. + * + * @return Instant + */ + Instant expiresAt(); + + /** + * Return a {@linkplain Duration} indicating how long the current session will remain valid for + * starting from this method's invocation time. + * + * @return Duration + */ + Duration validFor(); + /** * Perform a local logout without a redirect to the OpenId Connect provider. * diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcSessionImpl.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcSessionImpl.java index 80f897682aa82..af5e1e6b9a488 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcSessionImpl.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcSessionImpl.java @@ -1,5 +1,6 @@ package io.quarkus.oidc.runtime; +import java.time.Duration; import java.time.Instant; import java.util.function.Function; @@ -56,9 +57,19 @@ public Instant expiresIn() { return Instant.ofEpochSecond(idToken.getExpirationTime() - nowSecs); } + @Override + public Instant expiresAt() { + return Instant.ofEpochSecond(idToken.getExpirationTime()); + } + + @Override + public Duration validFor() { + final long nowSecs = System.currentTimeMillis() / 1000; + return Duration.ofSeconds(idToken.getExpirationTime() - nowSecs); + } + @Override public JsonWebToken getIdToken() { return idToken; } - } diff --git a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/TenantHttps.java b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/TenantHttps.java index bca5b831aed75..4f752143d3e92 100644 --- a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/TenantHttps.java +++ b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/TenantHttps.java @@ -27,7 +27,8 @@ public String getTenant() { @Path("query") @Authenticated public String getTenantWithQuery(@QueryParam("code") String value) { - return getTenant() + "?code=" + value; + return getTenant() + "?code=" + value + "&expiresAt=" + session.expiresAt().getEpochSecond() + + "&expiresInDuration=" + session.validFor().getSeconds(); } @GET diff --git a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java index 4c7b5516cd835..c1571712c6937 100644 --- a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java +++ b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java @@ -33,6 +33,7 @@ import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.smallrye.jwt.util.KeyUtils; +import io.vertx.core.json.JsonObject; /** * @author Pedro Igor @@ -256,10 +257,18 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception URI endpointLocationWithoutQueryUri = URI.create(endpointLocationWithoutQuery); assertEquals("code=b", endpointLocationWithoutQueryUri.getRawQuery()); - page = webClient.getPage(endpointLocationWithoutQueryUri.toURL()); - assertEquals("tenant-https:reauthenticated?code=b", page.getBody().asText()); Cookie sessionCookie = getSessionCookie(webClient, "tenant-https_test"); assertNotNull(sessionCookie); + JsonObject idToken = OidcUtils.decodeJwtContent(sessionCookie.getValue().split("\\|")[0]); + String expiresAt = idToken.getInteger("exp").toString(); + page = webClient.getPage(endpointLocationWithoutQueryUri.toURL()); + String response = page.getBody().asText(); + assertTrue( + response.startsWith("tenant-https:reauthenticated?code=b&expiresAt=" + expiresAt + "&expiresInDuration=")); + Integer duration = Integer.valueOf(response.substring(response.length() - 1)); + assertTrue(duration > 1 && duration < 5); + sessionCookie = getSessionCookie(webClient, "tenant-https_test"); + assertNotNull(sessionCookie); webClient.getCookieManager().clearCookies(); } }