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?