Skip to content

Commit 710f70f

Browse files
author
Varun Deep Saini
committed
AMM-118: Add time-based account lockout with auto-unlock
Signed-off-by: Varun Deep Saini <varun.23bcs10048@ms.sst.scaler.com>
1 parent a1a0027 commit 710f70f

File tree

6 files changed

+343
-126
lines changed

6 files changed

+343
-126
lines changed

src/main/java/com/iemr/common/controller/users/IEMRAdminController.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,13 @@ public String getLoginResponse(HttpServletRequest request) {
583583
throw new IEMRException("Authentication failed. Please log in again.");
584584
}
585585

586+
// Validate the token first
587+
Claims claims = jwtUtil.validateToken(jwtToken);
588+
if (claims == null) {
589+
logger.warn("Authentication failed: invalid or expired token.");
590+
throw new IEMRException("Authentication failed. Please log in again.");
591+
}
592+
586593
// Extract user ID from the JWT token
587594
String userId = jwtUtil.getUserIdFromToken(jwtToken);
588595

@@ -1230,4 +1237,85 @@ public ResponseEntity<?> getUserDetails(@PathVariable("userName") String userNam
12301237
}
12311238

12321239
}
1240+
1241+
@Operation(summary = "Unlock user account locked due to failed login attempts")
1242+
@RequestMapping(value = "/unlockUserAccount", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON, headers = "Authorization")
1243+
public String unlockUserAccount(@RequestBody String request, HttpServletRequest httpRequest) {
1244+
OutputResponse response = new OutputResponse();
1245+
try {
1246+
Long authenticatedUserId = getAuthenticatedUserId(httpRequest);
1247+
validateAdminPrivileges(authenticatedUserId);
1248+
Long userId = parseUserIdFromRequest(request);
1249+
boolean unlocked = iemrAdminUserServiceImpl.unlockUserAccount(userId);
1250+
response.setResponse(unlocked ? "User account successfully unlocked" : "User account was not locked");
1251+
} catch (Exception e) {
1252+
logger.error("Error unlocking user account: " + e.getMessage(), e);
1253+
response.setError(e);
1254+
}
1255+
return response.toString();
1256+
}
1257+
1258+
@Operation(summary = "Get user account lock status")
1259+
@RequestMapping(value = "/getUserLockStatus", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON, headers = "Authorization")
1260+
public String getUserLockStatus(@RequestBody String request, HttpServletRequest httpRequest) {
1261+
OutputResponse response = new OutputResponse();
1262+
try {
1263+
Long authenticatedUserId = getAuthenticatedUserId(httpRequest);
1264+
validateAdminPrivileges(authenticatedUserId);
1265+
Long userId = parseUserIdFromRequest(request);
1266+
String lockStatusJson = iemrAdminUserServiceImpl.getUserLockStatusJson(userId);
1267+
response.setResponse(lockStatusJson);
1268+
} catch (Exception e) {
1269+
logger.error("Error getting user lock status: " + e.getMessage(), e);
1270+
response.setError(e);
1271+
}
1272+
return response.toString();
1273+
}
1274+
1275+
private Long parseUserIdFromRequest(String request) throws IEMRException {
1276+
try {
1277+
JsonObject requestObj = JsonParser.parseString(request).getAsJsonObject();
1278+
if (!requestObj.has("userId") || requestObj.get("userId").isJsonNull()) {
1279+
throw new IEMRException("userId is required");
1280+
}
1281+
JsonElement userIdElement = requestObj.get("userId");
1282+
if (!userIdElement.isJsonPrimitive() || !userIdElement.getAsJsonPrimitive().isNumber()) {
1283+
throw new IEMRException("userId must be a number");
1284+
}
1285+
return userIdElement.getAsLong();
1286+
} catch (IEMRException e) {
1287+
throw e;
1288+
} catch (Exception e) {
1289+
throw new IEMRException("Invalid request body", e);
1290+
}
1291+
}
1292+
1293+
private Long getAuthenticatedUserId(HttpServletRequest httpRequest) throws IEMRException {
1294+
String authorization = httpRequest.getHeader("Authorization");
1295+
if (authorization != null && authorization.contains("Bearer ")) {
1296+
authorization = authorization.replace("Bearer ", "");
1297+
}
1298+
if (authorization == null || authorization.isEmpty()) {
1299+
throw new IEMRException("Authentication required");
1300+
}
1301+
try {
1302+
String sessionJson = sessionObject.getSessionObject(authorization);
1303+
if (sessionJson == null || sessionJson.isEmpty()) {
1304+
throw new IEMRException("Session expired. Please log in again.");
1305+
}
1306+
JSONObject session = new JSONObject(sessionJson);
1307+
return session.getLong("userID");
1308+
} catch (IEMRException e) {
1309+
throw e;
1310+
} catch (Exception e) {
1311+
throw new IEMRException("Authentication failed", e);
1312+
}
1313+
}
1314+
1315+
private void validateAdminPrivileges(Long userId) throws IEMRException {
1316+
if (!iemrAdminUserServiceImpl.hasAdminPrivileges(userId)) {
1317+
logger.warn("Unauthorized access attempt by userId: {}", userId);
1318+
throw new IEMRException("Access denied. Admin privileges required.");
1319+
}
1320+
}
12331321
}

src/main/java/com/iemr/common/data/users/User.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ public class User implements Serializable {
213213
@Column(name = "dhistoken")
214214
private String dhistoken;
215215

216+
@Expose
217+
@Column(name = "lock_timestamp")
218+
private Timestamp lockTimestamp;
219+
216220
/*
217221
* protected User() { }
218222
*/

src/main/java/com/iemr/common/repository/users/IEMRUserRepositoryCustom.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ UserSecurityQMapping verifySecurityQuestionAnswers(@Param("UserID") Long UserID,
7575

7676
@Query("SELECT u FROM User u WHERE u.userID=5718")
7777
User getAllExistingUsers();
78-
78+
7979
User findByUserID(Long userID);
8080

8181
}

src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ public List<ServiceRoleScreenMapping> getUserServiceRoleMappingForProvider(Integ
123123

124124
List<User> getUserIdbyUserName(String userName) throws IEMRException;
125125

126+
boolean unlockUserAccount(Long userId) throws IEMRException;
127+
128+
String getUserLockStatusJson(Long userId) throws IEMRException;
129+
130+
boolean hasAdminPrivileges(Long userId) throws IEMRException;
126131

127-
128132
}

0 commit comments

Comments
 (0)