Impossible to inject the SecurityContext in Quarkus 3.6.5+

60 views Asked by At

Latery I'm trying to resolve a problem with my jakarta.ws.rs.core.SecurityContext. I'm using the Hibernate Envers and I have a audited entity named Movie. For hold the SecurityContext, I've adopted a solution present on Hibernate Envers : How to inject SecurityContext (REST) in RevisionListener? and https://discourse.hibernate.org/t/how-to-get-username-envers-api-rest/5592/6.

Unfortunately, in Quarkus 3.6.5+ this solution is not working. But, in Quarkus 3.6.4 it works.

I have a class CustomRevisionListener where I'm trying to inject de SecurityContext, but it's returning null for Quarkus 3.6.5+. Consequently, usermail keeps equal to "anonymous".

package org.acme;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

import org.hibernate.envers.RevisionListener;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;

import org.acme.Log;
import io.quarkus.arc.Unremovable;
import io.quarkus.security.identity.SecurityIdentity;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.mutiny.ext.web.RoutingContext;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;

@ApplicationScoped
@Unremovable
public class CustomRevisionListener implements RevisionListener {

    private final Logger logger = Logger.getLogger(CustomRevisionListener.class);
    
    @Inject
    SecurityContext securityContext;


//  @Inject
//  UserRepository userRepository;
    
    @Override
    public void newRevision(Object revisionEntity) {

        Log log = (Log) revisionEntity;
        log.setCreationDate(LocalDateTime.ofInstant(Instant.ofEpochMilli(log.getTimestamp()), ZoneId.systemDefault()));
        
        String usermail = "anonymous";
        
        if(securityContext != null && securityContext.getUserPrincipal() != null) {
                usermail = securityContext.getUserPrincipal().getName();            
        }

        log.setUser(usermail);                                                                                

        HttpServerRequest request = ResteasyProviderFactory.getInstance().getContextData(HttpServerRequest.class);
        log.setIp(request.remoteAddress().hostAddress());
    }
}

I will post the codes responsables for capturing the Context bellow:

package org.acme;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import jakarta.inject.Qualifier;

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface CustomSecurityContext {
    
}

package org.acme;

import java.io.IOException;

import jakarta.enterprise.context.RequestScoped;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.ext.Provider;

/**
 * 
 * @author adm
 * https://stackoverflow.com/questions/68652949/hibernate-envers-how-to-inject-securitycontext-rest-in-revisionlistener
 * https://discourse.hibernate.org/t/how-to-get-username-envers-api-rest/5592/6
 */

@Provider
public class SecurityRequestFilter implements ContainerRequestFilter, ContainerResponseFilter {

    private static final ThreadLocal<SecurityContext> THREAD_LOCAL = new ThreadLocal<>();

    @RequestScoped
    @Produces
    @CustomSecurityContext
    public SecurityContext getSecurityContext() {
        return THREAD_LOCAL.get();
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
            throws IOException {
        THREAD_LOCAL.remove();
    }

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        THREAD_LOCAL.set(requestContext.getSecurityContext());
    }
}

More informations: I'm using Keycloak with OIDC connection, RESTEasy Classic, JDBC Connection for MySQL.

# OIDC Configuration
quarkus.oidc.auth-server-url=http://localhost:8080/realms/quarkus
quarkus.oidc.client-id=ensitec
quarkus.oidc.credentials.secret=vZOXyggQW2N2bxjy4pdWSNJetL4pm1C9
quarkus.oidc.tls.verification=none

# CORS Configuration
quarkus.http.cors=true
quarkus.http.cors.origins=*
quarkus.http.cors.methods=GET,DELETE,POST,PUT,OPTIONS
quarkus.http.cors.access-control-allow-credentials=true


quarkus.hibernate-envers.audit-table-prefix=_

Is it a bug from Hibernate Envers? Is there another method that I could hold the SecurityContext?

0

There are 0 answers