From 9430a83dde5d7c3f4535f6c3a5f9e21ac68ac8fa Mon Sep 17 00:00:00 2001
From: Joaquín Reñé <jrene@curisit.net>
Date: Thu, 16 Apr 2026 17:05:28 +0000
Subject: [PATCH] #4479 - upgrade SecurisServer to Java 21
---
securis/src/main/resources/META-INF/persistence.xml | 34 +++++------
securis/pom.xml | 6 ++
securis/src/main/resources/version.properties | 5 +
securis/src/main/webapp/WEB-INF/web.xml | 12 ++-
securis/src/main/java/net/curisit/securis/services/UserResource.java | 54 ++++++++++++------
securis/src/main/webapp/src/app/footer.component.ts | 2
securis/src/main/webapp/src/app/user.service.ts | 4
securis/src/main/java/net/curisit/securis/ioc/EntityManagerProvider.java | 30 +++++++++-
8 files changed, 100 insertions(+), 47 deletions(-)
diff --git a/securis/pom.xml b/securis/pom.xml
index 312b1c8..bf7229f 100644
--- a/securis/pom.xml
+++ b/securis/pom.xml
@@ -176,6 +176,12 @@
</dependencies>
<build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git a/securis/src/main/java/net/curisit/securis/ioc/EntityManagerProvider.java b/securis/src/main/java/net/curisit/securis/ioc/EntityManagerProvider.java
index f702c97..2add6fc 100644
--- a/securis/src/main/java/net/curisit/securis/ioc/EntityManagerProvider.java
+++ b/securis/src/main/java/net/curisit/securis/ioc/EntityManagerProvider.java
@@ -3,6 +3,7 @@
*/
package net.curisit.securis.ioc;
+import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
@@ -27,15 +28,27 @@
@ApplicationScoped
public class EntityManagerProvider {
- @SuppressWarnings("unused")
private static final Logger log = LogManager.getLogger(EntityManagerProvider.class);
/**
* entityManagerFactory<p>
* Application-wide EMF built from persistence.xml PU "localdb".
*/
- private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("localdb");
+ //private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("localdb");
+ private EntityManagerFactory entityManagerFactory;
+ @PostConstruct
+ public void init() {
+ try {
+ log.info("Initializing EntityManagerFactory with persistence unit 'localdb'");
+ entityManagerFactory = Persistence.createEntityManagerFactory("localdb");
+ log.info("EntityManagerFactory initialized correctly: {}", entityManagerFactory);
+ } catch (Exception e) {
+ log.error("Error creating EntityManagerFactory for persistence unit 'localdb'", e);
+ entityManagerFactory = null;
+ }
+ }
+
/**
* getEntityManager<p>
* Create a new {@link EntityManager}.
@@ -43,6 +56,17 @@
* @return a new EntityManager; caller must close it
*/
public EntityManager getEntityManager() {
- return entityManagerFactory.createEntityManager();
+ try {
+ if (entityManagerFactory == null) {
+ log.error("EntityManagerFactory is null");
+ return null;
+ }
+ EntityManager em = entityManagerFactory.createEntityManager();
+ log.info("Created EntityManager: {}", em);
+ return em;
+ } catch (Exception e) {
+ log.error("Error creating EntityManager", e);
+ return null;
+ }
}
}
diff --git a/securis/src/main/java/net/curisit/securis/services/UserResource.java b/securis/src/main/java/net/curisit/securis/services/UserResource.java
index 7c4681a..0764f5e 100644
--- a/securis/src/main/java/net/curisit/securis/services/UserResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/UserResource.java
@@ -12,7 +12,6 @@
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
-import jakarta.persistence.PersistenceException;
import jakarta.persistence.TypedQuery;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.Consumes;
@@ -57,7 +56,7 @@
* <p>
* Notes:
* - Uses {@link BasicSecurityContext} authorization via @Securable and @RolesAllowed.
- * - Uses JPA {@link EntityManager} injected through @Context.
+ * - Uses JPA {@link EntityManager} injected through dependency injection.
* - Mutating endpoints are wrapped in @EnsureTransaction to guarantee commit/rollback.
* - Passwords are stored as SHA-256 hashes (see {@link Utils#sha256(String)}).
*
@@ -86,7 +85,7 @@
@Inject private CacheTTL cache;
/** JPA entity manager bound to the current request context. */
- @Context EntityManager em;
+ @Inject EntityManager em;
private static final Logger LOG = LogManager.getLogger(UserResource.class);
@@ -330,7 +329,7 @@
// lastLogin can be set through API (rare), otherwise managed at login
currentUser.setLastLogin(user.getLastLogin());
- em.persist(currentUser);
+ em.merge(currentUser);
clearUserCache(currentUser.getUsername());
return Response.ok(currentUser).build();
@@ -402,35 +401,54 @@
@POST
@Path("/login")
@Produces({ MediaType.APPLICATION_JSON })
+ @EnsureTransaction
public Response login(@FormParam("username") String username, @FormParam("password") String password, @Context HttpServletRequest request) throws SeCurisServiceException {
LOG.info("index session: " + request.getSession());
+ LOG.info("login() called. session={}", request.getSession(false));
+ LOG.info("login() username='{}'", username);
- User user = em.find(User.class, username);
- if (user == null) {
- LOG.error("Unknown username {} used in login service", username);
+ if (username == null || username.trim().isEmpty()) {
+ LOG.error("login() username is null or empty");
throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials");
}
+ if (password == null || password.isEmpty()) {
+ LOG.error("login() password is null or empty for user '{}'", username);
+ throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials");
+ }
+
+ User user = em.find(User.class, username);
+ LOG.info("login() user found? {}", user != null);
+
+ if (user == null) {
+ LOG.error("Unknown username '{}' used in login service", username);
+ throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials");
+ }
+
String securedPassword = Utils.sha256(password);
+ LOG.info("login() hashed password generated? {}", securedPassword != null);
if (securedPassword == null || !securedPassword.equals(user.getPassword())) {
+ LOG.error("Wrong password for user '{}'", username);
throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials");
}
user.setLastLogin(new Date());
- em.getTransaction().begin();
- try {
- em.persist(user);
- em.getTransaction().commit();
- } catch (PersistenceException ex) {
- LOG.error("Error updating last login date for user: {}", username);
- LOG.error(ex);
- em.getTransaction().rollback();
- }
+ em.merge(user);
clearUserCache(username);
- String userFullName = String.format("%s %s", user.getFirstName(), user.getLastName() == null ? "" : user.getLastName()).trim();
+
+ String userFullName = String.format("%s %s",
+ user.getFirstName(),
+ user.getLastName() == null ? "" : user.getLastName()).trim();
+
String tokenAuth = tokenHelper.generateToken(username);
- return Response.ok(Utils.createMap("success", true, "token", tokenAuth, "username", username, "full_name", userFullName)).build();
+ LOG.info("login() success for user '{}'", username);
+
+ return Response.ok(Utils.createMap(
+ "success", true,
+ "token", tokenAuth,
+ "username", username,
+ "full_name", userFullName)).build();
}
/**
diff --git a/securis/src/main/resources/META-INF/persistence.xml b/securis/src/main/resources/META-INF/persistence.xml
index 62abb5f..dcfc8a8 100644
--- a/securis/src/main/resources/META-INF/persistence.xml
+++ b/securis/src/main/resources/META-INF/persistence.xml
@@ -1,22 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
-<persistence version="2.0"
- xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
- <persistence-unit name="localdb" transaction-type="RESOURCE_LOCAL">
- <description>SeCuris LocalDB</description>
- <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
- <non-jta-data-source>java:comp/env/SeCurisDS</non-jta-data-source>
- <shared-cache-mode>NONE</shared-cache-mode>
- <properties>
- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.internal.NoCachingRegionFactory"/>
- <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
- <!-- <property name="hibernate.connection.datasource" value="java:comp/env/jdbc/SeCurisDS" /> -->
+<persistence version="3.0"
+ xmlns="https://jakarta.ee/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
- <property name="hibernate.cache.use_second_level_cache" value="false" />
- <!-- <property name="hibernate.show_sql" value="true" /> -->
-
- <property name="hibernate.format_sql" value="false"/>
- </properties>
+ <persistence-unit name="localdb" transaction-type="RESOURCE_LOCAL">
+ <description>SeCuris LocalDB</description>
+ <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
+ <non-jta-data-source>java:comp/env/SeCurisDS</non-jta-data-source>
+ <shared-cache-mode>NONE</shared-cache-mode>
- </persistence-unit>
+ <properties>
+ <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.internal.NoCachingRegionFactory"/>
+ <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+ <property name="hibernate.cache.use_second_level_cache" value="false"/>
+ <property name="hibernate.format_sql" value="false"/>
+ </properties>
+ </persistence-unit>
</persistence>
\ No newline at end of file
diff --git a/securis/src/main/resources/version.properties b/securis/src/main/resources/version.properties
new file mode 100644
index 0000000..f3f2f9c
--- /dev/null
+++ b/securis/src/main/resources/version.properties
@@ -0,0 +1,5 @@
+version=${project.version}
+majorVersion=3
+minorVersion=0
+incrementalVersion=2
+qualifier=
\ No newline at end of file
diff --git a/securis/src/main/webapp/WEB-INF/web.xml b/securis/src/main/webapp/WEB-INF/web.xml
index 4059657..be1f5fa 100644
--- a/securis/src/main/webapp/WEB-INF/web.xml
+++ b/securis/src/main/webapp/WEB-INF/web.xml
@@ -104,11 +104,13 @@
</description>
<role-name>admin</role-name>
</security-role>
-
- <resource-env-ref>
- <resource-env-ref-name>SeCurisDS</resource-env-ref-name>
- <resource-env-ref-type>jakarta.sql.DataSource</resource-env-ref-type>
- </resource-env-ref>
+
+ <resource-ref>
+ <description>SeCuris DataSource</description>
+ <res-ref-name>SeCurisDS</res-ref-name>
+ <res-type>jakarta.sql.DataSource</res-type>
+ <res-auth>Container</res-auth>
+ </resource-ref>
<!--
<resource-env-ref>
diff --git a/securis/src/main/webapp/src/app/footer.component.ts b/securis/src/main/webapp/src/app/footer.component.ts
index 309167b..2018eaa 100644
--- a/securis/src/main/webapp/src/app/footer.component.ts
+++ b/securis/src/main/webapp/src/app/footer.component.ts
@@ -17,7 +17,7 @@
ngOnInit(): void {
//TODO Move to service
- this.http.get("version", /* workaround to avoid OPTIONS method request*/ new BaseRequestOptions())
+ this.http.get("api/version", /* workaround to avoid OPTIONS method request*/ new BaseRequestOptions())
.map((res) => <string>res.json().version)
.subscribe(
version => this.securisVersion = version,
diff --git a/securis/src/main/webapp/src/app/user.service.ts b/securis/src/main/webapp/src/app/user.service.ts
index 45bb541..95273eb 100644
--- a/securis/src/main/webapp/src/app/user.service.ts
+++ b/securis/src/main/webapp/src/app/user.service.ts
@@ -27,7 +27,7 @@
params.append('username', username);
params.append('password', password);
let options = new RequestOptions({ headers: new Headers({ "Content-Type": "application/x-www-form-urlencoded" })});
- return this.http.post('user/login', params.toString(), options)
+ return this.http.post('api/user/login', params.toString(), options)
.map((resp) => this.mapLogin(resp))
.catch((err) => super.processErrorResponse(err));
}
@@ -47,7 +47,7 @@
}
var token = this.store.get("token");
let option = new RequestOptions({ headers: new Headers({ 'X-SECURIS-TOKEN': token }) });
- return this.http.get('check', option)
+ return this.http.get('api/check', option)
.map((resp) => this.mapCheck(resp))
.catch((err) => super.processErrorResponse(err));
}
--
Gitblit v1.3.2