From eb917b2eb4901874502a598bc46d751010304524 Mon Sep 17 00:00:00 2001 From: SnehaRH Date: Thu, 2 Apr 2026 15:21:35 +0530 Subject: [PATCH 1/8] fix: property values are not fetching after deploying in linux server --- .../common/utils/config/ConfigProperties.java | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/iemr/common/utils/config/ConfigProperties.java b/src/main/java/com/iemr/common/utils/config/ConfigProperties.java index 59b69b82..1dd21fff 100644 --- a/src/main/java/com/iemr/common/utils/config/ConfigProperties.java +++ b/src/main/java/com/iemr/common/utils/config/ConfigProperties.java @@ -140,21 +140,31 @@ public static int getSessionExpiryTime() } public static String getPropertyByName(String propertyName) - { - String result = null; - try - { - if (properties == null) - { - initalizeProperties(); - } - result = properties.getProperty(propertyName).trim(); - } catch (Exception e) - { - logger.error(propertyName + " retrival failed.", e); - } - return result; - } + { + String result = null; + try + { + if (environment != null) + { + result = environment.getProperty(propertyName); + } + if (result == null) + { + if (properties == null) + { + initalizeProperties(); + } + result = properties.getProperty(propertyName).trim(); + } else + { + result = result.trim(); + } + } catch (Exception e) + { + logger.error(propertyName + " retrival failed.", e); + } + return result; + } public static Boolean getBoolean(String propertyName) { From 56e33f86d65629d5933cdb51e02c095eb6bb50ee Mon Sep 17 00:00:00 2001 From: snehar-nd Date: Wed, 13 May 2026 19:55:27 +0530 Subject: [PATCH 2/8] fix: occupationID and educationID not saved during beneficiary update setDemographicDetails() was overwriting occupationName (already set correctly by the mapper from occupationID) with null when no occupation name string was present in the payload. Added null guards so the mapper's resolved name is preserved, and explicitly set occupationId/educationId from i_bendemographics to ensure the IDs always reach Identity-API. Co-Authored-By: Claude Sonnet 4.6 --- .../RegisterBenificiaryServiceImpl.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java b/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java index 82acb58f..d96d49a0 100644 --- a/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java +++ b/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java @@ -155,20 +155,25 @@ else if(null != benificiaryDetails.getI_bendemographics().getReligion()) identityEditDTO.setReligion(benificiaryDetails.getI_bendemographics().getReligionName()); if (null != benificiaryDetails.getOccupation()) { - identityEditDTO.setOccupationName(benificiaryDetails.getOccupation()); - } else if (null != benificiaryDetails.getI_bendemographics() && - null != benificiaryDetails.getI_bendemographics().getOccupation()) { - identityEditDTO.setOccupationName(benificiaryDetails.getI_bendemographics().getOccupation()); - } else { - identityEditDTO.setOccupationName(benificiaryDetails.getOccupationName()); + identityEditDTO.setOccupationName(benificiaryDetails.getOccupation()); + } else if (null != benificiaryDetails.getI_bendemographics().getOccupation()) { + identityEditDTO.setOccupationName(benificiaryDetails.getI_bendemographics().getOccupation()); + } else if (null != benificiaryDetails.getOccupationName()) { + identityEditDTO.setOccupationName(benificiaryDetails.getOccupationName()); + } + if (null != benificiaryDetails.getI_bendemographics().getOccupationID()) { + identityEditDTO.setOccupationId(benificiaryDetails.getI_bendemographics().getOccupationID()); } if (null != benificiaryDetails.getEducation()) { - identityEditDTO.setEducation(benificiaryDetails.getEducation()); + identityEditDTO.setEducation(benificiaryDetails.getEducation()); } else if (null != benificiaryDetails.getI_bendemographics() && - null != benificiaryDetails.getI_bendemographics().getEducationName()) { - identityEditDTO.setEducation(benificiaryDetails.getI_bendemographics().getEducationName()); - } + null != benificiaryDetails.getI_bendemographics().getEducationName()) { + identityEditDTO.setEducation(benificiaryDetails.getI_bendemographics().getEducationName()); + } + if (null != benificiaryDetails.getI_bendemographics().getEducationID()) { + identityEditDTO.setEducationId(benificiaryDetails.getI_bendemographics().getEducationID()); + } if(null != benificiaryDetails.getIncomeStatus()) identityEditDTO.setIncomeStatus(benificiaryDetails.getIncomeStatus()); else From c57450654eda6f6cf074f9cd1f69e2a26d4fed9a Mon Sep 17 00:00:00 2001 From: snehar-nd Date: Wed, 13 May 2026 20:28:58 +0530 Subject: [PATCH 3/8] Revert "fix: property values are not fetching after deploying in linux server" This reverts commit eb917b2eb4901874502a598bc46d751010304524. --- .../common/utils/config/ConfigProperties.java | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/iemr/common/utils/config/ConfigProperties.java b/src/main/java/com/iemr/common/utils/config/ConfigProperties.java index 1dd21fff..59b69b82 100644 --- a/src/main/java/com/iemr/common/utils/config/ConfigProperties.java +++ b/src/main/java/com/iemr/common/utils/config/ConfigProperties.java @@ -140,31 +140,21 @@ public static int getSessionExpiryTime() } public static String getPropertyByName(String propertyName) - { - String result = null; - try - { - if (environment != null) - { - result = environment.getProperty(propertyName); - } - if (result == null) - { - if (properties == null) - { - initalizeProperties(); - } - result = properties.getProperty(propertyName).trim(); - } else - { - result = result.trim(); - } - } catch (Exception e) - { - logger.error(propertyName + " retrival failed.", e); - } - return result; - } + { + String result = null; + try + { + if (properties == null) + { + initalizeProperties(); + } + result = properties.getProperty(propertyName).trim(); + } catch (Exception e) + { + logger.error(propertyName + " retrival failed.", e); + } + return result; + } public static Boolean getBoolean(String propertyName) { From 544d557a167dc67c737b27a34c405099fb99d79a Mon Sep 17 00:00:00 2001 From: snehar-nd Date: Thu, 14 May 2026 14:37:20 +0530 Subject: [PATCH 4/8] fix: concurrent session logout not invalidating JWT in first system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit logOutUserFromConcurrentSession only cleaned up old-style Redis session keys but never added the displaced user's JWT to the denylist. Because JwtUserIdValidationFilter validates solely via JWT signature and the denylist, System 1's token remained valid and all APIs returned 200 after System 2 forced a concurrent login. Fix: store a username→JTI mapping in Redis at login time; during concurrent-session logout, look up the JTI and add it to the denylist and evict the user_ cache so the next request from System 1 is rejected with 401 and the frontend shows the session-expiry message. Co-Authored-By: Claude Sonnet 4.6 --- .../controller/users/IEMRAdminController.java | 32 +++++++++++++++++++ .../java/com/iemr/common/utils/JwtUtil.java | 4 +++ 2 files changed, 36 insertions(+) diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java index 701add24..c76fc1df 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -197,6 +197,15 @@ public String userAuthenticate( user.setUserName(mUser.get(0).getUserName()); logger.info("UserAgentUtil isMobile : " + isMobile); + // Store username → JTI mapping so concurrent-session logout can denylist this token + String accessJti = jwtUtil.getJtiFromToken(jwtToken); + redisTemplate.opsForValue().set( + "jti:" + m_User.getUserName().trim().toLowerCase(), + accessJti + "|" + mUser.get(0).getUserID(), + jwtUtil.getAccessTokenExpiration(), + TimeUnit.MILLISECONDS + ); + if (isMobile) { refreshToken = jwtUtil.generateRefreshToken(m_User.getUserName(), user.getUserID().toString()); logger.debug("Refresh token generated successfully for user: {}", user.getUserName()); @@ -387,6 +396,20 @@ public String logOutUserFromConcurrentSession( if (previousTokenFromRedis != null) { deleteSessionObjectByGettingSessionDetails(previousTokenFromRedis); sessionObject.deleteSessionObject(previousTokenFromRedis); + + // Denylist the active JWT so the first system's requests are immediately rejected + String usernameKey = mUsers.get(0).getUserName().trim().toLowerCase(); + String jtiData = (String) redisTemplate.opsForValue().get("jti:" + usernameKey); + if (jtiData != null) { + String[] parts = jtiData.split("\\|", 2); + String jti = parts[0]; + tokenDenylist.addTokenToDenylist(jti, jwtUtil.getAccessTokenExpiration()); + if (parts.length > 1) { + redisTemplate.delete("user_" + parts[1]); + } + redisTemplate.delete("jti:" + usernameKey); + } + response.setResponse("User successfully logged out"); } else{ logger.error("Unable to fetch session from redis"); @@ -522,6 +545,15 @@ public String superUserAuthenticate( isMobile = UserAgentUtil.isMobileDevice(userAgent); logger.info("UserAgentUtil isMobile : " + isMobile); + // Store username → JTI mapping so concurrent-session logout can denylist this token + String accessJti = jwtUtil.getJtiFromToken(jwtToken); + redisTemplate.opsForValue().set( + "jti:" + m_User.getUserName().trim().toLowerCase(), + accessJti + "|" + mUser.getUserID(), + jwtUtil.getAccessTokenExpiration(), + TimeUnit.MILLISECONDS + ); + if (isMobile) { refreshToken = jwtUtil.generateRefreshToken(m_User.getUserName(), user.getUserID().toString()); logger.debug("Refresh token generated successfully for user: {}", user.getUserName()); diff --git a/src/main/java/com/iemr/common/utils/JwtUtil.java b/src/main/java/com/iemr/common/utils/JwtUtil.java index 5d37a990..d7f6c270 100644 --- a/src/main/java/com/iemr/common/utils/JwtUtil.java +++ b/src/main/java/com/iemr/common/utils/JwtUtil.java @@ -163,6 +163,10 @@ public long getRefreshTokenExpiration() { return REFRESH_EXPIRATION_TIME; } + public long getAccessTokenExpiration() { + return ACCESS_EXPIRATION_TIME; + } + /** * Extract user ID from JWT token in the request (checks header and cookie) * @param request the HTTP request From 80fa0e5e65d7357c441dda42a43ed70b2a37ea38 Mon Sep 17 00:00:00 2001 From: snehar-nd Date: Thu, 14 May 2026 15:54:47 +0530 Subject: [PATCH 5/8] fix: concurrent session logout not invalidating JWT on first system logOutUserFromConcurrentSession only cleaned up old-style Redis session keys but never added the displaced user's JWT to the denylist. Because JwtUserIdValidationFilter validates solely via JWT signature and the denylist, System 1's token remained valid and all APIs returned 200 after System 2 forced a concurrent login. The root serialization bug: redisTemplate value serializer is Jackson2JsonRedisSerializer, so storing a plain String JTI caused a deserialization failure on retrieval. Fixed by using the existing StringRedisTemplate bean for the jti: key operations. Fix: - Store username->JTI mapping via StringRedisTemplate at login (both userAuthenticate and superUserAuthenticate) - On concurrent-session logout, retrieve the JTI, add it to the denylist, evict user_ from User cache, and clean up jti: key - Add getAccessTokenExpiration() to JwtUtil to supply the TTL Co-Authored-By: Claude Sonnet 4.6 --- .../controller/users/IEMRAdminController.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java index c76fc1df..a96e70bc 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -36,6 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -95,6 +96,8 @@ public class IEMRAdminController { private CookieUtil cookieUtil; @Autowired private RedisTemplate redisTemplate; + @Autowired + private StringRedisTemplate stringRedisTemplate; private AESUtil aesUtil; @@ -197,11 +200,10 @@ public String userAuthenticate( user.setUserName(mUser.get(0).getUserName()); logger.info("UserAgentUtil isMobile : " + isMobile); - // Store username → JTI mapping so concurrent-session logout can denylist this token - String accessJti = jwtUtil.getJtiFromToken(jwtToken); - redisTemplate.opsForValue().set( + // Store username -> JTI mapping so concurrent-session logout can denylist this token + stringRedisTemplate.opsForValue().set( "jti:" + m_User.getUserName().trim().toLowerCase(), - accessJti + "|" + mUser.get(0).getUserID(), + jwtUtil.getJtiFromToken(jwtToken) + "|" + mUser.get(0).getUserID(), jwtUtil.getAccessTokenExpiration(), TimeUnit.MILLISECONDS ); @@ -397,17 +399,16 @@ public String logOutUserFromConcurrentSession( deleteSessionObjectByGettingSessionDetails(previousTokenFromRedis); sessionObject.deleteSessionObject(previousTokenFromRedis); - // Denylist the active JWT so the first system's requests are immediately rejected + // Denylist the active JWT so System 1's requests are immediately rejected String usernameKey = mUsers.get(0).getUserName().trim().toLowerCase(); - String jtiData = (String) redisTemplate.opsForValue().get("jti:" + usernameKey); + String jtiData = stringRedisTemplate.opsForValue().get("jti:" + usernameKey); if (jtiData != null) { String[] parts = jtiData.split("\\|", 2); - String jti = parts[0]; - tokenDenylist.addTokenToDenylist(jti, jwtUtil.getAccessTokenExpiration()); + tokenDenylist.addTokenToDenylist(parts[0], jwtUtil.getAccessTokenExpiration()); if (parts.length > 1) { redisTemplate.delete("user_" + parts[1]); } - redisTemplate.delete("jti:" + usernameKey); + stringRedisTemplate.delete("jti:" + usernameKey); } response.setResponse("User successfully logged out"); @@ -545,11 +546,10 @@ public String superUserAuthenticate( isMobile = UserAgentUtil.isMobileDevice(userAgent); logger.info("UserAgentUtil isMobile : " + isMobile); - // Store username → JTI mapping so concurrent-session logout can denylist this token - String accessJti = jwtUtil.getJtiFromToken(jwtToken); - redisTemplate.opsForValue().set( + // Store username -> JTI mapping so concurrent-session logout can denylist this token + stringRedisTemplate.opsForValue().set( "jti:" + m_User.getUserName().trim().toLowerCase(), - accessJti + "|" + mUser.getUserID(), + jwtUtil.getJtiFromToken(jwtToken) + "|" + mUser.getUserID(), jwtUtil.getAccessTokenExpiration(), TimeUnit.MILLISECONDS ); From ccab7debb3148e5196bbd87667fc23a97c41efd8 Mon Sep 17 00:00:00 2001 From: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Date: Mon, 18 May 2026 12:54:31 +0530 Subject: [PATCH 6/8] fix(security): remove PII from JWT token for mobile logins (#413) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add generateSecureToken/generateSecureRefreshToken methods that use userId as sub instead of username. Mobile logins (okhttp User-Agent) use the secure token — web logins remain unchanged for backward compatibility. Other services will be migrated one by one. Co-authored-by: Claude Sonnet 4.6 --- .../controller/users/IEMRAdminController.java | 9 +++++--- .../java/com/iemr/common/utils/JwtUtil.java | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java index a96e70bc..845fe890 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -193,7 +193,10 @@ public String userAuthenticate( String jwtToken = null; String refreshToken = null; if (mUser.size() == 1) { - jwtToken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString()); + String userIdStr = mUser.get(0).getUserID().toString(); + jwtToken = isMobile + ? jwtUtil.generateSecureToken(userIdStr) + : jwtUtil.generateToken(m_User.getUserName(), userIdStr); User user = new User(); // Assuming the Users class exists user.setUserID(mUser.get(0).getUserID()); @@ -209,7 +212,7 @@ public String userAuthenticate( ); if (isMobile) { - refreshToken = jwtUtil.generateRefreshToken(m_User.getUserName(), user.getUserID().toString()); + refreshToken = jwtUtil.generateSecureRefreshToken(user.getUserID().toString()); logger.debug("Refresh token generated successfully for user: {}", user.getUserName()); String jti = jwtUtil.getJtiFromToken(refreshToken); redisTemplate.opsForValue().set( @@ -555,7 +558,7 @@ public String superUserAuthenticate( ); if (isMobile) { - refreshToken = jwtUtil.generateRefreshToken(m_User.getUserName(), user.getUserID().toString()); + refreshToken = jwtUtil.generateSecureRefreshToken(user.getUserID().toString()); logger.debug("Refresh token generated successfully for user: {}", user.getUserName()); String jti = jwtUtil.getJtiFromToken(refreshToken); redisTemplate.opsForValue().set( diff --git a/src/main/java/com/iemr/common/utils/JwtUtil.java b/src/main/java/com/iemr/common/utils/JwtUtil.java index d7f6c270..98ff7b7b 100644 --- a/src/main/java/com/iemr/common/utils/JwtUtil.java +++ b/src/main/java/com/iemr/common/utils/JwtUtil.java @@ -46,6 +46,27 @@ public String generateToken(String username, String userId) { return buildToken(username, userId, "access", ACCESS_EXPIRATION_TIME); } + // Mobile login: token without PII in sub + public String generateSecureToken(String userId) { + return buildSecureToken(userId, "access", ACCESS_EXPIRATION_TIME); + } + + public String generateSecureRefreshToken(String userId) { + return buildSecureToken(userId, "refresh", REFRESH_EXPIRATION_TIME); + } + + private String buildSecureToken(String userId, String tokenType, long expiration) { + return Jwts.builder() + .subject(userId) + .claim("userId", userId) + .claim("token_type", tokenType) + .id(UUID.randomUUID().toString()) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(getSigningKey()) + .compact(); + } + /** * Generate a refresh token. * From 2c23d9374afc6f3c4d88873a0627fd6b32e80be3 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 29 May 2026 12:25:25 +0530 Subject: [PATCH 7/8] Implement feature multiple login attempt --- .../controller/users/IEMRAdminController.java | 89 ++++++++++++++++++- .../service/users/IEMRAdminUserService.java | 2 +- .../users/IEMRAdminUserServiceImpl.java | 5 ++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java index 845fe890..ec0298e8 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -171,7 +171,93 @@ public String userAuthenticate( } String decryptPassword = aesUtil.decrypt("Piramal12Piramal", m_User.getPassword()); - List mUser = iemrAdminUserServiceImpl.userAuthenticate(m_User.getUserName(), decryptPassword); + // Fetch user + List existingUser = iemrAdminUserServiceImpl.userExitsCheck(m_User.getUserName()); + + /* + * ========================================= + * ACCOUNT LOCK CHECK + * ========================================= + */ + if(!existingUser.isEmpty()){ + if (existingUser.get(0) != null + && existingUser.get(0).getFailedAttempt() != null + && existingUser.get(0).getFailedAttempt() >= 5) { + + throw new IEMRException( + "Your account has been locked due to multiple failed login attempts. Please contact administrator."); + } + } + + + List mUser = iemrAdminUserServiceImpl + .userAuthenticate(m_User.getUserName(), decryptPassword); + + /* + * ========================================= + * FAILED LOGIN ATTEMPT LOGIC + * ========================================= + */ + if (mUser == null || mUser.isEmpty()) { + if(!existingUser.isEmpty()){ + if (existingUser != null) { + + Integer failedAttempt = existingUser.get(0).getFailedAttempt() != null + ? existingUser.get(0).getFailedAttempt() + : 0; + + failedAttempt++; + + existingUser.get(0).setFailedAttempt(failedAttempt); + + iemrAdminUserServiceImpl.save(existingUser.get(0)); + + int remainingAttempts = 5 - failedAttempt; + + // Lock account on 5th attempt + if (failedAttempt >= 5) { + + + + response.setError(new IEMRException( + "Your account has been locked due to multiple failed login attempts.")); + return response.toString(); + } + + // Warning on 3rd attempt + if (failedAttempt == 4) { + + + response.setError(new IEMRException( + "Invalid username or password. Remaining attempts: " + + remainingAttempts + + ". If you enter wrong username or password again, your account will be locked.")); + return response.toString(); + } + + + response.setError(new IEMRException( + "Invalid username or password. Remaining attempts: " + + remainingAttempts)); + return response.toString(); + + } + } + + + throw new IEMRException("Invalid username or password."); + } + + /* + * ========================================= + * RESET FAILED ATTEMPTS ON SUCCESS LOGIN + * ========================================= + */ + User loggedInUser = mUser.get(0); + + loggedInUser.setFailedAttempt(0); + + iemrAdminUserServiceImpl.save(loggedInUser); JSONObject resMap = new JSONObject(); JSONObject serviceRoleMultiMap = new JSONObject(); JSONObject serviceRoleMap = new JSONObject(); @@ -253,7 +339,6 @@ public String userAuthenticate( // Facility data for ALL users - common pattern, empty if not applicable try { if (mUser.size() == 1) { - User loggedInUser = mUser.get(0); String userRoleName = ""; if (loggedInUser.getM_UserServiceRoleMapping() != null) { for (UserServiceRoleMapping usrm : loggedInUser.getM_UserServiceRoleMapping()) { diff --git a/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java b/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java index 26b7bb15..1db05322 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java @@ -126,5 +126,5 @@ public List getUserServiceRoleMappingForProvider(Integ List findUserIdByUserName(String userName) throws IEMRException; - + User save(User loggedInUser); } diff --git a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java index 71d72c97..3d20be1b 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java @@ -1230,4 +1230,9 @@ public List findUserIdByUserName(String userName) { return iEMRUserRepositoryCustom.findUserName(userName); } + + @Override + public User save(User loggedInUser) { + return iEMRUserRepositoryCustom.save(loggedInUser); + } } From fe3336a170ac1bf3d2271d26665fc5888b5dbfdc Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Fri, 29 May 2026 13:09:15 +0530 Subject: [PATCH 8/8] Implement feature multiple login attempt --- .../controller/users/IEMRAdminController.java | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java index ec0298e8..b3644743 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -198,54 +198,49 @@ public String userAuthenticate( * FAILED LOGIN ATTEMPT LOGIC * ========================================= */ - if (mUser == null || mUser.isEmpty()) { - if(!existingUser.isEmpty()){ - if (existingUser != null) { - - Integer failedAttempt = existingUser.get(0).getFailedAttempt() != null - ? existingUser.get(0).getFailedAttempt() - : 0; - - failedAttempt++; + if(!existingUser.isEmpty()){ + if (existingUser != null) { - existingUser.get(0).setFailedAttempt(failedAttempt); + Integer failedAttempt = existingUser.get(0).getFailedAttempt() != null + ? existingUser.get(0).getFailedAttempt() + : 0; - iemrAdminUserServiceImpl.save(existingUser.get(0)); + failedAttempt++; - int remainingAttempts = 5 - failedAttempt; + existingUser.get(0).setFailedAttempt(failedAttempt); - // Lock account on 5th attempt - if (failedAttempt >= 5) { + iemrAdminUserServiceImpl.save(existingUser.get(0)); + int remainingAttempts = 5 - failedAttempt; + // Lock account on 5th attempt + if (failedAttempt >= 5) { - response.setError(new IEMRException( - "Your account has been locked due to multiple failed login attempts.")); - return response.toString(); - } - // Warning on 3rd attempt - if (failedAttempt == 4) { + response.setError(new IEMRException( + "Your account has been locked due to multiple failed login attempts.")); + return response.toString(); + } - response.setError(new IEMRException( - "Invalid username or password. Remaining attempts: " - + remainingAttempts - + ". If you enter wrong username or password again, your account will be locked.")); - return response.toString(); - } + // Warning on 3rd attempt + if (failedAttempt == 4) { - response.setError(new IEMRException( - "Invalid username or password. Remaining attempts: " - + remainingAttempts)); - return response.toString(); + response.setError(new IEMRException( + "Invalid username or password. Remaining attempts: " + + remainingAttempts + + ". If you enter wrong username or password again, your account will be locked.")); + return response.toString(); + } - } - } + response.setError(new IEMRException( + "Invalid username or password. Remaining attempts: " + + remainingAttempts)); + return response.toString(); - throw new IEMRException("Invalid username or password."); + } } /*