securis/pom.xml
.. .. @@ -176,6 +176,12 @@ 176 176 </dependencies> 177 177 178 178 <build> 179 + <resources>180 + <resource>181 + <directory>src/main/resources</directory>182 + <filtering>true</filtering>183 + </resource>184 + </resources>179 185 <plugins> 180 186 <plugin> 181 187 <groupId>org.apache.maven.plugins</groupId> securis/src/main/java/net/curisit/securis/ioc/EntityManagerProvider.java
.. .. @@ -3,6 +3,7 @@ 3 3 */ 4 4 package net.curisit.securis.ioc; 5 5 6 +import jakarta.annotation.PostConstruct;6 7 import jakarta.enterprise.context.ApplicationScoped; 7 8 import jakarta.persistence.EntityManager; 8 9 import jakarta.persistence.EntityManagerFactory; .. .. @@ -27,15 +28,27 @@ 27 28 @ApplicationScoped 28 29 public class EntityManagerProvider { 29 30 30 - @SuppressWarnings("unused")31 31 private static final Logger log = LogManager.getLogger(EntityManagerProvider.class); 32 32 33 33 /** 34 34 * entityManagerFactory<p> 35 35 * Application-wide EMF built from persistence.xml PU "localdb". 36 36 */ 37 - private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("localdb");37 + //private final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("localdb");38 + private EntityManagerFactory entityManagerFactory;38 39 40 + @PostConstruct41 + public void init() {42 + try {43 + log.info("Initializing EntityManagerFactory with persistence unit 'localdb'");44 + entityManagerFactory = Persistence.createEntityManagerFactory("localdb");45 + log.info("EntityManagerFactory initialized correctly: {}", entityManagerFactory);46 + } catch (Exception e) {47 + log.error("Error creating EntityManagerFactory for persistence unit 'localdb'", e);48 + entityManagerFactory = null;49 + }50 + }51 +39 52 /** 40 53 * getEntityManager<p> 41 54 * Create a new {@link EntityManager}. .. .. @@ -43,6 +56,17 @@ 43 56 * @return a new EntityManager; caller must close it 44 57 */ 45 58 public EntityManager getEntityManager() { 46 - return entityManagerFactory.createEntityManager();59 + try {60 + if (entityManagerFactory == null) {61 + log.error("EntityManagerFactory is null");62 + return null;63 + }64 + EntityManager em = entityManagerFactory.createEntityManager();65 + log.info("Created EntityManager: {}", em);66 + return em;67 + } catch (Exception e) {68 + log.error("Error creating EntityManager", e);69 + return null;70 + }47 71 } 48 72 } securis/src/main/java/net/curisit/securis/services/UserResource.java
.. .. @@ -12,7 +12,6 @@ 12 12 import jakarta.enterprise.context.RequestScoped; 13 13 import jakarta.inject.Inject; 14 14 import jakarta.persistence.EntityManager; 15 -import jakarta.persistence.PersistenceException;16 15 import jakarta.persistence.TypedQuery; 17 16 import jakarta.servlet.http.HttpServletRequest; 18 17 import jakarta.ws.rs.Consumes; .. .. @@ -57,7 +56,7 @@ 57 56 * <p> 58 57 * Notes: 59 58 * - Uses {@link BasicSecurityContext} authorization via @Securable and @RolesAllowed. 60 - * - Uses JPA {@link EntityManager} injected through @Context.59 + * - Uses JPA {@link EntityManager} injected through dependency injection.61 60 * - Mutating endpoints are wrapped in @EnsureTransaction to guarantee commit/rollback. 62 61 * - Passwords are stored as SHA-256 hashes (see {@link Utils#sha256(String)}). 63 62 * .. .. @@ -86,7 +85,7 @@ 86 85 @Inject private CacheTTL cache; 87 86 88 87 /** JPA entity manager bound to the current request context. */ 89 - @Context EntityManager em;88 + @Inject EntityManager em;90 89 91 90 private static final Logger LOG = LogManager.getLogger(UserResource.class); 92 91 .. .. @@ -330,7 +329,7 @@ 330 329 // lastLogin can be set through API (rare), otherwise managed at login 331 330 currentUser.setLastLogin(user.getLastLogin()); 332 331 333 - em.persist(currentUser);332 + em.merge(currentUser);334 333 clearUserCache(currentUser.getUsername()); 335 334 336 335 return Response.ok(currentUser).build(); .. .. @@ -402,35 +401,54 @@ 402 401 @POST 403 402 @Path("/login") 404 403 @Produces({ MediaType.APPLICATION_JSON }) 404 + @EnsureTransaction405 405 public Response login(@FormParam("username") String username, @FormParam("password") String password, @Context HttpServletRequest request) throws SeCurisServiceException { 406 406 LOG.info("index session: " + request.getSession()); 407 + LOG.info("login() called. session={}", request.getSession(false));408 + LOG.info("login() username='{}'", username);407 409 408 - User user = em.find(User.class, username);409 - if (user == null) {410 - LOG.error("Unknown username {} used in login service", username);410 + if (username == null || username.trim().isEmpty()) {411 + LOG.error("login() username is null or empty");411 412 throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials"); 412 413 } 414 + if (password == null || password.isEmpty()) {415 + LOG.error("login() password is null or empty for user '{}'", username);416 + throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials");417 + }418 +419 + User user = em.find(User.class, username);420 + LOG.info("login() user found? {}", user != null);421 +422 + if (user == null) {423 + LOG.error("Unknown username '{}' used in login service", username);424 + throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials");425 + }426 +413 427 String securedPassword = Utils.sha256(password); 428 + LOG.info("login() hashed password generated? {}", securedPassword != null);414 429 415 430 if (securedPassword == null || !securedPassword.equals(user.getPassword())) { 431 + LOG.error("Wrong password for user '{}'", username);416 432 throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Wrong credentials"); 417 433 } 418 434 419 435 user.setLastLogin(new Date()); 420 - em.getTransaction().begin();421 - try {422 - em.persist(user);423 - em.getTransaction().commit();424 - } catch (PersistenceException ex) {425 - LOG.error("Error updating last login date for user: {}", username);426 - LOG.error(ex);427 - em.getTransaction().rollback();428 - }436 + em.merge(user);429 437 430 438 clearUserCache(username); 431 - String userFullName = String.format("%s %s", user.getFirstName(), user.getLastName() == null ? "" : user.getLastName()).trim();439 +440 + String userFullName = String.format("%s %s",441 + user.getFirstName(),442 + user.getLastName() == null ? "" : user.getLastName()).trim();443 +432 444 String tokenAuth = tokenHelper.generateToken(username); 433 - return Response.ok(Utils.createMap("success", true, "token", tokenAuth, "username", username, "full_name", userFullName)).build();445 + LOG.info("login() success for user '{}'", username);446 +447 + return Response.ok(Utils.createMap(448 + "success", true,449 + "token", tokenAuth,450 + "username", username,451 + "full_name", userFullName)).build();434 452 } 435 453 436 454 /** securis/src/main/resources/META-INF/persistence.xml
.. .. @@ -1,22 +1,20 @@ 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 -<persistence version="2.0"3 - xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 - xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">5 - <persistence-unit name="localdb" transaction-type="RESOURCE_LOCAL">6 - <description>SeCuris LocalDB</description>7 - <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>8 - <non-jta-data-source>java:comp/env/SeCurisDS</non-jta-data-source>9 - <shared-cache-mode>NONE</shared-cache-mode>10 - <properties>11 - <property name="hibernate.cache.provider_class" value="org.hibernate.cache.internal.NoCachingRegionFactory"/>12 - <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />13 - <!-- <property name="hibernate.connection.datasource" value="java:comp/env/jdbc/SeCurisDS" /> -->2 +<persistence version="3.0"3 + xmlns="https://jakarta.ee/xml/ns/persistence"4 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"5 + xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">14 6 15 - <property name="hibernate.cache.use_second_level_cache" value="false" />16 - <!-- <property name="hibernate.show_sql" value="true" /> -->17 -18 - <property name="hibernate.format_sql" value="false"/>19 - </properties>7 + <persistence-unit name="localdb" transaction-type="RESOURCE_LOCAL">8 + <description>SeCuris LocalDB</description>9 + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>10 + <non-jta-data-source>java:comp/env/SeCurisDS</non-jta-data-source>11 + <shared-cache-mode>NONE</shared-cache-mode>20 12 21 - </persistence-unit>13 + <properties>14 + <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.internal.NoCachingRegionFactory"/>15 + <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>16 + <property name="hibernate.cache.use_second_level_cache" value="false"/>17 + <property name="hibernate.format_sql" value="false"/>18 + </properties>19 + </persistence-unit>22 20 </persistence> securis/src/main/resources/version.properties
.. .. @@ -0,0 +1,5 @@ 1 +version=${project.version}2 +majorVersion=33 +minorVersion=04 +incrementalVersion=25 +qualifier=securis/src/main/webapp/WEB-INF/web.xml
.. .. @@ -104,11 +104,13 @@ 104 104 </description> 105 105 <role-name>admin</role-name> 106 106 </security-role> 107 -108 - <resource-env-ref>109 - <resource-env-ref-name>SeCurisDS</resource-env-ref-name>110 - <resource-env-ref-type>jakarta.sql.DataSource</resource-env-ref-type>111 - </resource-env-ref>107 +108 + <resource-ref>109 + <description>SeCuris DataSource</description>110 + <res-ref-name>SeCurisDS</res-ref-name>111 + <res-type>jakarta.sql.DataSource</res-type>112 + <res-auth>Container</res-auth>113 + </resource-ref>112 114 113 115 <!-- 114 116 <resource-env-ref>
.. .. @@ -17,7 +17,7 @@ 17 17 18 18 ngOnInit(): void { 19 19 //TODO Move to service 20 - this.http.get("version", /* workaround to avoid OPTIONS method request*/ new BaseRequestOptions())20 + this.http.get("api/version", /* workaround to avoid OPTIONS method request*/ new BaseRequestOptions())21 21 .map((res) => <string>res.json().version) 22 22 .subscribe( 23 23 version => this.securisVersion = version, securis/src/main/webapp/src/app/user.service.ts
.. .. @@ -27,7 +27,7 @@ 27 27 params.append('username', username); 28 28 params.append('password', password); 29 29 let options = new RequestOptions({ headers: new Headers({ "Content-Type": "application/x-www-form-urlencoded" })}); 30 - return this.http.post('user/login', params.toString(), options)30 + return this.http.post('api/user/login', params.toString(), options)31 31 .map((resp) => this.mapLogin(resp)) 32 32 .catch((err) => super.processErrorResponse(err)); 33 33 } .. .. @@ -47,7 +47,7 @@ 47 47 } 48 48 var token = this.store.get("token"); 49 49 let option = new RequestOptions({ headers: new Headers({ 'X-SECURIS-TOKEN': token }) }); 50 - return this.http.get('check', option)50 + return this.http.get('api/check', option)51 51 .map((resp) => this.mapCheck(resp)) 52 52 .catch((err) => super.processErrorResponse(err)); 53 53 }