Skip to content

Commit

Permalink
Merge pull request #43994 from sberyozkin/oidc_token_introspection_ex…
Browse files Browse the repository at this point in the history
…pired_token

Check expiry of the cached OIDC token introspections
  • Loading branch information
sberyozkin authored Oct 21, 2024
2 parents 097092a + eeed776 commit 1b11ce1
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import jakarta.enterprise.event.Observes;

import org.jboss.logging.Logger;

import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.TokenIntrospection;
import io.quarkus.oidc.TokenIntrospectionCache;
import io.quarkus.oidc.UserInfo;
import io.quarkus.oidc.UserInfoCache;
import io.quarkus.oidc.common.runtime.OidcConstants;
import io.quarkus.runtime.ShutdownEvent;
import io.smallrye.mutiny.Uni;
import io.vertx.core.Vertx;
Expand All @@ -23,6 +26,7 @@
* which has been introspected which will be used to request UserInfo.
*/
public class DefaultTokenIntrospectionUserInfoCache implements TokenIntrospectionCache, UserInfoCache {
private static final Logger LOG = Logger.getLogger(DefaultTokenIntrospectionUserInfoCache.class);
private static final Uni<TokenIntrospection> NULL_INTROSPECTION_UNI = Uni.createFrom().nullItem();
private static final Uni<UserInfo> NULL_USERINFO_UNI = Uni.createFrom().nullItem();

Expand Down Expand Up @@ -50,7 +54,22 @@ public Uni<Void> addIntrospection(String token, TokenIntrospection introspection
public Uni<TokenIntrospection> getIntrospection(String token, OidcTenantConfig oidcConfig,
OidcRequestContext<TokenIntrospection> requestContext) {
CacheEntry entry = cache.get(token);
return entry == null ? NULL_INTROSPECTION_UNI : Uni.createFrom().item(entry.introspection);
if (entry == null || entry.introspection == null) {
return NULL_INTROSPECTION_UNI;
}
if (isTokenExpired(entry.introspection.getLong(OidcConstants.INTROSPECTION_TOKEN_EXP), oidcConfig)) {
LOG.debug("Introspected token has expired, removing it from the token introspection cache");
cache.remove(token);
return NULL_INTROSPECTION_UNI;
}

return Uni.createFrom().item(entry.introspection);
}

private static boolean isTokenExpired(Long exp, OidcTenantConfig oidcConfig) {
final long lifespanGrace = oidcConfig != null ? oidcConfig.token.lifespanGrace.orElse(0) : 0;
return exp != null
&& System.currentTimeMillis() / 1000 > (exp + lifespanGrace);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public MemoryCache(Vertx vertx, Optional<Duration> cleanUpTimerInterval,
}

private void init(Vertx vertx, Optional<Duration> cleanUpTimerInterval) {
if (cleanUpTimerInterval.isPresent()) {
if (vertx != null && cleanUpTimerInterval.isPresent()) {
timerId = vertx.setPeriodic(cleanUpTimerInterval.get().toMillis(), new Handler<Long>() {
@Override
public void handle(Long event) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.quarkus.oidc.runtime;

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;

import java.time.Duration;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.Test;

import io.quarkus.oidc.TokenIntrospection;
import io.quarkus.oidc.TokenIntrospectionCache;

public class TokenIntrospectionCacheTest {
TokenIntrospectionCache cache = new DefaultTokenIntrospectionUserInfoCache(createOidcConfig(), null);

@Test
public void testExpiredIntrospection() {

TokenIntrospection introspectionValidFor10secs = new TokenIntrospection(
"{\"active\": true,"
+ "\"exp\":" + (System.currentTimeMillis() / 1000 + 10) + "}");
TokenIntrospection introspectionValidFor3secs = new TokenIntrospection(
"{\"active\": true,"
+ "\"exp\":" + (System.currentTimeMillis() / 1000 + 3) + "}");
cache.addIntrospection("tokenValidFor10secs", introspectionValidFor10secs, null, null);
cache.addIntrospection("tokenValidFor3secs", introspectionValidFor3secs, null, null);

assertNotNull(cache.getIntrospection("tokenValidFor10secs", null, null).await().indefinitely());
assertNotNull(cache.getIntrospection("tokenValidFor3secs", null, null).await().indefinitely());

await().atMost(Duration.ofSeconds(5)).pollInterval(1, TimeUnit.SECONDS)
.until(new Callable<Boolean>() {

@Override
public Boolean call() throws Exception {
return cache.getIntrospection("tokenValidFor3secs", null, null).await().indefinitely() == null;
}

});

assertNotNull(cache.getIntrospection("tokenValidFor10secs", null, null).await().indefinitely());
assertNull(cache.getIntrospection("tokenValidFor3secs", null, null).await().indefinitely());
}

private static OidcConfig createOidcConfig() {
OidcConfig cfg = new OidcConfig();
cfg.tokenCache.maxSize = 2;
return cfg;
}
}

0 comments on commit 1b11ce1

Please sign in to comment.