Skip to content

Commit eb786bf

Browse files
authored
fix: amm-1927 res headers based on origin via allowed cors (#103)
* fix: amm-1927 res headers based on origin via allowed cors * fix: amm-1927 coderabbit comments resolved * localhost regex added * Update regex pattern for localhost in interceptor
2 parents 5dbf22f + ce2a0b0 commit eb786bf

2 files changed

Lines changed: 68 additions & 15 deletions

File tree

src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,46 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
3737
HttpServletResponse response = (HttpServletResponse) servletResponse;
3838

3939
String origin = request.getHeader("Origin");
40+
String method = request.getMethod();
41+
String uri = request.getRequestURI();
4042

4143
logger.debug("Incoming Origin: {}", origin);
4244
logger.debug("Allowed Origins Configured: {}", allowedOrigins);
45+
if ("OPTIONS".equalsIgnoreCase(method)) {
46+
if (origin == null) {
47+
logger.warn("BLOCKED - OPTIONS request without Origin header | Method: {} | URI: {}", method, uri);
48+
response.sendError(HttpServletResponse.SC_FORBIDDEN, "OPTIONS request requires Origin header");
49+
return;
50+
}
51+
if (!isOriginAllowed(origin)) {
52+
logger.warn("BLOCKED - Unauthorized Origin | Origin: {} | Method: {} | URI: {}", origin, method, uri);
53+
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin not allowed");
54+
return;
55+
}
56+
} else {
57+
// For non-OPTIONS requests, validate origin if present
58+
if (origin != null && !isOriginAllowed(origin)) {
59+
logger.warn("BLOCKED - Unauthorized Origin | Origin: {} | Method: {} | URI: {}", origin, method, uri);
60+
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Origin not allowed");
61+
return;
62+
}
63+
}
64+
65+
String path = request.getRequestURI();
66+
String contextPath = request.getContextPath();
4367

4468
if (origin != null && isOriginAllowed(origin)) {
45-
response.setHeader("Access-Control-Allow-Origin", origin);
46-
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
47-
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Jwttoken");
48-
response.setHeader("Vary", "Origin");
69+
response.setHeader("Access-Control-Allow-Origin", origin); // Never use wildcard
70+
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
71+
response.setHeader("Access-Control-Allow-Headers",
72+
"Authorization, Content-Type, Accept, Jwttoken, serverAuthorization, ServerAuthorization, serverauthorization, Serverauthorization");
4973
response.setHeader("Access-Control-Allow-Credentials", "true");
74+
response.setHeader("Access-Control-Max-Age", "3600");
75+
logger.info("Origin Validated | Origin: {} | Method: {} | URI: {}", origin, method, uri);
5076
} else {
5177
logger.warn("Origin [{}] is NOT allowed. CORS headers NOT added.", origin);
5278
}
5379

54-
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
55-
logger.info("OPTIONS request - skipping JWT validation");
56-
response.setStatus(HttpServletResponse.SC_OK);
57-
return;
58-
}
59-
60-
String path = request.getRequestURI();
61-
String contextPath = request.getContextPath();
6280
logger.info("JwtUserIdValidationFilter invoked for path: " + path);
6381

6482
// Log cookies for debugging
@@ -142,7 +160,7 @@ private boolean isOriginAllowed(String origin) {
142160
String regex = pattern
143161
.replace(".", "\\.")
144162
.replace("*", ".*")
145-
.replace("http://localhost:.*", "http://localhost:\\d+"); // special case for wildcard port
163+
.replace("http://localhost:.*", "http://localhost:\\d+");
146164

147165
boolean matched = origin.matches(regex);
148166
return matched;

src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121
*/
2222
package com.iemr.tm.utils.http;
2323

24+
import java.util.Arrays;
25+
2426
import javax.ws.rs.core.MediaType;
2527

2628
import org.slf4j.Logger;
2729
import org.slf4j.LoggerFactory;
2830
import org.springframework.beans.factory.annotation.Autowired;
31+
import org.springframework.beans.factory.annotation.Value;
2932
import org.springframework.stereotype.Component;
3033
import org.springframework.web.servlet.ModelAndView;
3134
import org.springframework.web.servlet.HandlerInterceptor;
@@ -39,6 +42,9 @@
3942
@Component
4043
public class HTTPRequestInterceptor implements HandlerInterceptor {
4144
Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
45+
46+
@Value("${cors.allowed-origins}")
47+
private String allowedOrigins;
4248

4349
private SessionObject sessionObject;
4450

@@ -95,7 +101,13 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
95101
response.getOutputStream().print(output.toString());
96102
response.setContentType(MediaType.APPLICATION_JSON);
97103
response.setContentLength(output.toString().length());
98-
response.setHeader("Access-Control-Allow-Origin", "*");
104+
String origin = request.getHeader("Origin");
105+
if (origin != null && isOriginAllowed(origin)) {
106+
response.setHeader("Access-Control-Allow-Origin", origin);
107+
response.setHeader("Access-Control-Allow-Credentials", "true");
108+
} else if (origin != null) {
109+
logger.warn("CORS headers NOT added for error response | Unauthorized origin: {}", origin);
110+
}
99111
status = false;
100112
}
101113
}
@@ -126,4 +138,27 @@ public void afterCompletion(HttpServletRequest request, HttpServletResponse resp
126138
throws Exception {
127139
logger.debug("In afterCompletion Request Completed");
128140
}
129-
}
141+
142+
/**
143+
* Check if the given origin is allowed based on configured allowedOrigins.
144+
* Uses the same logic as JwtUserIdValidationFilter for consistency.
145+
*
146+
* @param origin The origin to validate
147+
* @return true if origin is allowed, false otherwise
148+
*/
149+
private boolean isOriginAllowed(String origin) {
150+
if (origin == null || allowedOrigins == null || allowedOrigins.trim().isEmpty()) {
151+
return false;
152+
}
153+
154+
return Arrays.stream(allowedOrigins.split(","))
155+
.map(String::trim)
156+
.anyMatch(pattern -> {
157+
String regex = pattern
158+
.replace(".", "\\.")
159+
.replace("*", ".*")
160+
.replace("http://localhost:.*", "http://localhost:\\d+");
161+
return origin.matches(regex);
162+
});
163+
}
164+
}

0 commit comments

Comments
 (0)