How to get username Envers (API REST)

I have a REST API (wildfly 20 + microprofile jwt).
If I inject (via @Context) the javax.ws.rs.core.SecurityContext in my RevisionListener, the context is unfortunately null.

So how can I save the user name in my revision entity ? Thanks

PS : works fine in a web application with javax.security.enterprise.SecurityContext

I suppose that these resources are simply not available through CDI which is what Hibernate uses to do the instantiation/injection. You could try to create a ContainerRequestFilter or something like that and put the value into a thread local. Finally, you expose that value through a @RequestScoped @Produces method, which makes it available for injection.

The javax.ws.rs.core.SecurityContext is injected into my Java class annotated with javax.ws.rs.Path via the annotation javax.ws.rs.core.Context. Nothing original. May be the context is null when the RevisionListener is called.

I’m sorry but I don’t know how to implement your solution. Could you provide an example ?

I’m still wondering how the RevisionListener handles concurrent access. Is it RequestScoped ?

Thanks

Something like this:

@RequestScoped
public class MyContainerRequestFilter implements ContainerRequestFilter, ContainerResponseFilter {

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

  public void filter(ContainerRequestContext requestContext) {
    threadLocal.set(requestContext.getSecurityContext());
  }

  public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
    threadLocal.clear();
  }

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

Thank you beikov, it works great !
Here is my final class

import java.io.IOException;

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

/**
 * for some reason, the SecurityContext is not injected into the RevisionListener
 * this class does the job and produces RequestScoped SecurityContext
 */

@Provider
public class SecurityRequestFilter implements ContainerRequestFilter, ContainerResponseFilter {

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

	@RequestScoped
	@Produces
	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());
	}
}

Hello, I’m having the same issue as presented here before, but I’m using Hibernate Envers for Quarkus. Based on previous presented solution, I’ve created the following classes:

@Provider
public class SecurityRequestFilter implements ContainerRequestFilter, ContainerResponseFilter {

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

    @RequestScoped
    @Produces
    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());
    }
}
public class CustomRevisionListener implements RevisionListener {

    @Inject
    SecurityContext securityContext;
    
    @Override
    public void newRevision(Object revisionEntity) {
        CustomRevision customRevision = (CustomRevision) revisionEntity;
        customRevision.setUsername(securityContext.getUserPrincipal().getName());
    }
}

However, my SecurityContext in CustomRevisionListener is sadly null. Anyone knows how to fix this issue?

Thank you in advance!

It’s probably best if you ask this on the Quarkus Zulip chat @hugo_gonzalez

1 Like

Hi!

I’m using Quarkus and having the same problem. Did you manage to solve it?

May be this can help :
https://www.bytefish.de/blog/hibernate_envers_versioning_and_auditing.html