From 1f9e6f31ca85838f9eb60ecba09e8aad6fd98bd1 Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Sat, 5 Oct 2024 16:27:39 +0530 Subject: [PATCH 1/7] Closes #535, allowing to configure cors through spring properties --- .../ui/config/CorsGlobalConfiguration.java | 12 ++++++++---- .../io/kafbat/ui/config/CorsProperties.java | 18 ++++++++++++++++++ api/src/main/resources/application.yml | 6 ++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 api/src/main/java/io/kafbat/ui/config/CorsProperties.java 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..714fa349a 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java @@ -1,5 +1,6 @@ package io.kafbat.ui.config; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; @@ -15,6 +16,9 @@ @Configuration public class CorsGlobalConfiguration { + @Autowired + private CorsProperties corsProperties; + @Bean public WebFilter corsFilter() { return (final ServerWebExchange ctx, final WebFilterChain chain) -> { @@ -22,10 +26,10 @@ 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"); + headers.add("Access-Control-Allow-Origin", corsProperties.getAllowedOrigins()); + headers.add("Access-Control-Allow-Methods", corsProperties.getAllowedMethods()); + headers.add("Access-Control-Max-Age", corsProperties.getMaxAge()); + headers.add("Access-Control-Allow-Headers", corsProperties.getAllowedHeaders()); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); diff --git a/api/src/main/java/io/kafbat/ui/config/CorsProperties.java b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java new file mode 100644 index 000000000..a3c1a47ea --- /dev/null +++ b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java @@ -0,0 +1,18 @@ +package io.kafbat.ui.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import lombok.Data; + +@Component +@ConfigurationProperties(prefix = "cors") +@Data + +public class CorsProperties { + + private String allowedOrigins; + private String allowedMethods; + private String allowedHeaders; + private String maxAge; + +} diff --git a/api/src/main/resources/application.yml b/api/src/main/resources/application.yml index ba26c1f9c..d62e9cb39 100644 --- a/api/src/main/resources/application.yml +++ b/api/src/main/resources/application.yml @@ -19,3 +19,9 @@ logging: reactor.netty.http.server.AccessLog: INFO org.hibernate.validator: WARN +cors: + allowed-origins: "*" + allowed-methods: "GET, PUT, POST, DELETE, OPTIONS" + allowed-headers: "Content-Type" + max-age: "3600" + From cbc87435060c778b3cb5b2f278e8fab8e53fab27 Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Sat, 19 Oct 2024 14:04:12 +0530 Subject: [PATCH 2/7] Correct checkstyle --- api/src/main/java/io/kafbat/ui/config/CorsProperties.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/io/kafbat/ui/config/CorsProperties.java b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java index a3c1a47ea..e32a00cf1 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsProperties.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java @@ -1,12 +1,12 @@ package io.kafbat.ui.config; +import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import lombok.Data; +@Data @Component @ConfigurationProperties(prefix = "cors") -@Data public class CorsProperties { From 0228b5b236769c499394122ae11e058f76950380 Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Sat, 5 Oct 2024 16:27:39 +0530 Subject: [PATCH 3/7] Closes #535, allowing to configure cors through spring properties --- .../ui/config/CorsGlobalConfiguration.java | 18 +++++---- .../io/kafbat/ui/config/CorsProperties.java | 18 +++++++++ .../GlobalErrorWebExceptionHandler.java | 4 +- api/src/main/resources/application.yml | 7 ++++ .../main/resources/swagger/kafbat-ui-api.yaml | 39 +++++++++++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 api/src/main/java/io/kafbat/ui/config/CorsProperties.java 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 d39fda91d..b6afbf54c 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java @@ -1,5 +1,6 @@ package io.kafbat.ui.config; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; @@ -15,6 +16,9 @@ @Configuration public class CorsGlobalConfiguration { + @Autowired + private static CorsProperties corsProperties; + @Bean public WebFilter corsFilter() { return (final ServerWebExchange ctx, final WebFilterChain chain) -> { @@ -22,7 +26,7 @@ public WebFilter corsFilter() { final ServerHttpResponse response = ctx.getResponse(); final HttpHeaders headers = response.getHeaders(); - fillCorsHeader(headers, request); + fillCorsHeader(headers); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); @@ -33,11 +37,11 @@ public WebFilter corsFilter() { }; } - 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"); + public static void fillCorsHeader(HttpHeaders responseHeaders) { + responseHeaders.add("Access-Control-Allow-Origin", corsProperties.getAllowedOrigins()); + responseHeaders.add("Access-Control-Allow-Credentials", corsProperties.getAllowCredentials()); + responseHeaders.add("Access-Control-Allow-Methods", corsProperties.getAllowedMethods()); + responseHeaders.add("Access-Control-Max-Age", corsProperties.getMaxAge()); + responseHeaders.add("Access-Control-Allow-Headers", corsProperties.getAllowedHeaders()); } } diff --git a/api/src/main/java/io/kafbat/ui/config/CorsProperties.java b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java new file mode 100644 index 000000000..4ec728f4a --- /dev/null +++ b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java @@ -0,0 +1,18 @@ +package io.kafbat.ui.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import lombok.Data; + +@Component +@ConfigurationProperties(prefix = "cors") +@Data +public class CorsProperties { + + private String allowedOrigins; + private String allowedMethods; + private String allowedHeaders; + private String allowCredentials; + private String maxAge; + +} 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 61236f801..0578e5fa2 100644 --- a/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java +++ b/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java @@ -151,9 +151,7 @@ private String requestId(ServerRequest request) { } private Consumer headers(ServerRequest request) { - return (HttpHeaders headers) -> { - CorsGlobalConfiguration.fillCorsHeader(headers, request.exchange().getRequest()); - }; + return CorsGlobalConfiguration::fillCorsHeader; } private BigDecimal currentTimestamp() { diff --git a/api/src/main/resources/application.yml b/api/src/main/resources/application.yml index ba26c1f9c..ba3178109 100644 --- a/api/src/main/resources/application.yml +++ b/api/src/main/resources/application.yml @@ -19,3 +19,10 @@ logging: reactor.netty.http.server.AccessLog: INFO org.hibernate.validator: WARN +cors: + allowed-origins: "*" + allowed-methods: "GET, PUT, POST, DELETE, OPTIONS" + allowed-headers: "Content-Type" + allow-credentials: "true" + max-age: "3600" + diff --git a/contract/src/main/resources/swagger/kafbat-ui-api.yaml b/contract/src/main/resources/swagger/kafbat-ui-api.yaml index 315c4a17e..c707f1415 100644 --- a/contract/src/main/resources/swagger/kafbat-ui-api.yaml +++ b/contract/src/main/resources/swagger/kafbat-ui-api.yaml @@ -4391,3 +4391,42 @@ components: type: object additionalProperties: type: string + cors: + type: object + properties: + allowedOrigins: + type: array + items: + type: string + description: >- + List of allowed origins for CORS. + If not provided, defaults to allowing all origins (`*`) + default: ["*"] + allowedMethods: + type: array + items: + type: string + description: >- + List of allowed HTTP methods for CORS + If not provided, defaults to `GET, POST, PUT, DELETE, OPTIONS`. + default: ["GET", "POST", "PUT", "DELETE", "OPTIONS"] + allowedHeaders: + type: array + items: + type: string + description: >- + List of allowed HTTP headers for CORS. + If not provided, defaults to allowing all headers (`*`). + default: ["*"] + allowCredentials: + type: boolean + description: >- + Whether to allow credentials in CORS requests. + If not provided, defaults to `true` + default: true + maxAge: + type: integer + description: >- + Maximum age (in seconds) for CORS preflight requests. + If not provided, defaults to `3600` seconds. + default: 3600 From 1ef3f3b981da5419004502b181aaf5d6b4ffcebb Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Fri, 24 Jan 2025 01:06:07 +0530 Subject: [PATCH 4/7] Add spring annotation --- .../main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java | 1 + 1 file changed, 1 insertion(+) 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 d4d3c51b9..b6afbf54c 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java @@ -1,5 +1,6 @@ package io.kafbat.ui.config; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; From c011913eea2c41797abeea04afec28596cd7dc1a Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Fri, 24 Jan 2025 01:18:59 +0530 Subject: [PATCH 5/7] Correct checkstyle --- api/src/main/java/io/kafbat/ui/config/CorsProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/io/kafbat/ui/config/CorsProperties.java b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java index 4ec728f4a..60858cde6 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsProperties.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsProperties.java @@ -1,8 +1,8 @@ package io.kafbat.ui.config; +import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import lombok.Data; @Component @ConfigurationProperties(prefix = "cors") From 8d66ec08b2a6c66c4251724157ce5f144718fdf7 Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Fri, 24 Jan 2025 14:13:51 +0530 Subject: [PATCH 6/7] remove static context from CorsProperties injection --- .../java/io/kafbat/ui/config/CorsGlobalConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 b6afbf54c..68d819a33 100644 --- a/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java +++ b/api/src/main/java/io/kafbat/ui/config/CorsGlobalConfiguration.java @@ -17,7 +17,7 @@ public class CorsGlobalConfiguration { @Autowired - private static CorsProperties corsProperties; + private CorsProperties corsProperties; @Bean public WebFilter corsFilter() { @@ -37,7 +37,7 @@ public WebFilter corsFilter() { }; } - public static void fillCorsHeader(HttpHeaders responseHeaders) { + public void fillCorsHeader(HttpHeaders responseHeaders) { responseHeaders.add("Access-Control-Allow-Origin", corsProperties.getAllowedOrigins()); responseHeaders.add("Access-Control-Allow-Credentials", corsProperties.getAllowCredentials()); responseHeaders.add("Access-Control-Allow-Methods", corsProperties.getAllowedMethods()); From 2f6b5c78155553788324f058289fddabd9dbc9b5 Mon Sep 17 00:00:00 2001 From: Aditya Baldwa Date: Fri, 24 Jan 2025 14:24:55 +0530 Subject: [PATCH 7/7] Refactor fillCorsHeader to be non-static for proper dependency injection --- .../kafbat/ui/exception/GlobalErrorWebExceptionHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 0578e5fa2..24b26f3a5 100644 --- a/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java +++ b/api/src/main/java/io/kafbat/ui/exception/GlobalErrorWebExceptionHandler.java @@ -12,6 +12,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.web.WebProperties; import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler; import org.springframework.boot.web.reactive.error.ErrorAttributes; @@ -38,6 +39,9 @@ @Order(Ordered.HIGHEST_PRECEDENCE) public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { + @Autowired + private CorsGlobalConfiguration corsGlobalConfiguration; + public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes, ApplicationContext applicationContext, ServerCodecConfigurer codecConfigurer) { @@ -151,7 +155,7 @@ private String requestId(ServerRequest request) { } private Consumer headers(ServerRequest request) { - return CorsGlobalConfiguration::fillCorsHeader; + return corsGlobalConfiguration::fillCorsHeader; } private BigDecimal currentTimestamp() {