From fbf982528b405f7ce2e030a7bf023c3e4e1d6cc3 Mon Sep 17 00:00:00 2001 From: Keval Kanpariya Date: Thu, 17 Apr 2025 23:45:33 +0530 Subject: [PATCH 1/3] fix(cors): global cors config added controller specific cors config added --- src/main/environment/common_ci.properties | 2 ++ .../environment/common_example.properties | 1 + .../java/com/iemr/tm/config/CorsConfig.java | 24 +++++++++++++++++++ .../schedule/SchedulingController.java | 14 +++++------ .../specialist/SpecialistController.java | 8 +++---- .../iemr/tm/controller/van/VanController.java | 2 +- 6 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/iemr/tm/config/CorsConfig.java diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index f0ed942..b8941f0 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -25,4 +25,6 @@ logging.file.name=@env.SCHEDULER_API_LOGGING_FILE_NAME@ springdoc.api-docs.enabled=@env.SWAGGER_DOC_ENABLED@ springdoc.swagger-ui.enabled=@env.SWAGGER_DOC_ENABLED@ +cors.allowed-origins=@CORS_ALLOWED_ORIGINS@ + diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index d6b4463..6950876 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -22,3 +22,4 @@ jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret logging.path=logs/ logging.file.name=logs/scheduler-api.log +cors.allowed-origins=http://localhost:*,http://127.0.0.1:* \ No newline at end of file diff --git a/src/main/java/com/iemr/tm/config/CorsConfig.java b/src/main/java/com/iemr/tm/config/CorsConfig.java new file mode 100644 index 0000000..4022c48 --- /dev/null +++ b/src/main/java/com/iemr/tm/config/CorsConfig.java @@ -0,0 +1,24 @@ +package com.iemr.tm.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(",")) + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") + .allowedHeaders("*") + .exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed + .allowCredentials(true) + .maxAge(3600); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/tm/controller/schedule/SchedulingController.java b/src/main/java/com/iemr/tm/controller/schedule/SchedulingController.java index 3cb6812..54113b9 100644 --- a/src/main/java/com/iemr/tm/controller/schedule/SchedulingController.java +++ b/src/main/java/com/iemr/tm/controller/schedule/SchedulingController.java @@ -52,7 +52,7 @@ public class SchedulingController { @Autowired private SchedulingService schedulingService; - @CrossOrigin() + @Operation(summary = "Mark availability of specialist") @RequestMapping(value = "markavailability", method = RequestMethod.POST) public String markavailability(@RequestBody String specialistInput1) { @@ -72,7 +72,7 @@ public String markavailability(@RequestBody String specialistInput1) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Mark unavailability of specialist") @RequestMapping(value = "unmarkavailability", method = RequestMethod.POST) public String unmarkavailability(@RequestBody String specialistInput1) { @@ -91,7 +91,7 @@ public String unmarkavailability(@RequestBody String specialistInput1) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Get available slots of specialist for a particular day") @RequestMapping(value = "getavailableSlot", method = RequestMethod.POST) public String getavailableSlot(@RequestBody String specialistInput1) { @@ -109,7 +109,7 @@ public String getavailableSlot(@RequestBody String specialistInput1) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Get available slots of specialist for a particular month") @RequestMapping(value = { "/monthview/{year}", "/monthview/{year}/{month}", "/monthview/{year}/{month}/{day}" }, method = RequestMethod.POST) @@ -131,7 +131,7 @@ public String view(@RequestBody String specialistInput1, @PathVariable("year") I return response.toString(); } - @CrossOrigin() + @Operation(summary = "Book available slots of specialist of a particular day") @RequestMapping(value = "bookSlot", method = RequestMethod.POST) public String bookSlot(@RequestBody String specialistInput1) { @@ -149,7 +149,7 @@ public String bookSlot(@RequestBody String specialistInput1) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Cancel booked slots of specialist of a particular day") @RequestMapping(value = "cancelBookedSlot", method = RequestMethod.POST) public String cancelBookedSlot(@RequestBody String specialistInput1) { @@ -167,7 +167,7 @@ public String cancelBookedSlot(@RequestBody String specialistInput1) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Get day view of particular specialization") @RequestMapping(value = "getdayview", method = RequestMethod.POST) public String getdayview(@RequestBody String specialistInput1) { diff --git a/src/main/java/com/iemr/tm/controller/specialist/SpecialistController.java b/src/main/java/com/iemr/tm/controller/specialist/SpecialistController.java index c42e124..a1e51e5 100644 --- a/src/main/java/com/iemr/tm/controller/specialist/SpecialistController.java +++ b/src/main/java/com/iemr/tm/controller/specialist/SpecialistController.java @@ -50,7 +50,7 @@ public class SpecialistController { @Autowired private SpecialistService specialistService; - @CrossOrigin() + @Operation(summary = "Fetch master specialization") @RequestMapping(value = "masterspecialization", method = RequestMethod.POST) public String markavailability() { @@ -66,7 +66,7 @@ public String markavailability() { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Fetch list of specialists") @RequestMapping(value = "getSpecialist", method = RequestMethod.POST) public String getSpecialist(@RequestBody Specialist specialist) { @@ -83,7 +83,7 @@ public String getSpecialist(@RequestBody Specialist specialist) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Fetch user specialist") @RequestMapping(value = "info/{userID}", method = RequestMethod.GET) public String info(@PathVariable("userID") Long userID) { @@ -101,7 +101,7 @@ public String info(@PathVariable("userID") Long userID) { return response.toString(); } - @CrossOrigin() + @Operation(summary = "Fetch all specialists") @RequestMapping(value = "getSpecialistAll", method = RequestMethod.POST) public String getSpecialistAll(@RequestBody Specialist specialist) { diff --git a/src/main/java/com/iemr/tm/controller/van/VanController.java b/src/main/java/com/iemr/tm/controller/van/VanController.java index 876f593..c723b78 100644 --- a/src/main/java/com/iemr/tm/controller/van/VanController.java +++ b/src/main/java/com/iemr/tm/controller/van/VanController.java @@ -46,7 +46,7 @@ public class VanController { @Autowired private VanService vanService; - @CrossOrigin() + @Operation(summary = "Fetch specialization by van id") @RequestMapping(value = "getvan/{vanid}", method = RequestMethod.GET) public String markavailability(@PathVariable("vanid") Integer vanid) { From 3f4303148f06d79fbeb45d03031f73ea2b90074b Mon Sep 17 00:00:00 2001 From: Keval Kanpariya Date: Sat, 17 May 2025 09:27:01 +0530 Subject: [PATCH 2/3] fix(cors): dynamic cors filter added --- .../environment/common_example.properties | 2 +- .../java/com/iemr/tm/config/CorsConfig.java | 2 +- .../com/iemr/tm/utils/DynamicCorsFilter.java | 37 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 6950876..0786066 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -22,4 +22,4 @@ jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret logging.path=logs/ logging.file.name=logs/scheduler-api.log -cors.allowed-origins=http://localhost:*,http://127.0.0.1:* \ No newline at end of file +cors.allowed-origins=http://localhost:8088 \ No newline at end of file diff --git a/src/main/java/com/iemr/tm/config/CorsConfig.java b/src/main/java/com/iemr/tm/config/CorsConfig.java index 4022c48..5b4a7a7 100644 --- a/src/main/java/com/iemr/tm/config/CorsConfig.java +++ b/src/main/java/com/iemr/tm/config/CorsConfig.java @@ -14,7 +14,7 @@ public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOriginPatterns(allowedOrigins.split(",")) + .allowedOrigins(allowedOrigins) .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed diff --git a/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java b/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java new file mode 100644 index 0000000..f1e30bd --- /dev/null +++ b/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java @@ -0,0 +1,37 @@ +package com.iemr.common.utils; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Arrays; + +@Component +public class DynamicCorsFilter extends OncePerRequestFilter { + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) + throws ServletException, IOException { + + String origin = request.getHeader("Origin"); + if (origin != null && Arrays.asList(allowedOrigins).contains(origin)) { + response.setHeader("Access-Control-Allow-Origin", origin); + } + + if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { + response.setStatus(HttpServletResponse.SC_OK); + } else { + filterChain.doFilter(request, response); + } + } +} From f956d311f8a8fb2ab7e529c4ef8a7b50f89f1168 Mon Sep 17 00:00:00 2001 From: vishwab1 Date: Fri, 23 May 2025 18:44:53 +0530 Subject: [PATCH 3/3] fix(cors): cors origin added --- .../environment/common_example.properties | 2 +- .../java/com/iemr/tm/config/CorsConfig.java | 2 +- .../com/iemr/tm/utils/DynamicCorsFilter.java | 15 +++++---- .../java/com/iemr/tm/utils/FilterConfig.java | 12 +++++-- .../tm/utils/JwtUserIdValidationFilter.java | 33 ++++++++++++++++++- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 0786066..8ac4d97 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -22,4 +22,4 @@ jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret logging.path=logs/ logging.file.name=logs/scheduler-api.log -cors.allowed-origins=http://localhost:8088 \ No newline at end of file +cors.allowed-origins=http://localhost:* \ No newline at end of file diff --git a/src/main/java/com/iemr/tm/config/CorsConfig.java b/src/main/java/com/iemr/tm/config/CorsConfig.java index 5b4a7a7..19166c4 100644 --- a/src/main/java/com/iemr/tm/config/CorsConfig.java +++ b/src/main/java/com/iemr/tm/config/CorsConfig.java @@ -14,7 +14,7 @@ public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOrigins(allowedOrigins) + .allowedOriginPatterns(allowedOrigins.split(",")) .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("Authorization", "Jwttoken") // Explicitly expose headers if needed diff --git a/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java b/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java index f1e30bd..ce6d9db 100644 --- a/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java +++ b/src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java @@ -1,15 +1,16 @@ -package com.iemr.common.utils; +package com.iemr.tm.utils; + +import java.io.IOException; +import java.util.Arrays; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; -import java.util.Arrays; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; @Component public class DynamicCorsFilter extends OncePerRequestFilter { diff --git a/src/main/java/com/iemr/tm/utils/FilterConfig.java b/src/main/java/com/iemr/tm/utils/FilterConfig.java index 48aee27..802a3dd 100644 --- a/src/main/java/com/iemr/tm/utils/FilterConfig.java +++ b/src/main/java/com/iemr/tm/utils/FilterConfig.java @@ -1,19 +1,27 @@ package com.iemr.tm.utils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; + @Configuration public class FilterConfig { + @Value("${cors.allowed-origins}") + private String allowedOrigins; + @Bean public FilterRegistrationBean jwtUserIdValidationFilter( JwtAuthenticationUtil jwtAuthenticationUtil) { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil)); + + // Pass allowedOrigins explicitly to the filter constructor + JwtUserIdValidationFilter filter = new JwtUserIdValidationFilter(jwtAuthenticationUtil, allowedOrigins); + + registrationBean.setFilter(filter); registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints return registrationBean; } - } diff --git a/src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java index 174ed73..c49639b 100644 --- a/src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java @@ -1,9 +1,11 @@ package com.iemr.tm.utils; import java.io.IOException; +import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.iemr.tm.utils.http.AuthorizationHeaderRequestWrapper; @@ -22,9 +24,12 @@ public class JwtUserIdValidationFilter implements Filter { private final JwtAuthenticationUtil jwtAuthenticationUtil; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + private final String allowedOrigins; - public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { + public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil, + @Value("${cors.allowed-origins}") String allowedOrigins) { this.jwtAuthenticationUtil = jwtAuthenticationUtil; + this.allowedOrigins = allowedOrigins; } @Override @@ -37,6 +42,21 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo String contextPath = request.getContextPath(); logger.info("JwtUserIdValidationFilter invoked for path: " + path); + String origin = request.getHeader("Origin"); + if (origin != null && isOriginAllowed(origin)) { + response.setHeader("Access-Control-Allow-Origin", origin); + response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); + response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Jwttoken"); + response.setHeader("Access-Control-Allow-Credentials", "true"); + } + + if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { + logger.info("OPTIONS request - skipping JWT validation"); + response.setStatus(HttpServletResponse.SC_OK); + return; + } + + // Log cookies for debugging Cookie[] cookies = request.getCookies(); if (cookies != null) { @@ -110,6 +130,17 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); } } + + private boolean isOriginAllowed(String origin) { + if (origin == null || allowedOrigins == null || allowedOrigins.trim().isEmpty()) { + logger.warn("No allowed origins configured or origin is null"); + return false; + } + + return Arrays.stream(allowedOrigins.split(",")).map(String::trim) + .anyMatch(pattern -> origin.matches(pattern.replace(".", "\\.").replace("*", ".*"))); + } + private boolean isMobileClient(String userAgent) { if (userAgent == null) return false;