io.quarkus.oidc.runtime.OidcIdentityProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quarkus-oidc Show documentation
Show all versions of quarkus-oidc Show documentation
Secure your applications with OpenID Connect Adapter and IDP such as Keycloak
package io.quarkus.oidc.runtime;
import static io.quarkus.oidc.runtime.OidcUtils.validateAndCreateIdentity;
import static io.quarkus.vertx.http.runtime.security.HttpSecurityUtils.getRoutingContextAttribute;
import java.security.Principal;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.jwt.Claims;
import org.jboss.logging.Logger;
import org.jose4j.lang.UnresolvableKeyException;
import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.oidc.IdTokenCredential;
import io.quarkus.oidc.OIDCException;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.OidcTenantConfig.Roles.Source;
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.security.AuthenticationCompletionException;
import io.quarkus.security.AuthenticationFailedException;
import io.quarkus.security.credential.TokenCredential;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.IdentityProvider;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.request.TokenAuthenticationRequest;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.smallrye.mutiny.Uni;
import io.vertx.core.json.JsonObject;
@ApplicationScoped
public class OidcIdentityProvider implements IdentityProvider {
private static final Logger LOG = Logger.getLogger(OidcIdentityProvider.class);
static final String REFRESH_TOKEN_GRANT_RESPONSE = "refresh_token_grant_response";
static final String NEW_AUTHENTICATION = "new_authentication";
private static final Uni NULL_CODE_ACCESS_TOKEN_UNI = Uni.createFrom().nullItem();
protected final DefaultTenantConfigResolver tenantResolver;
private final BlockingTaskRunner uniVoidOidcContext;
private final BlockingTaskRunner getIntrospectionRequestContext;
private final BlockingTaskRunner getUserInfoRequestContext;
OidcIdentityProvider(DefaultTenantConfigResolver tenantResolver, BlockingSecurityExecutor blockingExecutor) {
this.tenantResolver = tenantResolver;
this.uniVoidOidcContext = new BlockingTaskRunner<>(blockingExecutor);
this.getIntrospectionRequestContext = new BlockingTaskRunner<>(blockingExecutor);
this.getUserInfoRequestContext = new BlockingTaskRunner<>(blockingExecutor);
}
@Override
public Class getRequestType() {
return TokenAuthenticationRequest.class;
}
@Override
public Uni authenticate(TokenAuthenticationRequest request,
AuthenticationRequestContext context) {
if (!(request.getToken() instanceof AccessTokenCredential || request.getToken() instanceof IdTokenCredential)) {
return Uni.createFrom().nullItem();
}
LOG.debug("Starting creating SecurityIdentity");
return resolveTenantConfigContext(request, context).onItem()
.transformToUni(new Function>() {
@Override
public Uni apply(TenantConfigContext tenantConfigContext) {
return Uni.createFrom().deferred(new Supplier>() {
@Override
public Uni get() {
return authenticate(request, getRequestData(request), tenantConfigContext);
}
});
}
});
}
protected Uni resolveTenantConfigContext(TokenAuthenticationRequest request,
AuthenticationRequestContext context) {
return tenantResolver.resolveContext(
getRoutingContextAttribute(request).put(AuthenticationRequestContext.class.getName(), context));
}
protected Map getRequestData(TokenAuthenticationRequest request) {
return getRoutingContextAttribute(request).data();
}
private Uni authenticate(TokenAuthenticationRequest request, Map requestData,
TenantConfigContext resolvedContext) {
if (resolvedContext.oidcConfig.authServerUrl.isPresent()) {
return validateAllTokensWithOidcServer(requestData, request, resolvedContext);
} else if (resolvedContext.oidcConfig.getCertificateChain().trustStoreFile.isPresent()) {
LOG.debug("Performing token verification with a public key inlined in the certificate chain");
return validateTokenWithoutOidcServer(request, resolvedContext);
} else if (resolvedContext.oidcConfig.publicKey.isPresent()) {
LOG.debug("Performing token verification with a configured public key");
return validateTokenWithoutOidcServer(request, resolvedContext);
} else {
return Uni.createFrom().failure(new OIDCException("Unexpected authentication request"));
}
}
private Uni validateAllTokensWithOidcServer(Map requestData,
TokenAuthenticationRequest request, TenantConfigContext resolvedContext) {
if (resolvedContext.oidcConfig.token.verifyAccessTokenWithUserInfo.orElse(false)
&& isOpaqueAccessToken(requestData, request, resolvedContext)) {
// UserInfo has to be acquired first as a precondition for verifying opaque access tokens.
// Typically it will be done for bearer access tokens therefore even if the access token has expired
// the client will be able to refresh if needed, no refresh token is available to Quarkus during the
// bearer access token verification
if (resolvedContext.oidcConfig.authentication.isUserInfoRequired().orElse(false)) {
return getUserInfoUni(requestData, request, resolvedContext).onItemOrFailure().transformToUni(
new BiFunction>() {
@Override
public Uni apply(UserInfo userInfo, Throwable t) {
if (t != null) {
return Uni.createFrom().failure(new AuthenticationFailedException(t));
}
return validateTokenWithUserInfoAndCreateIdentity(requestData, request, resolvedContext,
userInfo);
}
});
} else {
return validateTokenWithUserInfoAndCreateIdentity(requestData, request, resolvedContext, null);
}
} else {
final Uni primaryTokenUni;
if (isInternalIdToken(request)) {
if (requestData.get(NEW_AUTHENTICATION) == Boolean.TRUE) {
// No need to verify it in this case as 'CodeAuthenticationMechanism' has just created it
primaryTokenUni = Uni.createFrom()
.item(new TokenVerificationResult(OidcUtils.decodeJwtContent(request.getToken().getToken()), null));
} else {
primaryTokenUni = verifySelfSignedTokenUni(resolvedContext, request.getToken().getToken());
}
} else {
primaryTokenUni = verifyTokenUni(requestData, resolvedContext, request.getToken(),
isIdToken(request), null);
}
return getUserInfoAndCreateIdentity(primaryTokenUni, requestData, request, resolvedContext);
}
}
private Uni validateTokenWithUserInfoAndCreateIdentity(Map requestData,
TokenAuthenticationRequest request,
TenantConfigContext resolvedContext, UserInfo userInfo) {
Uni codeAccessTokenUni = verifyCodeFlowAccessTokenUni(requestData, request, resolvedContext,
userInfo);
return codeAccessTokenUni.onItemOrFailure().transformToUni(
new BiFunction>() {
@Override
public Uni apply(TokenVerificationResult codeAccessToken, Throwable t) {
if (t != null) {
requestData.put(OidcUtils.CODE_ACCESS_TOKEN_FAILURE, t);
return Uni.createFrom().failure(new AuthenticationFailedException(t));
}
if (codeAccessToken != null) {
requestData.put(OidcUtils.CODE_ACCESS_TOKEN_RESULT, codeAccessToken);
}
Uni tokenUni = verifyTokenUni(requestData, resolvedContext,
request.getToken(),
false, userInfo);
return tokenUni.onItemOrFailure()
.transformToUni(
new BiFunction>() {
@Override
public Uni apply(TokenVerificationResult result, Throwable t) {
if (t != null) {
return Uni.createFrom().failure(new AuthenticationFailedException(t));
}
return createSecurityIdentityWithOidcServer(result, requestData, request,
resolvedContext, userInfo);
}
});
}
});
}
private Uni getUserInfoAndCreateIdentity(Uni tokenUni,
Map requestData,
TokenAuthenticationRequest request,
TenantConfigContext resolvedContext) {
return tokenUni.onItemOrFailure()
.transformToUni(new BiFunction>() {
@Override
public Uni apply(TokenVerificationResult result, Throwable t) {
if (t != null) {
return Uni.createFrom().failure(new AuthenticationFailedException(t));
}
Uni codeAccessTokenUni = verifyCodeFlowAccessTokenUni(requestData, request,
resolvedContext,
null);
return codeAccessTokenUni.onItemOrFailure().transformToUni(
new BiFunction>() {
@Override
public Uni apply(TokenVerificationResult codeAccessTokenResult,
Throwable t) {
if (t != null) {
requestData.put(OidcUtils.CODE_ACCESS_TOKEN_FAILURE, t);
return Uni.createFrom().failure(t instanceof AuthenticationFailedException ? t
: new AuthenticationFailedException(t));
}
if (codeAccessTokenResult != null) {
if (tokenAutoRefreshPrepared(codeAccessTokenResult, requestData,
resolvedContext.oidcConfig)) {
return Uni.createFrom().failure(new TokenAutoRefreshException(null));
}
requestData.put(OidcUtils.CODE_ACCESS_TOKEN_RESULT, codeAccessTokenResult);
}
if (resolvedContext.oidcConfig.authentication.isUserInfoRequired().orElse(false)) {
return getUserInfoUni(requestData, request, resolvedContext).onItemOrFailure()
.transformToUni(
new BiFunction>() {
@Override
public Uni apply(UserInfo userInfo,
Throwable t) {
if (t != null) {
return Uni.createFrom()
.failure(new AuthenticationFailedException(t));
}
return createSecurityIdentityWithOidcServer(result,
requestData, request,
resolvedContext, userInfo);
}
});
} else {
return createSecurityIdentityWithOidcServer(result, requestData, request,
resolvedContext, null);
}
}
});
}
});
}
private boolean isOpaqueAccessToken(Map requestData, TokenAuthenticationRequest request,
TenantConfigContext resolvedContext) {
if (request.getToken() instanceof AccessTokenCredential) {
return ((AccessTokenCredential) request.getToken()).isOpaque();
} else if (request.getToken() instanceof IdTokenCredential
&& (resolvedContext.oidcConfig.authentication.verifyAccessToken
|| resolvedContext.oidcConfig.roles.source.orElse(null) == Source.accesstoken)) {
final String codeAccessToken = (String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE);
return OidcUtils.isOpaqueToken(codeAccessToken);
}
return false;
}
private Uni createSecurityIdentityWithOidcServer(TokenVerificationResult result,
Map requestData, TokenAuthenticationRequest request, TenantConfigContext resolvedContext,
final UserInfo userInfo) {
// Token has been verified, as a JWT or an opaque token, possibly involving
// an introspection request.
final TokenCredential tokenCred = request.getToken();
JsonObject tokenJson = result.localVerificationResult;
if (tokenJson == null) {
// JSON token representation may be null not only if it is an opaque access token
// but also if it is JWT and no JWK with a matching kid is available, asynchronous
// JWK refresh has not finished yet, but the fallback introspection request has succeeded.
tokenJson = OidcUtils.decodeJwtContent(tokenCred.getToken());
}
if (tokenJson != null) {
try {
OidcUtils.validatePrimaryJwtTokenType(resolvedContext.oidcConfig.token, tokenJson);
if (userInfo != null && resolvedContext.oidcConfig.token.isSubjectRequired()
&& !tokenJson.getString(Claims.sub.name()).equals(userInfo.getString(Claims.sub.name()))) {
String errorMessage = String
.format("Token and UserInfo do not have matching `sub` claims");
return Uni.createFrom().failure(new AuthenticationCompletionException(errorMessage));
}
JsonObject rolesJson = getRolesJson(requestData, resolvedContext, tokenCred, tokenJson,
userInfo);
SecurityIdentity securityIdentity = validateAndCreateIdentity(requestData, tokenCred,
resolvedContext, tokenJson, rolesJson, userInfo, result.introspectionResult, request);
// If the primary token is a bearer access token then there's no point of checking if
// it should be refreshed as RT is only available for the code flow tokens
if (isIdToken(request)
&& tokenAutoRefreshPrepared(result, requestData, resolvedContext.oidcConfig)) {
return Uni.createFrom().failure(new TokenAutoRefreshException(securityIdentity));
} else {
return Uni.createFrom().item(securityIdentity);
}
} catch (Throwable ex) {
return Uni.createFrom().failure(new AuthenticationFailedException(ex));
}
} else if (isIdToken(request)
|| tokenCred instanceof AccessTokenCredential
&& !((AccessTokenCredential) tokenCred).isOpaque()) {
return Uni.createFrom()
.failure(new AuthenticationFailedException("JWT token can not be converted to JSON"));
} else {
// ID Token or Bearer access token has been introspected or verified via Userinfo acquisition
QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder();
builder.addCredential(tokenCred);
OidcUtils.setSecurityIdentityUserInfo(builder, userInfo);
OidcUtils.setSecurityIdentityConfigMetadata(builder, resolvedContext);
final String userName;
if (result.introspectionResult == null) {
if (resolvedContext.oidcConfig.token.allowOpaqueTokenIntrospection &&
resolvedContext.oidcConfig.token.verifyAccessTokenWithUserInfo.orElse(false)) {
if (resolvedContext.oidcConfig.token.principalClaim.isPresent() && userInfo != null) {
userName = userInfo.getString(resolvedContext.oidcConfig.token.principalClaim.get());
} else {
userName = "";
}
} else {
// we don't expect this to ever happen
LOG.debug("Illegal state - token introspection result is not available.");
return Uni.createFrom().failure(new AuthenticationFailedException());
}
} else {
OidcUtils.setSecurityIdentityIntrospection(builder, result.introspectionResult);
String principalName = result.introspectionResult.getUsername();
if (principalName == null) {
principalName = result.introspectionResult.getSubject();
}
userName = principalName != null ? principalName : "";
Set scopes = result.introspectionResult.getScopes();
if (scopes != null) {
builder.addRoles(scopes);
OidcUtils.addTokenScopesAsPermissions(builder, scopes);
}
}
builder.setPrincipal(new Principal() {
@Override
public String getName() {
return userName != null ? userName : "";
}
});
if (userInfo != null) {
var rolesJson = new JsonObject(userInfo.getJsonObject().toString());
OidcUtils.setSecurityIdentityRoles(builder, resolvedContext.oidcConfig, rolesJson);
OidcUtils.setSecurityIdentityPermissions(builder, resolvedContext.oidcConfig, rolesJson);
}
OidcUtils.setTenantIdAttribute(builder, resolvedContext.oidcConfig);
var vertxContext = getRoutingContextAttribute(request);
OidcUtils.setBlockingApiAttribute(builder, vertxContext);
OidcUtils.setRoutingContextAttribute(builder, vertxContext);
SecurityIdentity identity = builder.build();
// If the primary token is a bearer access token then there's no point of checking if
// it should be refreshed as RT is only available for the code flow tokens
if (isIdToken(request)
&& tokenAutoRefreshPrepared(result, requestData, resolvedContext.oidcConfig)) {
return Uni.createFrom().failure(new TokenAutoRefreshException(identity));
}
return Uni.createFrom().item(identity);
}
}
private static boolean isInternalIdToken(TokenAuthenticationRequest request) {
return isIdToken(request) && ((IdTokenCredential) request.getToken()).isInternal();
}
private static boolean isIdToken(TokenAuthenticationRequest request) {
return request.getToken() instanceof IdTokenCredential;
}
private static boolean tokenAutoRefreshPrepared(TokenVerificationResult result, Map requestData,
OidcTenantConfig oidcConfig) {
if (result != null && oidcConfig.token.refreshExpired
&& oidcConfig.token.getRefreshTokenTimeSkew().isPresent()
&& requestData.get(REFRESH_TOKEN_GRANT_RESPONSE) != Boolean.TRUE
&& requestData.get(NEW_AUTHENTICATION) != Boolean.TRUE) {
Long expiry = null;
if (result.localVerificationResult != null) {
expiry = result.localVerificationResult.getLong(Claims.exp.name());
} else if (result.introspectionResult != null) {
expiry = result.introspectionResult.getLong(OidcConstants.INTROSPECTION_TOKEN_EXP);
}
if (expiry != null) {
final long refreshTokenTimeSkew = oidcConfig.token.getRefreshTokenTimeSkew().get().getSeconds();
final long now = System.currentTimeMillis() / 1000;
return now + refreshTokenTimeSkew > expiry;
}
}
return false;
}
private static JsonObject getRolesJson(Map requestData, TenantConfigContext resolvedContext,
TokenCredential tokenCred,
JsonObject tokenJson, UserInfo userInfo) {
JsonObject rolesJson = tokenJson;
if (resolvedContext.oidcConfig.roles.source.isPresent()) {
if (resolvedContext.oidcConfig.roles.source.get() == Source.userinfo) {
rolesJson = new JsonObject(userInfo.getJsonObject().toString());
} else if (tokenCred instanceof IdTokenCredential
&& resolvedContext.oidcConfig.roles.source.get() == Source.accesstoken) {
rolesJson = ((TokenVerificationResult) requestData
.get(OidcUtils.CODE_ACCESS_TOKEN_RESULT)).localVerificationResult;
if (rolesJson == null) {
// JSON token representation may be null not only if it is an opaque access token
// but also if it is JWT and no JWK with a matching kid is available, asynchronous
// JWK refresh has not finished yet, but the fallback introspection request has succeeded.
rolesJson = OidcUtils.decodeJwtContent((String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE));
}
}
}
return rolesJson;
}
private Uni verifyCodeFlowAccessTokenUni(Map requestData,
TokenAuthenticationRequest request,
TenantConfigContext resolvedContext, UserInfo userInfo) {
if (request.getToken() instanceof IdTokenCredential
&& (resolvedContext.oidcConfig.authentication.verifyAccessToken
|| resolvedContext.oidcConfig.roles.source.orElse(null) == Source.accesstoken)) {
final String codeAccessToken = (String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE);
return verifyTokenUni(requestData, resolvedContext, new AccessTokenCredential(codeAccessToken), false, userInfo);
} else {
return NULL_CODE_ACCESS_TOKEN_UNI;
}
}
private Uni verifyTokenUni(Map requestData, TenantConfigContext resolvedContext,
TokenCredential tokenCred, boolean enforceAudienceVerification, UserInfo userInfo) {
final String token = tokenCred.getToken();
if (OidcUtils.isOpaqueToken(token)) {
if (!resolvedContext.oidcConfig.token.allowOpaqueTokenIntrospection) {
LOG.debug("Token is opaque but the opaque token introspection is not allowed");
throw new AuthenticationFailedException();
}
// verify opaque access token with UserInfo if enabled and introspection URI is absent
if (resolvedContext.oidcConfig.token.verifyAccessTokenWithUserInfo.orElse(false)
&& resolvedContext.provider.getMetadata().getIntrospectionUri() == null) {
if (userInfo == null) {
return Uni.createFrom().failure(
new AuthenticationFailedException("Opaque access token verification failed as user info is null."));
} else {
// valid token verification result
return Uni.createFrom().item(new TokenVerificationResult(null, null));
}
}
LOG.debug("Starting the opaque token introspection");
return introspectTokenUni(resolvedContext, token, false);
} else if (resolvedContext.provider.getMetadata().getJsonWebKeySetUri() == null
|| resolvedContext.oidcConfig.token.requireJwtIntrospectionOnly) {
// Verify JWT token with the remote introspection
LOG.debug("Starting the JWT token introspection");
return introspectTokenUni(resolvedContext, token, false);
} else if (resolvedContext.oidcConfig.jwks.resolveEarly) {
// Verify JWT token with the local JWK keys with a possible remote introspection fallback
final String nonce = (String) requestData.get(OidcConstants.NONCE);
try {
LOG.debug("Verifying the JWT token with the local JWK keys");
return Uni.createFrom()
.item(resolvedContext.provider.verifyJwtToken(token, enforceAudienceVerification,
resolvedContext.oidcConfig.token.isSubjectRequired(), nonce));
} catch (Throwable t) {
if (t.getCause() instanceof UnresolvableKeyException) {
LOG.debug("No matching JWK key is found, refreshing and repeating the verification");
return refreshJwksAndVerifyTokenUni(resolvedContext, token, enforceAudienceVerification,
resolvedContext.oidcConfig.token.isSubjectRequired(), nonce);
} else {
LOG.debugf("Token verification has failed: %s", t.getMessage());
return Uni.createFrom().failure(t);
}
}
} else {
final String nonce = (String) requestData.get(OidcConstants.NONCE);
return resolveJwksAndVerifyTokenUni(resolvedContext, tokenCred, enforceAudienceVerification,
resolvedContext.oidcConfig.token.isSubjectRequired(), nonce);
}
}
private Uni verifySelfSignedTokenUni(TenantConfigContext resolvedContext, String token) {
try {
return Uni.createFrom().item(resolvedContext.provider.verifySelfSignedJwtToken(token));
} catch (Throwable t) {
return Uni.createFrom().failure(t);
}
}
private Uni refreshJwksAndVerifyTokenUni(TenantConfigContext resolvedContext, String token,
boolean enforceAudienceVerification, boolean subjectRequired, String nonce) {
return resolvedContext.provider.refreshJwksAndVerifyJwtToken(token, enforceAudienceVerification, subjectRequired, nonce)
.onFailure(f -> fallbackToIntrospectionIfNoMatchingKey(f, resolvedContext))
.recoverWithUni(f -> introspectTokenUni(resolvedContext, token, true));
}
private Uni resolveJwksAndVerifyTokenUni(TenantConfigContext resolvedContext,
TokenCredential tokenCred,
boolean enforceAudienceVerification, boolean subjectRequired, String nonce) {
return resolvedContext.provider
.getKeyResolverAndVerifyJwtToken(tokenCred, enforceAudienceVerification, subjectRequired, nonce,
(tokenCred instanceof IdTokenCredential))
.onFailure(f -> fallbackToIntrospectionIfNoMatchingKey(f, resolvedContext))
.recoverWithUni(f -> introspectTokenUni(resolvedContext, tokenCred.getToken(), true));
}
private static boolean fallbackToIntrospectionIfNoMatchingKey(Throwable f, TenantConfigContext resolvedContext) {
if (!(f.getCause() instanceof UnresolvableKeyException)) {
LOG.debug("Local JWT token verification has failed, skipping the token introspection");
return false;
} else if (!resolvedContext.oidcConfig.token.allowJwtIntrospection) {
LOG.debug("JWT token does not have a matching verification key but JWT token introspection is disabled");
return false;
} else {
LOG.debug("Local JWT token verification has failed, attempting the token introspection");
return true;
}
}
private Uni introspectTokenUni(TenantConfigContext resolvedContext, final String token,
boolean fallbackFromJwkMatch) {
TokenIntrospectionCache tokenIntrospectionCache = tenantResolver.getTokenIntrospectionCache();
Uni tokenIntrospectionUni = tokenIntrospectionCache == null ? null
: tokenIntrospectionCache
.getIntrospection(token, resolvedContext.oidcConfig, getIntrospectionRequestContext);
if (tokenIntrospectionUni == null) {
tokenIntrospectionUni = newTokenIntrospectionUni(resolvedContext, token, fallbackFromJwkMatch);
} else {
tokenIntrospectionUni = tokenIntrospectionUni.onItem().ifNull()
.switchTo(new Supplier>() {
@Override
public Uni get() {
return newTokenIntrospectionUni(resolvedContext, token, fallbackFromJwkMatch);
}
});
}
return tokenIntrospectionUni.onItem().transform(t -> new TokenVerificationResult(null, t));
}
private Uni newTokenIntrospectionUni(TenantConfigContext resolvedContext, String token,
boolean fallbackFromJwkMatch) {
Uni tokenIntrospectionUni = resolvedContext.provider.introspectToken(token, fallbackFromJwkMatch);
if (tenantResolver.getTokenIntrospectionCache() == null || !resolvedContext.oidcConfig.allowTokenIntrospectionCache) {
return tokenIntrospectionUni;
} else {
return tokenIntrospectionUni.call(new Function>() {
@Override
public Uni> apply(TokenIntrospection introspection) {
return tenantResolver.getTokenIntrospectionCache().addIntrospection(token, introspection,
resolvedContext.oidcConfig, uniVoidOidcContext);
}
});
}
}
private static Uni validateTokenWithoutOidcServer(TokenAuthenticationRequest request,
TenantConfigContext resolvedContext) {
try {
TokenVerificationResult result = resolvedContext.provider.verifyJwtToken(request.getToken().getToken(),
resolvedContext.oidcConfig.token.subjectRequired,
false, null);
return Uni.createFrom()
.item(validateAndCreateIdentity(Map.of(), request.getToken(), resolvedContext,
result.localVerificationResult, result.localVerificationResult, null, null, request));
} catch (Throwable t) {
return Uni.createFrom().failure(new AuthenticationFailedException(t));
}
}
private Uni getUserInfoUni(Map requestData, TokenAuthenticationRequest request,
TenantConfigContext resolvedContext) {
if (isInternalIdToken(request) && OidcUtils.cacheUserInfoInIdToken(tenantResolver, resolvedContext.oidcConfig)) {
JsonObject userInfo = OidcUtils.decodeJwtContent(request.getToken().getToken())
.getJsonObject(OidcUtils.USER_INFO_ATTRIBUTE);
if (userInfo != null) {
return Uni.createFrom().item(new UserInfo(userInfo.encode()));
}
}
LOG.debug("Requesting UserInfo");
String contextAccessToken = (String) requestData.get(OidcConstants.ACCESS_TOKEN_VALUE);
final String accessToken = contextAccessToken != null ? contextAccessToken : request.getToken().getToken();
UserInfoCache userInfoCache = tenantResolver.getUserInfoCache();
Uni userInfoUni = userInfoCache == null ? null
: userInfoCache.getUserInfo(accessToken, resolvedContext.oidcConfig, getUserInfoRequestContext);
if (userInfoUni == null) {
userInfoUni = newUserInfoUni(resolvedContext, accessToken);
} else {
userInfoUni = userInfoUni.onItem().ifNull()
.switchTo(new Supplier>() {
@Override
public Uni get() {
return newUserInfoUni(resolvedContext, accessToken);
}
});
}
return userInfoUni;
}
private Uni newUserInfoUni(TenantConfigContext resolvedContext, String accessToken) {
Uni userInfoUni = resolvedContext.provider.getUserInfo(accessToken);
if (tenantResolver.getUserInfoCache() == null || !resolvedContext.oidcConfig.allowUserInfoCache
|| OidcUtils.cacheUserInfoInIdToken(tenantResolver, resolvedContext.oidcConfig)) {
return userInfoUni;
} else {
return userInfoUni.call(new Function>() {
@Override
public Uni> apply(UserInfo userInfo) {
return tenantResolver.getUserInfoCache().addUserInfo(accessToken, userInfo,
resolvedContext.oidcConfig, uniVoidOidcContext);
}
});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy