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

io.quarkus.oidc.runtime.OidcAuthenticationMechanism 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.Set;
import java.util.function.Function;

import jakarta.enterprise.context.ApplicationScoped;

import org.jboss.logging.Logger;

import io.quarkus.oidc.OIDCException;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.OidcTenantConfig.ApplicationType;
import io.quarkus.oidc.common.runtime.OidcConstants;
import io.quarkus.security.identity.IdentityProviderManager;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.request.AuthenticationRequest;
import io.quarkus.security.identity.request.TokenAuthenticationRequest;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.quarkus.vertx.http.runtime.security.ChallengeData;
import io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism;
import io.quarkus.vertx.http.runtime.security.HttpCredentialTransport;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class OidcAuthenticationMechanism implements HttpAuthenticationMechanism {
    private static final Logger LOG = Logger.getLogger(OidcAuthenticationMechanism.class);

    private static HttpCredentialTransport OIDC_WEB_APP_TRANSPORT = new HttpCredentialTransport(
            HttpCredentialTransport.Type.AUTHORIZATION_CODE, OidcConstants.CODE_FLOW_CODE);

    private final BearerAuthenticationMechanism bearerAuth = new BearerAuthenticationMechanism();
    private final CodeAuthenticationMechanism codeAuth;
    private final DefaultTenantConfigResolver resolver;

    public OidcAuthenticationMechanism(DefaultTenantConfigResolver resolver, BlockingSecurityExecutor blockingExecutor) {
        this.resolver = resolver;
        this.codeAuth = new CodeAuthenticationMechanism(blockingExecutor);
        this.bearerAuth.init(this, resolver);
        this.codeAuth.init(this, resolver);
    }

    @Override
    public Uni authenticate(RoutingContext context,
            IdentityProviderManager identityProviderManager) {
        return resolve(context).chain(new Function<>() {
            @Override
            public Uni apply(OidcTenantConfig oidcConfig) {
                if (!oidcConfig.tenantEnabled) {
                    return Uni.createFrom().nullItem();
                }
                return isWebApp(context, oidcConfig) ? codeAuth.authenticate(context, identityProviderManager, oidcConfig)
                        : bearerAuth.authenticate(context, identityProviderManager, oidcConfig);
            }
        });
    }

    @Override
    public Uni getChallenge(RoutingContext context) {
        return resolve(context).chain(new Function<>() {
            @Override
            public Uni apply(OidcTenantConfig oidcTenantConfig) {
                if (!oidcTenantConfig.tenantEnabled) {
                    return Uni.createFrom().nullItem();
                }
                return isWebApp(context, oidcTenantConfig) ? codeAuth.getChallenge(context)
                        : bearerAuth.getChallenge(context);
            }
        });
    }

    private Uni resolve(RoutingContext context) {
        OidcTenantConfig resolvedConfig = context.get(OidcTenantConfig.class.getName());
        if (resolvedConfig != null) {
            return Uni.createFrom().item(resolvedConfig);
        }

        setTenantIdAttribute(context);

        return resolver.resolveConfig(context).map(new Function<>() {
            @Override
            public OidcTenantConfig apply(OidcTenantConfig oidcTenantConfig) {
                if (oidcTenantConfig == null) {
                    throw new OIDCException("Tenant configuration has not been resolved");
                }
                LOG.debugf("Resolved OIDC tenant id: %s", oidcTenantConfig.tenantId.orElse(OidcUtils.DEFAULT_TENANT_ID));
                context.put(OidcTenantConfig.class.getName(), oidcTenantConfig);
                return oidcTenantConfig;
            };
        });
    }

    private boolean isWebApp(RoutingContext context, OidcTenantConfig oidcConfig) {
        ApplicationType applicationType = oidcConfig.applicationType.orElse(ApplicationType.SERVICE);
        if (OidcTenantConfig.ApplicationType.HYBRID == applicationType) {
            return context.request().getHeader("Authorization") == null;
        }
        return OidcTenantConfig.ApplicationType.WEB_APP == applicationType;
    }

    @Override
    public Set> getCredentialTypes() {
        return Collections.singleton(TokenAuthenticationRequest.class);
    }

    @Override
    public Uni getCredentialTransport(RoutingContext context) {
        return resolve(context).onItem().transform(new Function() {
            @Override
            public HttpCredentialTransport apply(OidcTenantConfig oidcTenantConfig) {
                if (!oidcTenantConfig.tenantEnabled) {
                    return null;
                }
                return isWebApp(context, oidcTenantConfig) ? OIDC_WEB_APP_TRANSPORT
                        : new HttpCredentialTransport(
                                HttpCredentialTransport.Type.AUTHORIZATION, oidcTenantConfig.token.authorizationScheme);
            }
        });
    }

    private static void setTenantIdAttribute(RoutingContext context) {
        if (context.get(OidcUtils.TENANT_ID_ATTRIBUTE) == null) {
            for (String cookieName : context.cookieMap().keySet()) {
                if (OidcUtils.isSessionCookie(cookieName)) {
                    setTenantIdAttribute(context, OidcUtils.SESSION_COOKIE_NAME, cookieName, true);
                    break;
                } else if (cookieName.startsWith(OidcUtils.STATE_COOKIE_NAME)) {
                    setTenantIdAttribute(context, OidcUtils.STATE_COOKIE_NAME, cookieName, false);
                    break;
                }
            }
        }
    }

    private static void setTenantIdAttribute(RoutingContext context, String cookiePrefix, String cookieName,
            boolean sessionCookie) {
        String tenantId = OidcUtils.getTenantIdFromCookie(cookiePrefix, cookieName, sessionCookie);

        context.put(OidcUtils.TENANT_ID_ATTRIBUTE, tenantId);
        context.put(sessionCookie ? OidcUtils.TENANT_ID_SET_BY_SESSION_COOKIE : OidcUtils.TENANT_ID_SET_BY_STATE_COOKIE,
                tenantId);
        LOG.debugf("%s cookie set a '%s' tenant id on the %s request path", cookieName, tenantId, context.request().path());
    }

    @Override
    public int getPriority() {
        return HttpAuthenticationMechanism.DEFAULT_PRIORITY + 1;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy