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 @@ -67,6 +67,7 @@
import com.iemr.helpline104.reposotory.IMRMMR.IMRMMRRepository;
import com.iemr.helpline104.sms.SmsRequestOBJ;
import com.iemr.helpline104.utils.CookieUtil;
import com.iemr.helpline104.utils.RestTemplateUtil;
import com.iemr.helpline104.utils.mapper.InputMapper;

import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -198,11 +199,7 @@ public void createEmailGateway(String emailID, String requestID, String Authoriz
emailReqObj.put("requestID", requestID);
emailReqObj.put("emailType", IMRMMREmailTemplate);
emailReqObj.put("emailID", emailID);
HttpServletRequest requestHeader = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(requestHeader);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Cookie", "Jwttoken=" + jwtTokenFromCookie);

try {
String emailStatus = restTemplate(new Gson().toJson(emailReqObj), sendEmailGeneralUrl, Authorization);
if (emailStatus != null) {
Expand Down Expand Up @@ -283,11 +280,7 @@ public String createSMSRequest(String smsType, Long benRegID, Integer stateID, S
}

public String restTemplate(String request, String url, String Authorization) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set("AUTHORIZATION", Authorization);

HttpEntity<Object> requestOBJ = new HttpEntity<Object>(request, headers);
HttpEntity<Object> requestOBJ = RestTemplateUtil.createRequestEntity(request, Authorization);
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange(url, HttpMethod.POST, requestOBJ, String.class).getBody();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.iemr.helpline104.repository.location.LocationDistrictBlockRepository;
import com.iemr.helpline104.repository.location.LocationDistrictRepository;
import com.iemr.helpline104.utils.CookieUtil;
import com.iemr.helpline104.utils.RestTemplateUtil;
import com.iemr.helpline104.utils.config.ConfigProperties;
import com.iemr.helpline104.utils.exception.IEMRException;
import com.iemr.helpline104.utils.http.HttpUtils;
Expand Down Expand Up @@ -193,13 +194,8 @@ else if (phoneNo != null) {
private OutputResponse createFeedback(String feedbackDetails, HttpServletRequest request) throws IEMRException, JsonMappingException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
ObjectMapper objectMapper = new ObjectMapper();
String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(request);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
headers.add("AUTHORIZATION", request.getHeader("Authorization"));
headers.add("Jwttoken", jwtTokenFromCookie);
String url = properties.getPropertyByName("common-url") + "/" + properties.getPropertyByName("create-feedback");
HttpEntity<Object> request1 = new HttpEntity<Object>(feedbackDetails, headers);
HttpEntity<Object> request1 = RestTemplateUtil.createRequestEntity(feedbackDetails, request.getHeader("Authorization"));
ResponseEntity<String> responseStr = restTemplate.exchange(url, HttpMethod.POST, request1, String.class);
OutputResponse response = objectMapper.readValue(responseStr.getBody(), OutputResponse.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import com.iemr.helpline104.repository.location.LocationDistrictBlockRepository;
import com.iemr.helpline104.repository.location.LocationDistrictRepository;
import com.iemr.helpline104.utils.CookieUtil;
import com.iemr.helpline104.utils.RestTemplateUtil;
import com.iemr.helpline104.utils.config.ConfigProperties;
import com.iemr.helpline104.utils.exception.IEMRException;
import com.iemr.helpline104.utils.http.HttpUtils;
Expand Down Expand Up @@ -189,13 +190,8 @@ else if (requestID != null) {
private OutputResponse createFeedback(String feedbackDetails, HttpServletRequest request) throws IEMRException, JsonMappingException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
ObjectMapper objectMapper = new ObjectMapper();
String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(request);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
headers.add("AUTHORIZATION", request.getHeader("Authorization"));
headers.add("Jwttoken", jwtTokenFromCookie);
String url = properties.getPropertyByName("common-url") + "/" + properties.getPropertyByName("create-feedback");
HttpEntity<Object> request1 = new HttpEntity<Object>(feedbackDetails, headers);
HttpEntity<Object> request1 = RestTemplateUtil.createRequestEntity(feedbackDetails, request.getHeader("Authorization"));
ResponseEntity<String> responseStr = restTemplate.exchange(url, HttpMethod.POST, request1, String.class);
OutputResponse response = objectMapper.readValue(responseStr.getBody(), OutputResponse.class);
return response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import com.iemr.helpline104.repository.feedback.FeedbackRepository;
import com.iemr.helpline104.repository.feedbackType.FeedbackTypeRepository;
import com.iemr.helpline104.utils.CookieUtil;
import com.iemr.helpline104.utils.RestTemplateUtil;
import com.iemr.helpline104.utils.config.ConfigProperties;
import com.iemr.helpline104.utils.exception.IEMRException;
import com.iemr.helpline104.utils.http.HttpUtils;
Expand Down Expand Up @@ -334,13 +335,8 @@ private OutputResponse createFeedback(String feedbackDetails, HttpServletRequest
logger.info("createFeedback request: " + feedbackDetails);
RestTemplate restTemplate = new RestTemplate();
ObjectMapper objectMapper = new ObjectMapper();
String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(request);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
headers.add("AUTHORIZATION", request.getHeader("Authorization"));
headers.add("Jwttoken", jwtTokenFromCookie);
String url = properties.getPropertyByName("common-url") + "/" + properties.getPropertyByName("create-feedback");
HttpEntity<Object> request1 = new HttpEntity<Object>(feedbackDetails, headers);
HttpEntity<Object> request1 = RestTemplateUtil.createRequestEntity(feedbackDetails, request.getHeader("Authorization"));
ResponseEntity<String> responseStr = restTemplate.exchange(url, HttpMethod.POST, request1, String.class);
OutputResponse response = objectMapper.readValue(responseStr.getBody(), OutputResponse.class);
logger.info("createFeedback resonse from common: " + response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import com.iemr.helpline104.repository.feedbackType.FeedbackTypeRepository;
import com.iemr.helpline104.repository.foodSafetyCopmlaint.FoodSafetyCopmlaintRepository;
import com.iemr.helpline104.utils.CookieUtil;
import com.iemr.helpline104.utils.RestTemplateUtil;
import com.iemr.helpline104.utils.config.ConfigProperties;
import com.iemr.helpline104.utils.exception.IEMRException;
import com.iemr.helpline104.utils.http.HttpUtils;
Expand Down Expand Up @@ -209,13 +210,10 @@ public T_FoodSafetyCopmlaint save(T_FoodSafetyCopmlaint t_foodSafetyCopmlaint, H
private OutputResponse createFeedback(String feedbackDetails, HttpServletRequest request) throws IEMRException, JsonMappingException, JsonProcessingException {
RestTemplate restTemplate = new RestTemplate();
ObjectMapper objectMapper = new ObjectMapper();
String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(request);
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Content-Type", "application/json");
headers.add("AUTHORIZATION", request.getHeader("Authorization"));
headers.add("Jwttoken", jwtTokenFromCookie);

String url = properties.getPropertyByName("common-url") + "/" + properties.getPropertyByName("create-feedback");
HttpEntity<Object> request1 = new HttpEntity<Object>(feedbackDetails, headers);
HttpEntity<Object> request1 = RestTemplateUtil.createRequestEntity(feedbackDetails, request.getHeader("Authorization"));

ResponseEntity<String> responseStr = restTemplate.exchange(url, HttpMethod.POST, request1, String.class);
OutputResponse response = objectMapper.readValue(responseStr.getBody(), OutputResponse.class);
return response;
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/com/iemr/helpline104/utils/CookieUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ public Optional<String> getCookieValue(HttpServletRequest request, String cookie
return Optional.empty();
}

public String getJwtTokenFromCookie(HttpServletRequest request) {
public static String getJwtTokenFromCookie(HttpServletRequest request) {
if (request.getCookies() == null) {
return null; // If cookies are null, return null safely.
}
return Arrays.stream(request.getCookies()).filter(cookie -> "Jwttoken".equals(cookie.getName()))
.map(Cookie::getValue).findFirst().orElse(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.iemr.helpline104.utils.http.AuthorizationHeaderRequestWrapper;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
Expand Down Expand Up @@ -74,29 +75,36 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
if (jwtFromCookie != null) {
logger.info("Validating JWT token from cookie");
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) {
filterChain.doFilter(servletRequest, servletResponse);
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
request, "");
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
return;
}
}

if (jwtFromHeader != null) {
} else if (jwtFromHeader != null) {
logger.info("Validating JWT token from header");
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) {
filterChain.doFilter(servletRequest, servletResponse);
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
request, "");
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
return;
}
} else {
String userAgent = request.getHeader("User-Agent");
Comment on lines 75 to +92
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Token-validation flow prevents header-fallback & strips valid Authorization

  1. If a Jwttoken cookie is present but fails validation, the subsequent else if branch is skipped, so a perfectly valid JwtToken header is ignored and the request gets a 401.
  2. When validation succeeds, the request is wrapped with an empty Authorization header. Downstream code (e.g. FeedbackServiceImpl) later forwards that header to other services, so a legitimately authenticated call is propagated as an empty bearer, possibly breaking the chain.
-if (jwtFromCookie != null) {
+if (jwtFromCookie != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) {
     ...
-} else if (jwtFromHeader != null) {
+} else if (jwtFromHeader != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) {
     ...
-                request, "");
+                request, "Bearer " + (jwtFromHeader != null ? jwtFromHeader : jwtFromCookie));

Refactor the conditional logic to:

  1. Validate cookie token β†’ if valid proceed, else fall through.
  2. Validate header token β†’ if valid proceed.
  3. Otherwise 401.

And instead of blanking the header, propagate the validated bearer token so internal service calls remain authorised.

πŸ“ 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
if (jwtFromCookie != null) {
logger.info("Validating JWT token from cookie");
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) {
filterChain.doFilter(servletRequest, servletResponse);
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
request, "");
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
return;
}
}
if (jwtFromHeader != null) {
} else if (jwtFromHeader != null) {
logger.info("Validating JWT token from header");
if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) {
filterChain.doFilter(servletRequest, servletResponse);
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
request, "");
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
return;
}
} else {
String userAgent = request.getHeader("User-Agent");
// … lines 1–74 remain unchanged …
// First try a valid cookie, else try a valid header, else 401
- if (jwtFromCookie != null) {
+ if (jwtFromCookie != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) {
logger.info("Validating JWT token from cookie");
- if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromCookie)) {
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
- request, "");
+ request, "Bearer " + (jwtFromHeader != null ? jwtFromHeader : jwtFromCookie));
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
return;
- }
} else if (jwtFromHeader != null) {
+ } else if (jwtFromHeader != null && jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) {
logger.info("Validating JWT token from header");
- if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) {
AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
- request, "");
+ request, "Bearer " + (jwtFromHeader != null ? jwtFromHeader : jwtFromCookie));
filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
return;
- }
} else {
String userAgent = request.getHeader("User-Agent");
}
// … remainder of method …
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/helpline104/utils/JwtUserIdValidationFilter.java
between lines 75 and 92, refactor the token validation logic to first validate
the JWT token from the cookie and if it fails, continue to validate the JWT
token from the header instead of skipping it. Only return a 401 if both
validations fail. Additionally, when wrapping the request after successful
validation, ensure the Authorization header is set to the validated token value
instead of an empty string to preserve the authenticated token for downstream
services.

logger.info("User-Agent: " + userAgent);

if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
try {
UserAgentContext.setUserAgent(userAgent);
filterChain.doFilter(servletRequest, servletResponse);
} finally {
UserAgentContext.clear();
}
return;
}
}
String userAgent = request.getHeader("User-Agent");
logger.info("User-Agent: " + userAgent);

if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}

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());
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/iemr/helpline104/utils/RestTemplateUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.iemr.helpline104.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;

public class RestTemplateUtil {
private final static Logger logger = LoggerFactory.getLogger(RestTemplateUtil.class);

public static HttpEntity<Object> createRequestEntity(Object body, String authorization) {

ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
if (servletRequestAttributes == null) {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8");
headers.add(HttpHeaders.AUTHORIZATION, authorization);
return new HttpEntity<>(body, headers);
}
Comment on lines +18 to +26
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid inserting an empty Authorization header

headers.add(HttpHeaders.AUTHORIZATION, authorization); is executed even when authorization is null or blank, resulting in a header like Authorization: being sent.

-headers.add(HttpHeaders.AUTHORIZATION, authorization);
+if (authorization != null && !authorization.isBlank()) {
+    headers.add(HttpHeaders.AUTHORIZATION, authorization);
+}

Apply the same guard in the main path below.

πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/helpline104/utils/RestTemplateUtil.java around lines
14 to 22, the code adds the Authorization header without checking if the
authorization string is null or blank, which can lead to sending an empty
Authorization header. Fix this by adding a condition to check if the
authorization string is not null and not blank before adding the Authorization
header. Apply this same check both in the if block shown and in the main path of
the method to prevent empty Authorization headers from being sent.

HttpServletRequest requestHeader = servletRequestAttributes.getRequest();
String jwtTokenFromCookie = null;
try {
jwtTokenFromCookie = CookieUtil.getJwtTokenFromCookie(requestHeader);

} catch (Exception e) {
logger.error("Error while getting jwtToken from Cookie" + e.getMessage() );
}

MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8");
if(null != UserAgentContext.getUserAgent()) {
headers.add(HttpHeaders.USER_AGENT, UserAgentContext.getUserAgent());
}
headers.add(HttpHeaders.AUTHORIZATION, authorization);
headers.add("JwtToken",requestHeader.getHeader("JwtToken"));
if(null != jwtTokenFromCookie) {
headers.add(HttpHeaders.COOKIE, "Jwttoken=" + jwtTokenFromCookie);
}

return new HttpEntity<>(body, headers);
}

}
18 changes: 18 additions & 0 deletions src/main/java/com/iemr/helpline104/utils/UserAgentContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.iemr.helpline104.utils;

public class UserAgentContext {
private static final ThreadLocal<String> userAgentHolder = new ThreadLocal<>();

public static void setUserAgent(String userAgent) {
userAgentHolder.set(userAgent);
}

public static String getUserAgent() {
return userAgentHolder.get();
}

public static void clear() {
userAgentHolder.remove();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.iemr.helpline104.utils.http;

import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;

public class AuthorizationHeaderRequestWrapper extends HttpServletRequestWrapper {
private final String Authorization;

public AuthorizationHeaderRequestWrapper(HttpServletRequest request, String authHeaderValue) {
super(request);
this.Authorization = authHeaderValue;
}

@Override
public String getHeader(String name) {
if ("Authorization".equalsIgnoreCase(name)) {
return Authorization;
}
return super.getHeader(name);
}

@Override
public Enumeration<String> getHeaders(String name) {
if ("Authorization".equalsIgnoreCase(name)) {
return Collections.enumeration(Collections.singletonList(Authorization));
}
return super.getHeaders(name);
}

@Override
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
if (!names.contains("Authorization")) {
names.add("Authorization");
}
return Collections.enumeration(names);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
boolean status = true;
logger.debug("In preHandle we are Intercepting the Request");
String authorization = request.getHeader("Authorization");
if (authorization == null || authorization.isEmpty()) {
logger.info("Authorization header is null or empty. Skipping HTTPRequestInterceptor.");
return true; // Allow the request to proceed without validation
}
logger.debug("RequestURI:: {} || method :: {}", request.getRequestURI(), request.getMethod());
if (!request.getMethod().equalsIgnoreCase("OPTIONS")) {
try {
Expand Down
Loading