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

io.quarkiverse.renarde.util.RenardeJWTAuthMechanism Maven / Gradle / Ivy

The newest version!
package io.quarkiverse.renarde.util;

import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;

import io.netty.handler.codec.http.HttpHeaderNames;
import io.quarkiverse.renarde.impl.RenardeConfigBean;
import io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism;
import io.quarkus.smallrye.jwt.runtime.auth.SmallRyeJwtConfig;
import io.quarkus.vertx.http.runtime.security.ChallengeData;
import io.smallrye.mutiny.Uni;
import io.vertx.core.http.Cookie;
import io.vertx.ext.web.RoutingContext;

/**
 * This class replaces the original JWTAuthMechanism with a lower priority, so that other interactive auth
 * such as WebAuthn, OIDC or Form get a chance to issue a redirect challenge, when this dumbass can only
 * issue a 401, and since the auth mechanisms are in random order, we'd sometimes get a 401 and sometimes
 * a proper redirect. It now issues a redirect, but stays in lower priority.
 */
@Priority(2000)
@ApplicationScoped
public class RenardeJWTAuthMechanism extends JWTAuthMechanism {

    private static final Logger log = Logger.getLogger(RenardeJWTAuthMechanism.class);

    @Inject
    RenardeConfigBean config;

    @ConfigProperty(name = "quarkus.renarde.auth.location-cookie")
    String locationCookie;

    // for CDI proxy
    RenardeJWTAuthMechanism() {
        this(null);
    }

    public RenardeJWTAuthMechanism(SmallRyeJwtConfig config) {
        super(config);
    }

    @Override
    public int getPriority() {
        return -1000;
    }

    protected void storeInitialLocation(final RoutingContext exchange) {
        exchange.response().addCookie(Cookie.cookie(locationCookie, exchange.request().absoluteURI())
                .setPath("/").setSecure(exchange.request().isSSL()));
    }

    static Uni getRedirect(final RoutingContext exchange, final String location) {
        String loc = exchange.request().scheme() + "://" + exchange.request().host() + location;
        return Uni.createFrom().item(new ChallengeData(302, "Location", loc));
    }

    @Override
    public Uni getChallenge(RoutingContext context) {
        // always redirect to the login page, except when we have a special REST header
        String authHeader = context.request().headers().get(HttpHeaderNames.AUTHORIZATION);
        if (authHeader != null) {
            return super.getChallenge(context);
        }

        if (context.request().uri().equals(config.getLoginPage())) {
            log.errorf(
                    "Avoiding redirect loop, make sure that your endpoint annotated with @LoginPage is accessible without being authenticated: %s",
                    config.getLoginPage());
            return super.getChallenge(context);
        } else {
            // we need to store the URL
            storeInitialLocation(context);
            return getRedirect(context, config.getLoginPage());
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy