diff --git a/src/main/java/com/iemr/common/data/users/User.java b/src/main/java/com/iemr/common/data/users/User.java index 275b0ec6..cf0d19ac 100644 --- a/src/main/java/com/iemr/common/data/users/User.java +++ b/src/main/java/com/iemr/common/data/users/User.java @@ -209,6 +209,10 @@ public class User implements Serializable { @Column(name = "failed_attempt") private Integer failedAttempt; + @Expose + @Column(name = "lock_timestamp") + private Timestamp lockTimestamp; + @Expose @Column(name = "dhistoken") private String dhistoken; 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..021ab74c 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java @@ -222,7 +222,27 @@ public void setValidator(Validator validator) { private void checkUserAccountStatus(User user) throws IEMRException { if (user.getDeleted()) { - throw new IEMRException("Your account is locked or de-activated. Please contact administrator"); + // check if account was locked due to failed attempts and lock has expired + if (user.getLockTimestamp() != null) { + java.time.LocalDate lockDate = user.getLockTimestamp().toLocalDateTime().toLocalDate(); + java.time.LocalDate today = java.time.LocalDate.now(); + + if (today.isAfter(lockDate)) { + // auto-unlock: it's a new day after the lock date + user.setDeleted(false); + user.setFailedAttempt(0); + user.setLockTimestamp(null); + iEMRUserRepositoryCustom.save(user); + logger.info("Account auto-unlocked for user {} (locked on {}, unlocked on {})", + user.getUserName(), lockDate, today); + return; + } else { + throw new IEMRException( + "Your account has been locked. You can try tomorrow or connect to the administrator."); + } + } + throw new IEMRException( + "Your account is locked or de-activated. Please contact administrator"); } else if (user.getStatusID() > 2) { throw new IEMRException("Your account is not active. Please contact administrator"); } @@ -265,6 +285,10 @@ public List userAuthenticate(String userName, String password) throws Exce checkUserAccountStatus(user); iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 0) { + // if already locked/deleted, don't overwrite lock timestamp + if (Boolean.TRUE.equals(user.getDeleted())) { + checkUserAccountStatus(user); + } if (user.getFailedAttempt() + 1 < failedAttempt) { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); @@ -273,24 +297,26 @@ public List userAuthenticate(String userName, String password) throws Exce } else if (user.getFailedAttempt() + 1 >= failedAttempt) { user.setFailedAttempt(user.getFailedAttempt() + 1); user.setDeleted(true); + user.setLockTimestamp(new java.sql.Timestamp(System.currentTimeMillis())); user = iEMRUserRepositoryCustom.save(user); logger.warn("User Account has been locked after reaching the limit of {} failed login attempts.", ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Invalid username or password. Please contact administrator."); + "Your account has been locked. You can try tomorrow or connect to the administrator."); } else { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); logger.warn("Failed login attempt {} of {} for a user account.", user.getFailedAttempt(), ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Invalid username or password. Please contact administrator."); + "Invalid username or password."); } } else { checkUserAccountStatus(user); if (user.getFailedAttempt() != 0) { user.setFailedAttempt(0); + user.setLockTimestamp(null); user = iEMRUserRepositoryCustom.save(user); } } @@ -318,7 +344,7 @@ private void resetUserLoginFailedAttempt(User user) throws IEMRException { */ @Override public User superUserAuthenticate(String userName, String password) throws Exception { - List users = iEMRUserRepositoryCustom.findByUserName(userName); + List users = iEMRUserRepositoryCustom.findByUserNameNew(userName); if (users.size() != 1) { throw new IEMRException("Invalid username or password"); @@ -351,6 +377,10 @@ public User superUserAuthenticate(String userName, String password) throws Excep iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 0) { + // if already locked/deleted, don't overwrite lock timestamp + if (Boolean.TRUE.equals(user.getDeleted())) { + checkUserAccountStatus(user); + } if (user.getFailedAttempt() + 1 < failedAttempt) { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); @@ -359,24 +389,26 @@ public User superUserAuthenticate(String userName, String password) throws Excep } else if (user.getFailedAttempt() + 1 >= failedAttempt) { user.setFailedAttempt(user.getFailedAttempt() + 1); user.setDeleted(true); + user.setLockTimestamp(new java.sql.Timestamp(System.currentTimeMillis())); user = iEMRUserRepositoryCustom.save(user); logger.warn("User Account has been locked after reaching the limit of {} failed login attempts.", ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Invalid username or password. Please contact administrator."); + "Your account has been locked. You can try tomorrow or connect to the administrator."); } else { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); logger.warn("Failed login attempt {} of {} for a user account.", user.getFailedAttempt(), ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Invalid username or password. Please contact administrator."); + "Invalid username or password."); } } else { checkUserAccountStatus(user); if (user.getFailedAttempt() != 0) { user.setFailedAttempt(0); + user.setLockTimestamp(null); user = iEMRUserRepositoryCustom.save(user); } } diff --git a/src/main/resources/db/migration/V1__add_lock_timestamp_to_m_user.sql b/src/main/resources/db/migration/V1__add_lock_timestamp_to_m_user.sql new file mode 100644 index 00000000..b59f69c8 --- /dev/null +++ b/src/main/resources/db/migration/V1__add_lock_timestamp_to_m_user.sql @@ -0,0 +1,5 @@ +-- Add lock_timestamp column to m_user table for time-bound account locking +-- When a user gets locked after 5 failed login attempts, this stores when +-- the lock happened. After 24 hours, the account auto-unlocks on next login. + +ALTER TABLE m_user ADD COLUMN lock_timestamp DATETIME NULL DEFAULT NULL;