From 958bb063433b300cda04463b0294783d994300fe Mon Sep 17 00:00:00 2001 From: "H@di" Date: Sat, 21 Sep 2024 14:25:16 +0330 Subject: [PATCH 1/3] Fix CORS problem in case of OPTION requests on read only topics (#555) --- api/src/main/java/io/kafbat/ui/config/ReadOnlyModeFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/io/kafbat/ui/config/ReadOnlyModeFilter.java b/api/src/main/java/io/kafbat/ui/config/ReadOnlyModeFilter.java index 81165e988..ac7b24238 100644 --- a/api/src/main/java/io/kafbat/ui/config/ReadOnlyModeFilter.java +++ b/api/src/main/java/io/kafbat/ui/config/ReadOnlyModeFilter.java @@ -33,7 +33,8 @@ public class ReadOnlyModeFilter implements WebFilter { @NotNull @Override public Mono filter(ServerWebExchange exchange, @NotNull WebFilterChain chain) { - var isSafeMethod = exchange.getRequest().getMethod() == HttpMethod.GET; + var isSafeMethod = + exchange.getRequest().getMethod() == HttpMethod.GET || exchange.getRequest().getMethod() == HttpMethod.OPTIONS; if (isSafeMethod) { return chain.filter(exchange); } From 78d8aecca2040de7d901e1e5acd1639edd7a0aee Mon Sep 17 00:00:00 2001 From: "H@di" Date: Sat, 21 Sep 2024 15:50:42 +0330 Subject: [PATCH 2/3] Fix CORS headers on error handling (#555) --- .../io/kafbat/ui/config/CorsGlobalConfiguration.java | 11 +++++++---- .../ui/exception/GlobalErrorWebExceptionHandler.java | 5 +++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java index 4713dfd37..94350c260 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java @@ -22,10 +22,7 @@ public WebFilter corsFilter() { final ServerHttpResponse response = ctx.getResponse(); final HttpHeaders headers = response.getHeaders(); - headers.add("Access-Control-Allow-Origin", "*"); - headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS"); - headers.add("Access-Control-Max-Age", "3600"); - headers.add("Access-Control-Allow-Headers", "Content-Type"); + fillCorsHeader(headers); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); @@ -36,4 +33,10 @@ public WebFilter corsFilter() { }; } + public static void fillCorsHeader(HttpHeaders responseHeaders) { + responseHeaders.add("Access-Control-Allow-Origin", "*"); + responseHeaders.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS"); + responseHeaders.add("Access-Control-Max-Age", "3600"); + responseHeaders.add("Access-Control-Allow-Headers", "Content-Type"); + } } diff --git a/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java b/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java index b4c978ac2..dc44ca519 100644 --- a/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java +++ b/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java @@ -2,6 +2,7 @@ import com.google.common.base.Throwables; import com.google.common.collect.Sets; +import io.kafbat.ui.config.CorsGlobalConfiguration; import io.kafbat.ui.model.ErrorResponseDTO; import java.math.BigDecimal; import java.util.List; @@ -78,6 +79,7 @@ private Mono renderDefault(Throwable throwable, ServerRequest re return ServerResponse .status(ErrorCode.UNEXPECTED.httpStatus()) .contentType(MediaType.APPLICATION_JSON) + .headers(CorsGlobalConfiguration::fillCorsHeader) .bodyValue(response); } @@ -92,6 +94,7 @@ private Mono render(CustomBaseException baseException, ServerReq return ServerResponse .status(errorCode.httpStatus()) .contentType(MediaType.APPLICATION_JSON) + .headers(CorsGlobalConfiguration::fillCorsHeader) .bodyValue(response); } @@ -122,6 +125,7 @@ private Mono render(WebExchangeBindException exception, ServerRe return ServerResponse .status(HttpStatus.BAD_REQUEST) .contentType(MediaType.APPLICATION_JSON) + .headers(CorsGlobalConfiguration::fillCorsHeader) .bodyValue(response); } @@ -136,6 +140,7 @@ private Mono render(ResponseStatusException exception, ServerReq return ServerResponse .status(exception.getStatusCode()) .contentType(MediaType.APPLICATION_JSON) + .headers(CorsGlobalConfiguration::fillCorsHeader) .bodyValue(response); } From aebf6b27da9adf1ab8fa0f049d7a10f6d1c4350d Mon Sep 17 00:00:00 2001 From: "H@di" Date: Sat, 21 Sep 2024 15:53:40 +0330 Subject: [PATCH 3/3] Fix CORS header configs (#555) * add Access-Control-Allow-Credentials=true * use real request origin instead of '*' to fill Access-Control-Allow-Origin, due to high security standards of modern browsers --- .../ui/config/CorsGlobalConfiguration.java | 7 ++++--- .../GlobalErrorWebExceptionHandler.java | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java index 94350c260..d39fda91d 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java @@ -22,7 +22,7 @@ public WebFilter corsFilter() { final ServerHttpResponse response = ctx.getResponse(); final HttpHeaders headers = response.getHeaders(); - fillCorsHeader(headers); + fillCorsHeader(headers, request); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); @@ -33,8 +33,9 @@ public WebFilter corsFilter() { }; } - public static void fillCorsHeader(HttpHeaders responseHeaders) { - responseHeaders.add("Access-Control-Allow-Origin", "*"); + public static void fillCorsHeader(HttpHeaders responseHeaders, ServerHttpRequest request) { + responseHeaders.add("Access-Control-Allow-Origin", request.getHeaders().getOrigin()); + responseHeaders.add("Access-Control-Allow-Credentials", "true"); responseHeaders.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS"); responseHeaders.add("Access-Control-Max-Age", "3600"); responseHeaders.add("Access-Control-Allow-Headers", "Content-Type"); diff --git a/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java b/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java index dc44ca519..61236f801 100644 --- a/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java +++ b/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import org.springframework.boot.autoconfigure.web.WebProperties; @@ -17,6 +18,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; @@ -79,7 +81,7 @@ private Mono renderDefault(Throwable throwable, ServerRequest re return ServerResponse .status(ErrorCode.UNEXPECTED.httpStatus()) .contentType(MediaType.APPLICATION_JSON) - .headers(CorsGlobalConfiguration::fillCorsHeader) + .headers(headers(request)) .bodyValue(response); } @@ -94,7 +96,7 @@ private Mono render(CustomBaseException baseException, ServerReq return ServerResponse .status(errorCode.httpStatus()) .contentType(MediaType.APPLICATION_JSON) - .headers(CorsGlobalConfiguration::fillCorsHeader) + .headers(headers(request)) .bodyValue(response); } @@ -125,7 +127,7 @@ private Mono render(WebExchangeBindException exception, ServerRe return ServerResponse .status(HttpStatus.BAD_REQUEST) .contentType(MediaType.APPLICATION_JSON) - .headers(CorsGlobalConfiguration::fillCorsHeader) + .headers(headers(request)) .bodyValue(response); } @@ -140,7 +142,7 @@ private Mono render(ResponseStatusException exception, ServerReq return ServerResponse .status(exception.getStatusCode()) .contentType(MediaType.APPLICATION_JSON) - .headers(CorsGlobalConfiguration::fillCorsHeader) + .headers(headers(request)) .bodyValue(response); } @@ -148,6 +150,12 @@ private String requestId(ServerRequest request) { return request.exchange().getRequest().getId(); } + private Consumer headers(ServerRequest request) { + return (HttpHeaders headers) -> { + CorsGlobalConfiguration.fillCorsHeader(headers, request.exchange().getRequest()); + }; + } + private BigDecimal currentTimestamp() { return BigDecimal.valueOf(System.currentTimeMillis()); }