Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1894,24 +1894,26 @@ public BenMenstrualDetails getMenstrualHistory(Long beneficiaryRegID, Long visit
BenMenstrualDetails menstrualHistoryDetails = BenMenstrualDetails.getBenMenstrualDetails(menstrualHistory);

// CRs changes, 30-10-2018
String problemID = menstrualHistoryDetails.getMenstrualProblemID();
String problemName = menstrualHistoryDetails.getProblemName();

if (problemID != null && problemName != null) {
String[] problemIdArr = problemID.split(",");
String[] problemNameArr = problemName.split(",");
ArrayList<Map<String, Object>> menstrualProblemList = new ArrayList<>();
Map<String, Object> menstrualProblemMap = null;

if (problemIdArr.length == problemNameArr.length) {
for (int i = 0; i < problemIdArr.length; i++) {
menstrualProblemMap = new HashMap<String, Object>();
menstrualProblemMap.put("menstrualProblemID", problemIdArr[i]);
menstrualProblemMap.put("problemName", problemNameArr[i]);
menstrualProblemList.add(menstrualProblemMap);
if (null != menstrualHistoryDetails) {
String problemID = menstrualHistoryDetails.getMenstrualProblemID();
String problemName = menstrualHistoryDetails.getProblemName();

if (problemID != null && problemName != null) {
String[] problemIdArr = problemID.split(",");
String[] problemNameArr = problemName.split(",");
ArrayList<Map<String, Object>> menstrualProblemList = new ArrayList<>();
Map<String, Object> menstrualProblemMap = null;

if (problemIdArr.length == problemNameArr.length) {
for (int i = 0; i < problemIdArr.length; i++) {
menstrualProblemMap = new HashMap<String, Object>();
menstrualProblemMap.put("menstrualProblemID", problemIdArr[i]);
menstrualProblemMap.put("problemName", problemNameArr[i]);
menstrualProblemList.add(menstrualProblemMap);
}
}
menstrualHistoryDetails.setMenstrualProblemList(menstrualProblemList);
}
menstrualHistoryDetails.setMenstrualProblemList(menstrualProblemList);
}

return menstrualHistoryDetails;
Expand Down
57 changes: 34 additions & 23 deletions src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,49 +48,60 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
logger.info("No cookies found in the request");
}

// Log headers for debugging
String jwtTokenFromHeader = request.getHeader("Jwttoken");
logger.info("JWT token from header: ");

// Skip login and public endpoints
if (path.equals(contextPath + "/user/userAuthenticate")
|| path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession")
|| path.startsWith(contextPath + "/swagger-ui")
|| path.startsWith(contextPath + "/v3/api-docs")
|| path.startsWith(contextPath + "/user/refreshToken")
|| path.startsWith(contextPath + "/public")) {
|| path.startsWith(contextPath + "/swagger-ui") || path.startsWith(contextPath + "/v3/api-docs")
|| path.startsWith(contextPath + "/user/refreshToken") || path.startsWith(contextPath + "/public")) {
logger.info("Skipping filter for path: " + path);
filterChain.doFilter(servletRequest, servletResponse);
return;
}

try {
// Retrieve JWT token from cookies
String jwtTokenFromCookie = getJwtTokenFromCookies(request);
logger.info("JWT token from cookie: ");

// Determine which token (cookie or header) to validate
String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader;
if (jwtToken == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers");
return;
String jwtFromCookie = getJwtTokenFromCookies(request);
String jwtFromHeader = request.getHeader("JwtToken");
String authHeader = request.getHeader("Authorization");

if (jwtFromCookie != null) {
logger.info("Validating JWT token from cookie");
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}

// Validate JWT token and userId
boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken);
if (jwtFromHeader != null) {
logger.info("Validating JWT token from header");
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}
String userAgent = request.getHeader("User-Agent");
logger.info("User-Agent: " + userAgent);

if (isValid) {
// If token is valid, allow the request to proceed
if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token");
return;
}
Comment on lines +81 to 87
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Verification agent

🧩 Analysis chain

Security concern: Mobile client bypass needs stronger validation.

The special handling for mobile clients bypasses JWT validation based only on User-Agent detection, which could pose a security risk as User-Agent strings can be easily spoofed.

Consider implementing additional security measures for mobile clients rather than bypassing validation entirely. At minimum, verify that the Authorization header contains a valid token:

-if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
+if (userAgent != null && isMobileClient(userAgent) && authHeader != null &&
+    authHeader.startsWith("Bearer ") && jwtAuthenticationUtil.validateToken(authHeader.substring(7))) {
   filterChain.doFilter(servletRequest, servletResponse);
   return;
}

Run this script to check if the Authorization header is properly validated elsewhere:


🏁 Script executed:

#!/bin/bash
# Check if Authorization header is properly validated elsewhere
rg -A 5 "Authorization.*header" --glob "*.java"

# Check for other token validation methods
rg -A 5 "validateToken|validateAuth" --glob "*.java"

# Look at JwtAuthenticationUtil implementation
find . -name "JwtAuthenticationUtil.java" -exec cat {} \;

Length of output: 5629


🏁 Script executed:

#!/bin/bash
# Locate and display the JwtUserIdValidationFilter for context
find . -name JwtUserIdValidationFilter.java -exec sed -n '1,200p' '{}' ';'

Length of output: 4307


Strengthen JWT validation for mobile‐client bypass

The current logic skips any real token validation for mobile clients as long as an Authorization header is present, which can be trivially spoofed. We should extract and validate a Bearer token just as we do for cookies and JwtToken headers.

Locations to update:

  • src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java around the if (userAgent != null …) block (lines ~83–89).

Suggested diff:

--- a/src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
+++ b/src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
@@ -86,7 +86,17 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespons
         String userAgent = request.getHeader("User-Agent");
         logger.info("User-Agent: " + userAgent);
 
-        if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
-            filterChain.doFilter(servletRequest, servletResponse);
-            return;
+        if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
+            // Extract Bearer token from Authorization header
+            String token = null;
+            if (authHeader.startsWith("Bearer ")) {
+                token = authHeader.substring("Bearer ".length());
+            }
+            // Validate token and associated userId
+            if (token != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(token)) {
+                filterChain.doFilter(servletRequest, servletResponse);
+                return;
+            }
+            logger.warn("Invalid or missing JWT in Authorization header for mobile client");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Invalid or missing token");
+            return;
         }
 
         logger.warn("No valid authentication token found");

This ensures mobile clients must present a well‐formed Bearer JWT that passes the same validateUserIdAndJwtToken checks applied elsewhere.

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
String userAgent = request.getHeader("User-Agent");
logger.info("User-Agent: " + userAgent);
if (isValid) {
// If token is valid, allow the request to proceed
if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token");
return;
}
String userAgent = request.getHeader("User-Agent");
logger.info("User-Agent: " + userAgent);
if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
// Extract Bearer token from Authorization header
String token = null;
if (authHeader.startsWith("Bearer ")) {
token = authHeader.substring("Bearer ".length());
}
// Validate token and associated userId
if (token != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(token)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
logger.warn("Invalid or missing JWT in Authorization header for mobile client");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Invalid or missing token");
return;
}
logger.warn("No valid authentication token found");
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java around lines
83 to 89, the current code bypasses full JWT validation for mobile clients based
solely on User-Agent and presence of an Authorization header, which is insecure.
Modify this logic to extract the Bearer token from the Authorization header and
perform the same validateUserIdAndJwtToken checks used elsewhere before allowing
the filter chain to proceed. This ensures mobile clients must present a valid
JWT token rather than just any Authorization header.


logger.warn("No valid authentication token found");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Invalid or missing token");

} catch (Exception e) {
logger.error("Authorization error: ", e);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage());
}
}

private boolean isMobileClient(String userAgent) {
if (userAgent == null)
return false;
userAgent = userAgent.toLowerCase();
return userAgent.contains("okhttp"); // iOS (custom clients)
}

private String getJwtTokenFromCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
Expand Down
Loading