Skip to content
Closed
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
1 change: 1 addition & 0 deletions src/main/environment/104_ci.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ springdoc.swagger-ui.enabled=@env.SWAGGER_DOC_ENABLED@

sendSMSUrl= @env.COMMON_API_BASE_URL@sms/sendSMS
sendEmailGeneralUrl = @env.COMMON_API_BASE_URL@emailController/sendEmailGeneral
cors.allowed-origins=@CORS_ALLOWED_ORIGINS@
3 changes: 2 additions & 1 deletion src/main/environment/104_example.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ spring.redis.host=localhost
jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret
#If both properties are set, only logging.file.name takes effect.
logging.path=logs/
logging.file.name=logs/helpline104-api.log
logging.file.name=logs/helpline104-api.log
cors.allowed-origins=http://localhost:*
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

Verify CORS origin pattern validity and consider security implications.

The addition of externalized CORS configuration is a good approach for centralization. However, please verify that the wildcard pattern http://localhost:* is supported by your CORS implementation, as many CORS libraries don't support port wildcards.

Additionally, consider the security implications of allowing all localhost ports, as this could potentially allow access from unintended local applications running on different ports.


🌐 Web query:

Does Spring Boot CORS configuration support wildcard ports in origin patterns like "http://localhost:*"?

πŸ’‘ Result:

Based on the search results, Spring Boot's CORS configuration does not natively support wildcard ports in origin patterns like "http://localhost:*". However, there are several approaches to handle this scenario.

CORS Configuration Options in Spring Boot

Spring provides multiple ways to configure CORS with varying levels of flexibility:

Method-Level and Class-Level Configuration

Using the @CrossOrigin annotation, you can specify allowed origins for specific endpoints or controllers:

@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class MyController {
    // Controller methods
}

This approach requires you to explicitly specify each allowed origin port (e.g., "http://localhost:4200")[5][7].

Global Configuration

For application-wide CORS settings, you can implement WebMvcConfigurer:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:4200")
            .allowedMethods("GET", "POST", "PUT", "DELETE");
    }
}

This configuration also requires explicit origin specification[4][5].

Alternative Solutions for Localhost Development

Since Spring Boot doesn't directly support wildcard ports in origins, here are alternatives for local development:

1. Using allowedOriginPatterns

Since Spring Boot 2.4.0, there's a more flexible allowedOriginPatterns option that provides more pattern-matching capabilities than the standard allowedOrigins[3]. While it doesn't explicitly support port wildcards, it offers more flexibility.

2. Multiple Origin Configuration

You can specify multiple localhost origins with different ports:

registry.addMapping("/api/**")
    .allowedOrigins(
        "http://localhost:3000", 
        "http://localhost:4200", 
        "http://localhost:8080"
    );

3. Feature Request

There is recognition of this need in the community. For instance, there's a feature request in the Kubernetes ingress-nginx project (issue #8264) to allow wildcard ports specifically for localhost origins[6]. This suggests that wildcard port support for localhost would be valuable, but it's not currently a standard feature in Spring Boot.

Best Practices for CORS in Development vs. Production

For development environments:

  • Configure multiple specific localhost origins as needed
  • Consider using a more permissive CORS policy during development

For production environments:

  • Use specific, restrictive origin lists
  • Avoid wildcards entirely for security reasons
  • If using allowCredentials = true, you cannot use wildcards for origins[7]

If you need to test with varying localhost ports, the most straightforward approach is to list all the specific ports you might use during development rather than relying on a wildcard pattern that isn't supported.

Citations:


Update CORS configuration to use supported origin patterns

The pattern http://localhost:* isn’t recognized by Spring Boot’s allowedOrigins. Please adjust as follows:

β€’ In Spring Boot 2.4+ you can use allowedOriginPatterns with Ant-style patterns:

# src/main/environment/104_example.properties (line 25)
cors.allowed-origin-patterns=http://localhost:[*]

(This lets you match any localhost port.)

β€’ Or explicitly list the ports you need:

cors.allowed-origins=http://localhost:3000,http://localhost:4200,http://localhost:8080

Security note: avoid wildcards in productionβ€”only whitelist specific origins when allowCredentials=true and lock down CORS in your prod environment.

πŸ€– Prompt for AI Agents
In src/main/environment/104_example.properties at line 25, the CORS origin
pattern "http://localhost:*" is not supported by Spring Boot's allowedOrigins
configuration. To fix this, replace it with either the allowedOriginPatterns
property using an Ant-style pattern like "http://localhost:[*]" to match any
localhost port, or explicitly list the allowed localhost origins with specific
ports separated by commas. Ensure this change aligns with your Spring Boot
version (2.4+) and consider restricting origins in production for security.

25 changes: 25 additions & 0 deletions src/main/java/com/iemr/helpline104/config/CorsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.iemr.helpline104.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

@Value("${cors.allowed-origins}")
private String allowedOrigins;

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns(allowedOrigins.split(","))
Comment on lines +16 to +17
Copy link
Contributor

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Consider validation for empty origins configuration.

The code splits allowedOrigins by comma without checking if it's null or empty, which could lead to unexpected behavior.

-        registry.addMapping("/**")
-                .allowedOriginPatterns(allowedOrigins.split(","))
+        registry.addMapping("/**")
+                .allowedOriginPatterns(allowedOrigins != null && !allowedOrigins.trim().isEmpty() 
+                    ? allowedOrigins.split(",") 
+                    : new String[0])
πŸ“ 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
registry.addMapping("/**")
.allowedOriginPatterns(allowedOrigins.split(","))
registry.addMapping("/**")
.allowedOriginPatterns(allowedOrigins != null && !allowedOrigins.trim().isEmpty()
? allowedOrigins.split(",")
: new String[0])
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/helpline104/config/CorsConfig.java around lines 16 to
17, the code splits the allowedOrigins string by commas without validating if
allowedOrigins is null or empty. To fix this, add a check before splitting to
ensure allowedOrigins is not null or empty; if it is, handle it appropriately by
either setting a default value or skipping the configuration to avoid unexpected
behavior.

.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed
.allowCredentials(true)
.maxAge(3600)
Comment on lines +18 to +22
Copy link
Contributor

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Review security implications of CORS configuration.

The current configuration has several security considerations:

  1. allowCredentials(true) with potentially broad origin patterns could be risky
  2. allowedHeaders("*") is very permissive
  3. Exposing Authorization and Jwttoken headers increases attack surface

Consider more restrictive settings:

                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
-                .allowedHeaders("*")
+                .allowedHeaders("Authorization", "Content-Type", "Accept", "Jwttoken")
                .exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed
                .allowCredentials(true)
                .maxAge(3600)
πŸ“ 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
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed
.allowCredentials(true)
.maxAge(3600)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("Authorization", "Content-Type", "Accept", "Jwttoken")
.exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed
.allowCredentials(true)
.maxAge(3600)
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/helpline104/config/CorsConfig.java around lines 18 to
22, the CORS configuration is overly permissive and poses security risks by
allowing credentials with broad origins, permitting all headers, and exposing
sensitive headers like Authorization and Jwttoken. To fix this, restrict allowed
origins to specific trusted domains instead of allowing all, specify only
necessary headers in allowedHeaders instead of "*", and avoid exposing sensitive
headers unless absolutely required. Adjust allowCredentials accordingly to match
the restricted origins and minimize exposure.

;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class IMRMMRController {
@Autowired
private IMRMMRService imrmmrService;

@CrossOrigin()

@Operation(summary = "Save IMR MMR")
@PostMapping(value = "/saveIMRMMR", headers = "Authorization", produces = {
"application/json" })
Expand All @@ -78,7 +78,7 @@ public String saveIMRMMR(@RequestBody String request,
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Fetch support services")
@GetMapping(value = "/fetchimrmmrmasters", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String fetchSupportServices() {
Expand All @@ -105,7 +105,7 @@ public String fetchSupportServices() {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Feedback request")
@PostMapping(value = "/getIMRMMRList", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String feedbackReuest(@RequestBody String request) {
Expand All @@ -123,7 +123,7 @@ public String feedbackReuest(@RequestBody String request) {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Update IMR MMR complaint")
@PostMapping(value = "/update/ImrMmrComplaint", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String updateImrMmrComplaint(@RequestBody String request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class BalVivahController {
@Autowired
private BalVivahComplaintService balVivahComplaintService;

@CrossOrigin()

@Operation(summary = "Save bal vivah complaint")
@PostMapping(value = "/saveBalVivahComplaint", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String balVivahComplaint(@RequestBody String request, HttpServletRequest httpRequest) {
Expand All @@ -60,7 +60,7 @@ public String balVivahComplaint(@RequestBody String request, HttpServletRequest
return output.toString();
}

@CrossOrigin()

@Operation(summary = "Get bal vivah list")
@PostMapping(value = "/getBalVivahList", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String feedbackReuest(@RequestBody String request) {
Expand All @@ -79,7 +79,7 @@ public String feedbackReuest(@RequestBody String request) {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Update bal vivah complaint")
@PostMapping(value = "/update/BalVivahComplaint", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String updateBalVivahComplaint(@RequestBody String request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void setBeneficiaryCallService(BeneficiaryCallService beneficiaryCallServ
this.beneficiaryCallService = beneficiaryCallService;
}

@CrossOrigin()

@Operation(summary = "Stores callerID to the specific beneficiary who are on call")
@PostMapping(value = "/startCall", headers = "Authorization")
public String startCall(
Expand All @@ -85,7 +85,7 @@ public String startCall(
return output.toString();
}

@CrossOrigin()

@Operation(summary = "Update beneficiary reg id to the caller id")
@PostMapping(value = "update/beneficiaryCallID", headers = "Authorization")
public String updateBeneficiaryIDInCall(
Expand Down Expand Up @@ -115,7 +115,7 @@ public String updateBeneficiaryIDInCall(
}


@CrossOrigin

@Operation(summary = "Fetch services available in the 104 helpline")
@PostMapping(value = "/get/services", headers = "Authorization")
public String getServices(
Expand All @@ -138,7 +138,7 @@ public String getServices(
return output.toString();
}

@CrossOrigin()

@Operation(summary = "Set service history")
@PostMapping(value = "set/callHistory", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String setServiceHistory(@RequestBody String request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class BloodComponentController {
@Autowired
private BloodComponentService bloodComponentService;

@CrossOrigin

@Operation(summary = "Save blood component details")
@PostMapping(value = "/save/bloodComponentDetails", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String saveBloodComponentDetails(
Expand All @@ -67,7 +67,7 @@ public String saveBloodComponentDetails(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Fetch blood component details")
@PostMapping(value = "/get/bloodComponentDetails", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String getBloodComponentDetails(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class BloodRequestController {
@Autowired
private BloodComponentTypeService componentTypeService;

@CrossOrigin

@Operation(summary = "Save blood request details")
@PostMapping(value = "/save/bloodRequestDetails", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String saveBloodRequestDetails(@RequestBody String request) {
Expand All @@ -77,7 +77,7 @@ public String saveBloodRequestDetails(@RequestBody String request) {
return output.toString();
}

@CrossOrigin

@Operation(summary = "Get blood request details")
@PostMapping(value = "/get/bloodRequestDetails", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String getbloodRequestDetails(
Expand All @@ -102,7 +102,7 @@ public String getbloodRequestDetails(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Get blood component types")
@PostMapping(value = "/get/bloodComponentTypes", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String getBloodComponentTypes() {
Expand All @@ -120,7 +120,7 @@ public String getBloodComponentTypes() {
return output.toString();
}

@CrossOrigin

@Operation(summary = "Get blood groups")
@PostMapping(value = "/get/bloodGroups", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String getBloodGroups() {
Expand All @@ -138,7 +138,7 @@ public String getBloodGroups() {
return output.toString();
}

@CrossOrigin

@Operation(summary = "Get blood bank URL")
@PostMapping(value = "/get/bloodBankURL", headers = "Authorization")
public String getBloodBankURL(
Expand All @@ -163,7 +163,7 @@ public String getBloodBankURL(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Save blood bank URL")
@PostMapping(value = "/save/bloodBankURL", headers = "Authorization")
public String saveBloodBankURL(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class CallQAMappingController {
@Autowired
public CallqamappingService callqamappingService;

@CrossOrigin

@Operation(summary = "Save call qa mapping")
@PostMapping(value = "/save/callqamapping", produces = MediaType.APPLICATION_JSON_VALUE, headers = "Authorization")
public String saveCallqamapping(@RequestBody String request) {
Expand All @@ -69,7 +69,7 @@ public String saveCallqamapping(@RequestBody String request) {
return output.toString();
}

@CrossOrigin

@Operation(summary = "Fetch questions and answers given by beneficiary")
@PostMapping(value = "/get/CDIqamapping", headers = "Authorization")
public String getCDIqamapping(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class Helpline104BeneficiaryHistoryController {
@Autowired
private H104BenHistoryService h104BenHistoryService;

@CrossOrigin

@Operation(summary = "Retrieves case record")
@PostMapping(value = "/getBenCaseSheet", headers = "Authorization")
public String getBenCaseSheet(
Expand All @@ -70,7 +70,7 @@ public String getBenCaseSheet(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Stores case record")
@PostMapping(value = "/save/benCaseSheet", headers = "Authorization")
public String saveBenCaseSheet(
Expand Down Expand Up @@ -101,7 +101,7 @@ public String saveBenCaseSheet(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Retrieves present case record")
@PostMapping(value = "/getPresentCaseSheet", headers = "Authorization")
public String getPresentCaseSheet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class ClinicalDecisionSupportController {
private CDSSService cDSSService;
private Logger logger = LoggerFactory.getLogger(ClinicalDecisionSupportController.class);

@CrossOrigin()

@Operation(summary = "Get symptoms")
@PostMapping(value = "/Symptoms", produces = "application/json", headers = "Authorization")
public String getSymptomsPost(@RequestBody SymptomsWrapper symptomsDetails) {
Expand All @@ -73,7 +73,7 @@ public String getSymptomsPost(@RequestBody SymptomsWrapper symptomsDetails) {

}

@CrossOrigin()

@Operation(summary = "Get questions by symptom, age and gender")
@PostMapping(value = "/getQuestions", produces = "application/json", headers = "Authorization")
public String getQuestion(@RequestBody SymptomsWrapper symptomsDetails) {
Expand All @@ -99,7 +99,7 @@ public String getQuestion(@RequestBody SymptomsWrapper symptomsDetails) {

}

@CrossOrigin()

@Operation(summary = "Get result based on compliant id")
@PostMapping(value = "/getResult", produces = "application/json", headers = "Authorization")
public String getResult(@RequestBody String userAnswer) {
Expand All @@ -125,7 +125,7 @@ public String getResult(@RequestBody String userAnswer) {

}

@CrossOrigin()

@Operation(summary = "Save symptom")
@PostMapping(value = "/saveSymptom", produces = "application/json", headers = "Authorization")
public String saveSymptom(@RequestBody String inputData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

import io.swagger.v3.oas.annotations.Operation;

@CrossOrigin

@RestController
@RequestMapping(value = "/master", headers = "Authorization")

Expand All @@ -56,7 +56,7 @@ public String patientAppMasterData(@PathVariable("providerServiceMapID") Integer
return response.toString();
}

@CrossOrigin

@Operation(summary= "Save COVID data")
@PostMapping({ "/save/covidScreeningData" })
public String saveBenCovidDoctorData(@RequestBody String requestObj,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class DirectoryServicesController {
@Autowired
private DirectoryServiceService directoryServiceService;

@CrossOrigin

@Operation(summary = "Retrieve directory search history")
@RequestMapping(value = "/getdirectorySearchHistory", method = RequestMethod.POST, headers = "Authorization")
public String getBenDirectoryHistory(
Expand All @@ -72,7 +72,7 @@ public String getBenDirectoryHistory(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Store directory serach history")
@RequestMapping(value = "/save/directorySearchHistory", method = RequestMethod.POST, headers = "Authorization")
public String directorySearchHistory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class DiseaseController {
@Autowired
DiseaseService diseaseService;

@CrossOrigin()

@Operation(summary = "Save disease")
@PostMapping(value = "/saveDisease", headers = "Authorization", produces = {
"application/json" })
Expand All @@ -57,7 +57,7 @@ public String saveDisease(@RequestBody String request) {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Delete disease")
@PostMapping(value = "/deleteDisease", headers = "Authorization", produces = {
"application/json" })
Expand All @@ -75,7 +75,7 @@ public String deleteDisease(@RequestBody String request) {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Get diseases")
@PostMapping(value = "/getDisease", headers = "Authorization", produces = {
"application/json" })
Expand All @@ -93,7 +93,7 @@ public String getDisease(@RequestBody String request) {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Update disease")
@PostMapping(value = "/updateDisease", headers = "Authorization", produces = {
"application/json" })
Expand All @@ -111,7 +111,7 @@ public String updateDisease(@RequestBody String request) {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Get available disease")
@PostMapping(value = "/getAvailableDiseases", headers = "Authorization", produces = { "application/json" })
public String getAvailableDiseases() {
Expand All @@ -128,7 +128,7 @@ public String getAvailableDiseases() {
return response.toString();
}

@CrossOrigin()

@Operation(summary = "Get disease by id")
@PostMapping(value = "/getDiseasesByID", headers = "Authorization", produces = {
"application/json" })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class DiseaseScreeningController {
@Autowired
private QuestionScoreService questionScoreService;

@CrossOrigin

@Operation(summary = "Fetch disease screening questions")
@PostMapping(value = "/get/questions", headers = "Authorization")
public String fetchQuestions(
Expand All @@ -81,7 +81,7 @@ public String fetchQuestions(
return output.toString();
}

@CrossOrigin

@Operation(summary = "Fetch disease screening answers")
@PostMapping(value = "/get/answers", headers = "Authorization")
public String fetchAnswers(@Parameter(description = "{\"questionID\":\"integer\"}") @RequestBody String request) {
Expand Down
Loading
Loading