From 89b1c533d1b48b8b339b9c74a59c2ce73e6431af Mon Sep 17 00:00:00 2001
From: Joaquín Reñé <jrene@curisit.net>
Date: Tue, 27 May 2025 10:27:57 +0000
Subject: [PATCH] #4399 - Fix JPA and Serialization for new JPA versions (new eclipse envs)

---
 securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java |  230 +++++++++++++++++++++++----------------------------------
 1 files changed, 93 insertions(+), 137 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java b/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
index 391ec7f..fd61433 100644
--- a/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
+++ b/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
@@ -5,30 +5,25 @@
 import java.util.List;
 import java.util.Set;
 
-import javax.annotation.Priority;
-import javax.inject.Inject;
-import javax.persistence.EntityManager;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.Priorities;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.ext.Provider;
-import javax.ws.rs.ext.WriterInterceptor;
-import javax.ws.rs.ext.WriterInterceptorContext;
+import jakarta.annotation.Priority;
+import jakarta.inject.Inject;
+import jakarta.persistence.EntityManager;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.ws.rs.Priorities;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+import jakarta.ws.rs.ext.Provider;
+import jakarta.ws.rs.ext.WriterInterceptor;
+import jakarta.ws.rs.ext.WriterInterceptorContext;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.jboss.resteasy.core.Dispatcher;
-import org.jboss.resteasy.core.ResourceMethodInvoker;
-import org.jboss.resteasy.core.ServerResponse;
-import org.jboss.resteasy.spi.Failure;
-import org.jboss.resteasy.spi.HttpRequest;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
 
 import net.curisit.securis.db.User;
 import net.curisit.securis.security.BasicSecurityContext;
@@ -39,6 +34,7 @@
 @Provider
 @Priority(Priorities.AUTHENTICATION)
 public class RequestsInterceptor implements ContainerRequestFilter, WriterInterceptor {
+
 	private static final Logger LOG = LogManager.getLogger(RequestsInterceptor.class);
 
 	@Context
@@ -47,171 +43,131 @@
 	@Context
 	private HttpServletRequest servletRequest;
 
+	@Context
+	private ResourceInfo resourceInfo;
+
 	@Inject
 	private CacheTTL cache;
 
 	@Inject
 	private TokenHelper tokenHelper;
 
-	@Context
-	private Dispatcher dispatcher;
-
 	@Inject
 	private EntityManagerProvider emProvider;
 
+	private static final String EM_CONTEXT_PROPERTY = "curisit.entitymanager";
+
 	@Override
-	public void filter(ContainerRequestContext containerRequestContext) throws IOException {
+	public void filter(ContainerRequestContext requestContext) throws IOException {
 		EntityManager em = emProvider.getEntityManager();
 		LOG.debug("GETTING EM: {}", em);
 
-		ResteasyProviderFactory.pushContext(EntityManager.class, em);
+		// Guardamos el EntityManager en el contexto para recuperación posterior
+		requestContext.setProperty(EM_CONTEXT_PROPERTY, em);
 
-		ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) containerRequestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
-		Method method = methodInvoker.getMethod();
+		Method method = resourceInfo.getResourceMethod();
 
-		LOG.debug("Stored in context, em: {}, {}", em, method.toGenericString());
-
-		boolean next = checkSecurableMethods(containerRequestContext, method);
-		if (next) {
-			prepareTransaction(containerRequestContext, method, em);
+		if (checkSecurableMethods(requestContext, method)) {
+			if (method.isAnnotationPresent(EnsureTransaction.class)) {
+				LOG.debug("Beginning transaction");
+				em.getTransaction().begin();
+			}
 		}
 	}
 
-	private void prepareTransaction(ContainerRequestContext containerRequestContext, Method method, EntityManager em) {
+	private boolean checkSecurableMethods(ContainerRequestContext ctx, Method method) {
+		if (!method.isAnnotationPresent(Securable.class)) return true;
 
-		if (method.isAnnotationPresent(EnsureTransaction.class)) {
-			LOG.debug("Beginning a new transaction");
-			em.getTransaction().begin();
-		}
-	}
-
-	private boolean checkSecurableMethods(ContainerRequestContext containerRequestContext, Method method) {
-		if (!method.isAnnotationPresent(Securable.class)) {
-			return true;
-		}
 		String token = servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM);
 		if (token == null || !tokenHelper.isTokenValid(token)) {
-			LOG.warn("Access denied, Token not valid: {} for method: {}::{}", token, method.getDeclaringClass(), method.getName());
-			containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build());
+			LOG.warn("Access denied, invalid token");
+			ctx.abortWith(Response.status(Status.UNAUTHORIZED).build());
 			return false;
-		} else {
-			Securable securable = method.getAnnotation(Securable.class);
-			// If roles == 0 we only need to validate the token
-			String username = tokenHelper.extractUserFromToken(token);
-			int userRoles = getUserRoles(username);
-			if (securable.roles() != 0 && (securable.roles() & userRoles) == 0) {
-				LOG.warn("Method {} requires roles: {}, but user {} hasn't got them", method.getName(), securable.roles(), username);
-				containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build());
-				return false;
-			}
-			Set<Integer> orgs = getUserOrganizations(username);
-			Set<Integer> apps = getUserApplications(username);
-
-			BasicSecurityContext scw = new BasicSecurityContext(username, userRoles, servletRequest.isSecure());
-			scw.setOrganizationsIds(orgs);
-			scw.setApplicationsIds(apps);
-			containerRequestContext.setSecurityContext(scw);
-			// Next line provide injection in resource methods
-			ResteasyProviderFactory.pushContext(BasicSecurityContext.class, scw);
-			LOG.debug("Added custom SecurityContext for user {}, orgs: {}", username, orgs);
 		}
+
+		String username = tokenHelper.extractUserFromToken(token);
+		int roles = getUserRoles(username);
+		Securable securable = method.getAnnotation(Securable.class);
+
+		if (securable.roles() != 0 && (securable.roles() & roles) == 0) {
+			LOG.warn("User {} lacks required roles for method {}", username, method.getName());
+			ctx.abortWith(Response.status(Status.UNAUTHORIZED).build());
+			return false;
+		}
+
+		BasicSecurityContext sc = new BasicSecurityContext(username, roles, servletRequest.isSecure());
+		sc.setOrganizationsIds(getUserOrganizations(username));
+		sc.setApplicationsIds(getUserApplications(username));
+		ctx.setSecurityContext(sc);
 		return true;
-
-	}
-
-	private Set<Integer> getUserOrganizations(String username) {
-		@SuppressWarnings("unchecked")
-		Set<Integer> userOrgs = cache.get("orgs_" + username, Set.class);
-		if (userOrgs == null) {
-			EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
-
-			// Theorically this shouldn't be never null, but just in case...
-			User user = em.find(User.class, username);
-			if (user != null) {
-				userOrgs = user.getAllOrgsIds();
-				// We store user orgs in cache only for one hour
-				cache.set("orgs_" + username, userOrgs, 3600);
-			}
-		}
-
-		return userOrgs;
-	}
-
-	private Set<Integer> getUserApplications(String username) {
-		@SuppressWarnings("unchecked")
-		Set<Integer> userApps = cache.get("apps_" + username, Set.class);
-		if (userApps == null) {
-			EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
-
-			// Theorically this shouldn't be never null, but just in case...
-			User user = em.find(User.class, username);
-			if (user != null) {
-				userApps = user.getAllAppsIds();
-				// We store user orgs in cache only for one hour
-				cache.set("apps_" + username, userApps, 3600);
-			}
-		}
-
-		return userApps;
 	}
 
 	private int getUserRoles(String username) {
-		if (username == null) {
-			return 0;
-		}
-		Integer userRoles = cache.get("roles_" + username, Integer.class);
-		if (userRoles == null) {
-			EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
+		if (username == null) return 0;
+		Integer cached = cache.get("roles_" + username, Integer.class);
+		if (cached != null) return cached;
 
-			User user = em.find(User.class, username);
-			if (user != null) {
-				userRoles = 0;
-				List<Integer> roles = user.getRoles();
-				if (roles != null) {
-					for (Integer rol : roles) {
-						userRoles += rol;
-					}
-				}
-				// We store user roles in cache only for one hour
-				cache.set("roles_" + username, userRoles, 3600);
-				cache.set("orgs_" + username, user.getOrgsIds(), 3600);
-			}
+		EntityManager em = emProvider.getEntityManager();
+		User user = em.find(User.class, username);
+		int roles = 0;
+		if (user != null) {
+			List<Integer> r = user.getRoles();
+			if (r != null) for (Integer role : r) roles += role;
+			cache.set("roles_" + username, roles, 3600);
+			cache.set("orgs_" + username, user.getOrgsIds(), 3600);
 		}
-		return userRoles == null ? 0 : userRoles.intValue();
+		return roles;
 	}
 
-	// @Override
-	public ServerResponse preProcess(HttpRequest request, ResourceMethodInvoker method) throws Failure, WebApplicationException {
-		return null;
+	private Set<Integer> getUserOrganizations(String username) {
+		Set<Integer> cached = cache.get("orgs_" + username, Set.class);
+		if (cached != null) return cached;
+		User user = emProvider.getEntityManager().find(User.class, username);
+		if (user != null) {
+			Set<Integer> result = user.getAllOrgsIds();
+			cache.set("orgs_" + username, result, 3600);
+			return result;
+		}
+		return Set.of();
+	}
+
+	private Set<Integer> getUserApplications(String username) {
+		Set<Integer> cached = cache.get("apps_" + username, Set.class);
+		if (cached != null) return cached;
+		User user = emProvider.getEntityManager().find(User.class, username);
+		if (user != null) {
+			Set<Integer> result = user.getAllAppsIds();
+			cache.set("apps_" + username, result, 3600);
+			return result;
+		}
+		return Set.of();
 	}
 
 	@Override
 	public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
 		context.proceed();
-		EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
+
+		EntityManager em = (EntityManager) context.getProperty(EM_CONTEXT_PROPERTY);
+		if (em == null) return;
+
 		try {
-			if (em != null && em.getTransaction().isActive()) {
+			if (em.getTransaction().isActive()) {
 				if (servletResponse.getStatus() == Status.OK.getStatusCode()) {
 					em.getTransaction().commit();
-					LOG.debug("COMMIT");
+					LOG.debug("Transaction committed");
 				} else {
-					// This code is never executed if there is an error the
-					// filter chain is broken
 					em.getTransaction().rollback();
-					LOG.debug("ROLLBACK");
+					LOG.debug("Transaction rolled back");
 				}
 			}
 		} finally {
 			if (em.isOpen()) {
-				LOG.debug("CLOSING EM: {}, trans: {}", em, em.isJoinedToTransaction());
 				try {
 					em.close();
-				} catch (Exception ex) {
-					ex.printStackTrace();
-					LOG.error("Error closing EM: {}, {}", em, ex);
+				} catch (Exception e) {
+					LOG.error("Error closing EntityManager", e);
 				}
 			}
 		}
 	}
-
 }

--
Gitblit v1.3.2