All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.oidc.runtime.DefaultTokenIntrospectionUserInfoCache Maven / Gradle / Ivy

Go to download

Secure your applications with OpenID Connect Adapter and IDP such as Keycloak

There is a newer version: 3.17.5
Show newest version
package io.quarkus.oidc.runtime;

import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

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.runtime.OidcConfig.TokenCache;
import io.smallrye.mutiny.Uni;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;

/**
 * Default TokenIntrospection and UserInfo Cache implementation.
 * A single cache entry can keep TokenIntrospection and/or UserInfo.
 * 

* In most cases it is the opaque bearer access tokens which are introspected * but the code flow access tokens can also be introspected if they have the roles claims. *

* In either case, if a remote request to fetch UserInfo is required then it will be the same access token * which has been introspected which will be used to request UserInfo. */ public class DefaultTokenIntrospectionUserInfoCache implements TokenIntrospectionCache, UserInfoCache { private static final Uni NULL_INTROSPECTION_UNI = Uni.createFrom().nullItem(); private static final Uni NULL_USERINFO_UNI = Uni.createFrom().nullItem(); private TokenCache cacheConfig; private Map cacheMap; private AtomicInteger size = new AtomicInteger(); public DefaultTokenIntrospectionUserInfoCache(OidcConfig oidcConfig, Vertx vertx) { this.cacheConfig = oidcConfig.tokenCache; init(vertx); } private void init(Vertx vertx) { if (cacheConfig.maxSize > 0) { cacheMap = new ConcurrentHashMap<>(); if (cacheConfig.cleanUpTimerInterval.isPresent()) { vertx.setPeriodic(cacheConfig.cleanUpTimerInterval.get().toMillis(), new Handler() { @Override public void handle(Long event) { // Remove all the entries which have expired removeInvalidEntries(); } }); } } else { cacheMap = Collections.emptyMap(); } } @Override public Uni addIntrospection(String token, TokenIntrospection introspection, OidcTenantConfig oidcTenantConfig, OidcRequestContext requestContext) { if (cacheConfig.maxSize > 0) { CacheEntry entry = findValidCacheEntry(token); if (entry != null) { entry.introspection = introspection; } else if (prepareSpaceForNewCacheEntry()) { cacheMap.put(token, new CacheEntry(introspection)); } } return CodeAuthenticationMechanism.VOID_UNI; } @Override public Uni getIntrospection(String token, OidcTenantConfig oidcConfig, OidcRequestContext requestContext) { CacheEntry entry = findValidCacheEntry(token); return entry == null ? NULL_INTROSPECTION_UNI : Uni.createFrom().item(entry.introspection); } @Override public Uni addUserInfo(String token, UserInfo userInfo, OidcTenantConfig oidcTenantConfig, OidcRequestContext requestContext) { if (cacheConfig.maxSize > 0) { CacheEntry entry = findValidCacheEntry(token); if (entry != null) { entry.userInfo = userInfo; } else if (prepareSpaceForNewCacheEntry()) { cacheMap.put(token, new CacheEntry(userInfo)); } } return CodeAuthenticationMechanism.VOID_UNI; } @Override public Uni getUserInfo(String token, OidcTenantConfig oidcConfig, OidcRequestContext requestContext) { CacheEntry entry = findValidCacheEntry(token); return entry == null ? NULL_USERINFO_UNI : Uni.createFrom().item(entry.userInfo); } public int getCacheSize() { return cacheMap.size(); } public void clearCache() { cacheMap.clear(); size.set(0); } private void removeInvalidEntries() { long now = now(); for (Iterator> it = cacheMap.entrySet().iterator(); it.hasNext();) { Map.Entry next = it.next(); if (isEntryExpired(next.getValue(), now)) { it.remove(); size.decrementAndGet(); } } } private boolean prepareSpaceForNewCacheEntry() { int currentSize; do { currentSize = size.get(); if (currentSize == cacheConfig.maxSize) { return false; } } while (!size.compareAndSet(currentSize, currentSize + 1)); return true; } private CacheEntry findValidCacheEntry(String token) { CacheEntry entry = cacheMap.get(token); if (entry != null) { long now = now(); if (isEntryExpired(entry, now)) { // Entry has expired, remote introspection will be required entry = null; cacheMap.remove(token); size.decrementAndGet(); } } return entry; } private boolean isEntryExpired(CacheEntry entry, long now) { return entry.createdTime + cacheConfig.timeToLive.toMillis() < now; } private static long now() { return System.currentTimeMillis(); } private static class CacheEntry { volatile TokenIntrospection introspection; volatile UserInfo userInfo; long createdTime = System.currentTimeMillis(); public CacheEntry(TokenIntrospection introspection) { this.introspection = introspection; } public CacheEntry(UserInfo userInfo) { this.userInfo = userInfo; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy