| .. | .. |
|---|
| 81 | 81 | */ |
|---|
| 82 | 82 | @Override |
|---|
| 83 | 83 | public void filter(ContainerRequestContext requestContext) throws IOException { |
|---|
| 84 | | - EntityManager em = emProvider.getEntityManager(); |
|---|
| 85 | | - LOG.debug("GETTING EM: {}", em); |
|---|
| 84 | + |
|---|
| 85 | + Method method = resourceInfo != null ? resourceInfo.getResourceMethod() : null; |
|---|
| 86 | + if (method == null) { |
|---|
| 87 | + LOG.warn("RequestsInterceptor: resource method is null"); |
|---|
| 88 | + return; |
|---|
| 89 | + } |
|---|
| 86 | 90 | |
|---|
| 87 | | - // Store EntityManager for later retrieval (writer interceptor) |
|---|
| 88 | | - requestContext.setProperty(EM_CONTEXT_PROPERTY, em); |
|---|
| 91 | + boolean securable = method.isAnnotationPresent(Securable.class); |
|---|
| 92 | + boolean ensureTransaction = method.isAnnotationPresent(EnsureTransaction.class); |
|---|
| 89 | 93 | |
|---|
| 90 | | - Method method = resourceInfo.getResourceMethod(); |
|---|
| 94 | + // Only require injected helpers when the endpoint actually needs them |
|---|
| 95 | + if (securable) { |
|---|
| 96 | + if (tokenHelper == null || cache == null || emProvider == null) { |
|---|
| 97 | + LOG.error( |
|---|
| 98 | + "RequestsInterceptor is not fully initialized for secured endpoint '{}'. " + |
|---|
| 99 | + "tokenHelper={}, cache={}, emProvider={}", |
|---|
| 100 | + method.getName(), tokenHelper, cache, emProvider |
|---|
| 101 | + ); |
|---|
| 102 | + requestContext.abortWith( |
|---|
| 103 | + Response.status(Status.INTERNAL_SERVER_ERROR) |
|---|
| 104 | + .entity("Security infrastructure not initialized") |
|---|
| 105 | + .build() |
|---|
| 106 | + ); |
|---|
| 107 | + return; |
|---|
| 108 | + } |
|---|
| 91 | 109 | |
|---|
| 92 | | - if (checkSecurableMethods(requestContext, method)) { |
|---|
| 93 | | - if (method.isAnnotationPresent(EnsureTransaction.class)) { |
|---|
| 94 | | - LOG.debug("Beginning transaction"); |
|---|
| 95 | | - em.getTransaction().begin(); |
|---|
| 110 | + if (!checkSecurableMethods(requestContext, method)) { |
|---|
| 111 | + return; |
|---|
| 112 | + } |
|---|
| 113 | + } |
|---|
| 114 | + |
|---|
| 115 | + // Only open/use EM when needed |
|---|
| 116 | + if (ensureTransaction || securable) { |
|---|
| 117 | + EntityManager em = getEntityManagerSafely(); |
|---|
| 118 | + if (em == null) { |
|---|
| 119 | + LOG.error("No EntityManager available for method '{}'", method.getName()); |
|---|
| 120 | + requestContext.abortWith( |
|---|
| 121 | + Response.status(Status.INTERNAL_SERVER_ERROR) |
|---|
| 122 | + .entity("Persistence infrastructure not initialized") |
|---|
| 123 | + .build() |
|---|
| 124 | + ); |
|---|
| 125 | + return; |
|---|
| 126 | + } |
|---|
| 127 | + |
|---|
| 128 | + LOG.debug("GETTING EM: {}", em); |
|---|
| 129 | + requestContext.setProperty(EM_CONTEXT_PROPERTY, em); |
|---|
| 130 | + |
|---|
| 131 | + if (ensureTransaction) { |
|---|
| 132 | + try { |
|---|
| 133 | + if (!em.getTransaction().isActive()) { |
|---|
| 134 | + LOG.debug("Beginning transaction"); |
|---|
| 135 | + em.getTransaction().begin(); |
|---|
| 136 | + } |
|---|
| 137 | + } catch (Exception e) { |
|---|
| 138 | + LOG.error("Error beginning transaction for method '{}'", method.getName(), e); |
|---|
| 139 | + requestContext.abortWith( |
|---|
| 140 | + Response.status(Status.INTERNAL_SERVER_ERROR) |
|---|
| 141 | + .entity("Could not begin transaction") |
|---|
| 142 | + .build() |
|---|
| 143 | + ); |
|---|
| 144 | + } |
|---|
| 96 | 145 | } |
|---|
| 97 | 146 | } |
|---|
| 98 | 147 | } |
|---|
| .. | .. |
|---|
| 107 | 156 | * @return true if request can proceed; false when aborted |
|---|
| 108 | 157 | */ |
|---|
| 109 | 158 | private boolean checkSecurableMethods(ContainerRequestContext ctx, Method method) { |
|---|
| 110 | | - if (!method.isAnnotationPresent(Securable.class)) return true; |
|---|
| 159 | + if (!method.isAnnotationPresent(Securable.class)) { |
|---|
| 160 | + return true; |
|---|
| 161 | + } |
|---|
| 111 | 162 | |
|---|
| 112 | | - String token = servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM); |
|---|
| 163 | + String token = servletRequest != null ? servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM) : null; |
|---|
| 113 | 164 | if (token == null || !tokenHelper.isTokenValid(token)) { |
|---|
| 114 | 165 | LOG.warn("Access denied, invalid token"); |
|---|
| 115 | 166 | ctx.abortWith(Response.status(Status.UNAUTHORIZED).build()); |
|---|
| .. | .. |
|---|
| 126 | 177 | return false; |
|---|
| 127 | 178 | } |
|---|
| 128 | 179 | |
|---|
| 129 | | - BasicSecurityContext sc = new BasicSecurityContext(username, roles, servletRequest.isSecure()); |
|---|
| 180 | + boolean secure = servletRequest != null && servletRequest.isSecure(); |
|---|
| 181 | + BasicSecurityContext sc = new BasicSecurityContext(username, roles, secure); |
|---|
| 130 | 182 | sc.setOrganizationsIds(getUserOrganizations(username)); |
|---|
| 131 | 183 | sc.setApplicationsIds(getUserApplications(username)); |
|---|
| 132 | 184 | ctx.setSecurityContext(sc); |
|---|
| 133 | 185 | return true; |
|---|
| 186 | + } |
|---|
| 187 | + |
|---|
| 188 | + /** |
|---|
| 189 | + * getEntityManagerSafely<p> |
|---|
| 190 | + * Get the entity manager in a safely way |
|---|
| 191 | + * |
|---|
| 192 | + * @return entityManager |
|---|
| 193 | + */ |
|---|
| 194 | + private EntityManager getEntityManagerSafely() { |
|---|
| 195 | + try { |
|---|
| 196 | + if (emProvider == null) { |
|---|
| 197 | + return null; |
|---|
| 198 | + } |
|---|
| 199 | + return emProvider.getEntityManager(); |
|---|
| 200 | + } catch (Exception e) { |
|---|
| 201 | + LOG.error("Error obtaining EntityManager from provider", e); |
|---|
| 202 | + return null; |
|---|
| 203 | + } |
|---|
| 134 | 204 | } |
|---|
| 135 | 205 | |
|---|
| 136 | 206 | // ------------------------------------------------------------- |
|---|
| .. | .. |
|---|
| 145 | 215 | * @return userRoles |
|---|
| 146 | 216 | */ |
|---|
| 147 | 217 | private int getUserRoles(String username) { |
|---|
| 148 | | - if (username == null) return 0; |
|---|
| 149 | | - Integer cached = cache.get("roles_" + username, Integer.class); |
|---|
| 150 | | - if (cached != null) return cached; |
|---|
| 218 | + if (username == null || cache == null) { |
|---|
| 219 | + return 0; |
|---|
| 220 | + } |
|---|
| 151 | 221 | |
|---|
| 152 | | - EntityManager em = emProvider.getEntityManager(); |
|---|
| 222 | + Integer cached = cache.get("roles_" + username, Integer.class); |
|---|
| 223 | + if (cached != null) { |
|---|
| 224 | + return cached; |
|---|
| 225 | + } |
|---|
| 226 | + |
|---|
| 227 | + EntityManager em = getEntityManagerSafely(); |
|---|
| 228 | + if (em == null) { |
|---|
| 229 | + LOG.error("Cannot resolve user roles: EntityManager is not available"); |
|---|
| 230 | + return 0; |
|---|
| 231 | + } |
|---|
| 232 | + |
|---|
| 153 | 233 | User user = em.find(User.class, username); |
|---|
| 154 | 234 | int roles = 0; |
|---|
| 155 | 235 | if (user != null) { |
|---|
| 156 | 236 | List<Integer> r = user.getRoles(); |
|---|
| 157 | | - if (r != null) for (Integer role : r) roles += role; |
|---|
| 237 | + if (r != null) { |
|---|
| 238 | + for (Integer role : r) { |
|---|
| 239 | + roles += role; |
|---|
| 240 | + } |
|---|
| 241 | + } |
|---|
| 158 | 242 | cache.set("roles_" + username, roles, 3600); |
|---|
| 159 | | - // also warm some caches |
|---|
| 160 | 243 | cache.set("orgs_" + username, user.getOrgsIds(), 3600); |
|---|
| 161 | 244 | } |
|---|
| 162 | 245 | return roles; |
|---|
| .. | .. |
|---|
| 171 | 254 | * @return userOrganizations |
|---|
| 172 | 255 | */ |
|---|
| 173 | 256 | private Set<Integer> getUserOrganizations(String username) { |
|---|
| 174 | | - Set<Integer> cached = cache.getSet("orgs_" + username, Integer.class); |
|---|
| 175 | | - if (cached != null) return cached; |
|---|
| 257 | + if (username == null || cache == null) { |
|---|
| 258 | + return Set.of(); |
|---|
| 259 | + } |
|---|
| 176 | 260 | |
|---|
| 177 | | - User user = emProvider.getEntityManager().find(User.class, username); |
|---|
| 261 | + Set<Integer> cached = cache.getSet("orgs_" + username, Integer.class); |
|---|
| 262 | + if (cached != null) { |
|---|
| 263 | + return cached; |
|---|
| 264 | + } |
|---|
| 265 | + |
|---|
| 266 | + EntityManager em = getEntityManagerSafely(); |
|---|
| 267 | + if (em == null) { |
|---|
| 268 | + LOG.error("Cannot resolve user organizations: EntityManager is not available"); |
|---|
| 269 | + return Set.of(); |
|---|
| 270 | + } |
|---|
| 271 | + |
|---|
| 272 | + User user = em.find(User.class, username); |
|---|
| 178 | 273 | if (user != null) { |
|---|
| 179 | 274 | Set<Integer> result = user.getAllOrgsIds(); |
|---|
| 180 | 275 | cache.set("orgs_" + username, result, 3600); |
|---|
| .. | .. |
|---|
| 192 | 287 | * @return userApplications |
|---|
| 193 | 288 | */ |
|---|
| 194 | 289 | private Set<Integer> getUserApplications(String username) { |
|---|
| 195 | | - Set<Integer> cached = cache.getSet("apps_" + username, Integer.class); |
|---|
| 196 | | - if (cached != null) return cached; |
|---|
| 290 | + if (username == null || cache == null) { |
|---|
| 291 | + return Set.of(); |
|---|
| 292 | + } |
|---|
| 197 | 293 | |
|---|
| 198 | | - User user = emProvider.getEntityManager().find(User.class, username); |
|---|
| 294 | + Set<Integer> cached = cache.getSet("apps_" + username, Integer.class); |
|---|
| 295 | + if (cached != null) { |
|---|
| 296 | + return cached; |
|---|
| 297 | + } |
|---|
| 298 | + |
|---|
| 299 | + EntityManager em = getEntityManagerSafely(); |
|---|
| 300 | + if (em == null) { |
|---|
| 301 | + LOG.error("Cannot resolve user applications: EntityManager is not available"); |
|---|
| 302 | + return Set.of(); |
|---|
| 303 | + } |
|---|
| 304 | + |
|---|
| 305 | + User user = em.find(User.class, username); |
|---|
| 199 | 306 | if (user != null) { |
|---|
| 200 | 307 | Set<Integer> result = user.getAllAppsIds(); |
|---|
| 201 | 308 | cache.set("apps_" + username, result, 3600); |
|---|
| .. | .. |
|---|
| 218 | 325 | */ |
|---|
| 219 | 326 | @Override |
|---|
| 220 | 327 | public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { |
|---|
| 221 | | - context.proceed(); |
|---|
| 222 | | - |
|---|
| 223 | | - EntityManager em = (EntityManager) context.getProperty(EM_CONTEXT_PROPERTY); |
|---|
| 224 | | - if (em == null) return; |
|---|
| 225 | | - |
|---|
| 226 | 328 | try { |
|---|
| 227 | | - if (em.getTransaction().isActive()) { |
|---|
| 228 | | - if (servletResponse.getStatus() == Status.OK.getStatusCode()) { |
|---|
| 229 | | - em.getTransaction().commit(); |
|---|
| 230 | | - LOG.debug("Transaction committed"); |
|---|
| 231 | | - } else { |
|---|
| 232 | | - em.getTransaction().rollback(); |
|---|
| 233 | | - LOG.debug("Transaction rolled back"); |
|---|
| 234 | | - } |
|---|
| 235 | | - } |
|---|
| 329 | + context.proceed(); |
|---|
| 236 | 330 | } finally { |
|---|
| 237 | | - if (em.isOpen()) { |
|---|
| 331 | + EntityManager em = (EntityManager) context.getProperty(EM_CONTEXT_PROPERTY); |
|---|
| 332 | + if (em == null) { |
|---|
| 333 | + return; |
|---|
| 334 | + } |
|---|
| 335 | + |
|---|
| 336 | + try { |
|---|
| 337 | + if (em.getTransaction() != null && em.getTransaction().isActive()) { |
|---|
| 338 | + int status = servletResponse != null ? servletResponse.getStatus() : Status.INTERNAL_SERVER_ERROR.getStatusCode(); |
|---|
| 339 | + if (status >= 200 && status < 300) { |
|---|
| 340 | + em.getTransaction().commit(); |
|---|
| 341 | + LOG.debug("Transaction committed"); |
|---|
| 342 | + } else { |
|---|
| 343 | + em.getTransaction().rollback(); |
|---|
| 344 | + LOG.debug("Transaction rolled back"); |
|---|
| 345 | + } |
|---|
| 346 | + } |
|---|
| 347 | + } catch (Exception e) { |
|---|
| 348 | + LOG.error("Error finalizing transaction", e); |
|---|
| 238 | 349 | try { |
|---|
| 239 | | - em.close(); |
|---|
| 350 | + if (em.getTransaction() != null && em.getTransaction().isActive()) { |
|---|
| 351 | + em.getTransaction().rollback(); |
|---|
| 352 | + } |
|---|
| 353 | + } catch (Exception rollbackEx) { |
|---|
| 354 | + LOG.error("Error rolling back transaction", rollbackEx); |
|---|
| 355 | + } |
|---|
| 356 | + } finally { |
|---|
| 357 | + try { |
|---|
| 358 | + if (em.isOpen()) { |
|---|
| 359 | + em.close(); |
|---|
| 360 | + } |
|---|
| 240 | 361 | } catch (Exception e) { |
|---|
| 241 | 362 | LOG.error("Error closing EntityManager", e); |
|---|
| 242 | 363 | } |
|---|
| 243 | 364 | } |
|---|
| 244 | 365 | } |
|---|
| 245 | 366 | } |
|---|
| 367 | + |
|---|
| 246 | 368 | } |
|---|
| 247 | 369 | |
|---|