-
Notifications
You must be signed in to change notification settings - Fork 51
Add failed login attempt tracking and basic lock after 5 attempts #366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -386,29 +386,62 @@ public User superUserAuthenticate(String userName, String password) throws Excep | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return users.get(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public LoginResponseModel userAuthenticateV1(LoginRequestModel loginRequest, String ipAddress, String hostName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public LoginResponseModel userAuthenticateV1(LoginRequestModel loginRequest, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String ipAddress, String hostName) throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LoginResponseModel loginResponseModel = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<User> users = iEMRUserRepositoryCustom.findByUserName(loginRequest.getUserName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<User> users = iEMRUserRepositoryCustom | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .findByUserName(loginRequest.getUserName()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (users.size() == 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| User user = users.get(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| User user = users.get(0); // β FIRST declare user | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // β THEN check failed attempts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Integer failedAttempt = user.getFailedAttempt(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (failedAttempt != null && failedAttempt >= 5) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IEMRException( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Your account has been locked. You can try tomorrow or connect to the administrator." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+408
to
+412
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid hard-coding the lock threshold to This bypasses the configured βοΈ Suggested fix- Integer failedAttempt = user.getFailedAttempt();
+ Integer failedAttempt = user.getFailedAttempt();
+ int maxFailedAttempts = 5;
+ if (failedLoginAttempt != null) {
+ maxFailedAttempts = Integer.parseInt(failedLoginAttempt);
+ }
- if (failedAttempt != null && failedAttempt >= 5) {
+ if (failedAttempt != null && failedAttempt >= maxFailedAttempts) {
throw new IEMRException(
"Your account has been locked. You can try tomorrow or connect to the administrator."
);π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!securePassword.validatePasswordExisting(loginRequest.getPassword(), user.getPassword())) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!securePassword.validatePasswordExisting( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginRequest.getPassword(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.getPassword())) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+403
to
+417
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reintroduce account status validation in This flow currently skips π Suggested fix if (users.size() == 1) {
User user = users.get(0); // β
FIRST declare user
+ checkUserAccountStatus(user);
// β
THEN check failed attempts
Integer failedAttempt = user.getFailedAttempt();π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int currentAttempt = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.getFailedAttempt() == null ? 0 : user.getFailedAttempt(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentAttempt++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.setFailedAttempt(currentAttempt); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iEMRUserRepositoryCustom.save(user); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+419
to
+425
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Failed-attempt update is non-atomic and can lose increments under parallel logins. Concurrent invalid attempts can read the same value and overwrite each other, weakening lockout enforcement. A safer pattern is an atomic DB-side increment (single statement) and using the returned value for lock decisions. π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IEMRException("Invalid username or password"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IEMRException("Invalid username or password"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // β reset on success | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.setFailedAttempt(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iEMRUserRepositoryCustom.save(user); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginResponseModel = userMapper.userDataToLoginResponse(user); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info("Login response is " + loginResponseModel.toString()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<UserServiceRoleMapping> userServiceRoleMappings = getUserServiceRoleMapping( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginResponseModel.getUserID()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginResponseModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .setUserServiceRoleMappings(userServiceRoleMapper.userRoleToLoginUserRole(userServiceRoleMappings)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // loginResponseModel.setHostName(hostName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // loginResponseModel.setIpAddress(ipAddress); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<UserServiceRoleMapping> userServiceRoleMappings = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getUserServiceRoleMapping(loginResponseModel.getUserID()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginResponseModel.setUserServiceRoleMappings( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userServiceRoleMapper.userRoleToLoginUserRole(userServiceRoleMappings)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IEMRException("Invalid username or password"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
Repository: PSMRI/Common-API
Length of output: 25201
Correct the
mappedByreference to match the actual field name inFeedbackDetails.The
mappedBy = "m_User"in User.java references a non-existent field. FeedbackDetails defines the User field asmUser(camelCase), notm_User. This mismatch will cause JPA to fail during entity initialization at runtime.Change
mappedBy = "m_User"tomappedBy = "mUser".π€ Prompt for AI Agents