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