Skip to content

cors configuration for scheduler api service #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions src/main/environment/common_ci.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ [email protected]_API_LOGGING_FILE_NAME@
[email protected]_DOC_ENABLED@
[email protected]_DOC_ENABLED@

cors.allowed-origins=@CORS_ALLOWED_ORIGINS@


1 change: 1 addition & 0 deletions src/main/environment/common_example.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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:*
24 changes: 24 additions & 0 deletions src/main/java/com/iemr/tm/config/CorsConfig.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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)
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/com/iemr/tm/utils/DynamicCorsFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.iemr.tm.utils;

import java.io.IOException;
import java.util.Arrays;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@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);
}
}
}
12 changes: 10 additions & 2 deletions src/main/java/com/iemr/tm/utils/FilterConfig.java
Original file line number Diff line number Diff line change
@@ -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> jwtUserIdValidationFilter(
JwtAuthenticationUtil jwtAuthenticationUtil) {
FilterRegistrationBean<JwtUserIdValidationFilter> 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;
}

}
33 changes: 32 additions & 1 deletion src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down