Skip to content

Commit 19b24f5

Browse files
authored
[ISSUE #13951] Add configurable CORS filter for console module (#13966)
* [ISSUE #13951] Add configurable CORS filter for console module - Add ConsoleCorsConfig class for managing CORS configurations - Update ConsoleWebConfig to use configurable CORS settings - Add configuration properties in application.properties - Add unit tests for ConsoleCorsConfig and ConsoleWebConfig - Maintain backward compatibility with default settings * trigger ci * [ISSUE #13951] Simplify ConsoleCorsConfig implementation
1 parent ce3b2ac commit 19b24f5

File tree

5 files changed

+248
-5
lines changed

5 files changed

+248
-5
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 1999-2025 Alibaba Group Holding Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.alibaba.nacos.console.config;
18+
19+
import com.alibaba.nacos.common.utils.StringUtils;
20+
import com.alibaba.nacos.sys.env.EnvUtil;
21+
22+
import java.util.Arrays;
23+
import java.util.Collections;
24+
import java.util.List;
25+
26+
/**
27+
* Nacos console cors configurations.
28+
*
29+
* @author zhan7236
30+
*/
31+
public class ConsoleCorsConfig {
32+
33+
private static final String CONSOLE_CORS_PREFIX = "nacos.console.cors.";
34+
35+
private static final String ALLOW_CREDENTIALS_KEY = CONSOLE_CORS_PREFIX + "allow-credentials";
36+
37+
private static final String ALLOWED_HEADERS_KEY = CONSOLE_CORS_PREFIX + "allowed-headers";
38+
39+
private static final String MAX_AGE_KEY = CONSOLE_CORS_PREFIX + "max-age";
40+
41+
private static final String ALLOWED_METHODS_KEY = CONSOLE_CORS_PREFIX + "allowed-methods";
42+
43+
private static final String ALLOWED_ORIGINS_KEY = CONSOLE_CORS_PREFIX + "allowed-origins";
44+
45+
private static final boolean DEFAULT_ALLOW_CREDENTIALS = true;
46+
47+
private static final long DEFAULT_MAX_AGE = 18000L;
48+
49+
private final boolean allowCredentials;
50+
51+
private final List<String> allowedHeaders;
52+
53+
private final long maxAge;
54+
55+
private final List<String> allowedMethods;
56+
57+
private final List<String> allowedOrigins;
58+
59+
public ConsoleCorsConfig() {
60+
this.allowCredentials = EnvUtil.getProperty(ALLOW_CREDENTIALS_KEY, Boolean.class, DEFAULT_ALLOW_CREDENTIALS);
61+
this.allowedHeaders = parseListProperty(ALLOWED_HEADERS_KEY);
62+
this.maxAge = EnvUtil.getProperty(MAX_AGE_KEY, Long.class, DEFAULT_MAX_AGE);
63+
this.allowedMethods = parseListProperty(ALLOWED_METHODS_KEY);
64+
this.allowedOrigins = parseListProperty(ALLOWED_ORIGINS_KEY);
65+
}
66+
67+
private List<String> parseListProperty(String key) {
68+
String value = EnvUtil.getProperty(key, "");
69+
if (StringUtils.isNotBlank(value)) {
70+
return Arrays.asList(value.split(","));
71+
}
72+
return Collections.emptyList();
73+
}
74+
75+
public boolean isAllowCredentials() {
76+
return allowCredentials;
77+
}
78+
79+
public List<String> getAllowedHeaders() {
80+
return allowedHeaders;
81+
}
82+
83+
public long getMaxAge() {
84+
return maxAge;
85+
}
86+
87+
public List<String> getAllowedMethods() {
88+
return allowedMethods;
89+
}
90+
91+
public List<String> getAllowedOrigins() {
92+
return allowedOrigins;
93+
}
94+
95+
@Override
96+
public String toString() {
97+
return "ConsoleCorsConfig{" + "allowCredentials=" + allowCredentials + ", allowedHeaders=" + allowedHeaders
98+
+ ", maxAge=" + maxAge + ", allowedMethods=" + allowedMethods + ", allowedOrigins=" + allowedOrigins
99+
+ '}';
100+
}
101+
}

console/src/main/java/com/alibaba/nacos/console/config/ConsoleWebConfig.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,24 @@ public void init() {
6565
@Bean
6666
public CorsFilter corsFilter() {
6767
CorsConfiguration config = new CorsConfiguration();
68-
config.setAllowCredentials(true);
69-
config.addAllowedHeader("*");
70-
config.setMaxAge(18000L);
71-
config.addAllowedMethod("*");
72-
config.addAllowedOriginPattern("*");
68+
ConsoleCorsConfig corsConfig = new ConsoleCorsConfig();
69+
config.setAllowCredentials(corsConfig.isAllowCredentials());
70+
if (corsConfig.getAllowedHeaders().isEmpty()) {
71+
config.addAllowedHeader("*");
72+
} else {
73+
config.setAllowedHeaders(corsConfig.getAllowedHeaders());
74+
}
75+
config.setMaxAge(corsConfig.getMaxAge());
76+
if (corsConfig.getAllowedMethods().isEmpty()) {
77+
config.addAllowedMethod("*");
78+
} else {
79+
config.setAllowedMethods(corsConfig.getAllowedMethods());
80+
}
81+
if (corsConfig.getAllowedOrigins().isEmpty()) {
82+
config.addAllowedOriginPattern("*");
83+
} else {
84+
config.setAllowedOrigins(corsConfig.getAllowedOrigins());
85+
}
7386
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
7487
source.registerCorsConfiguration("/**", config);
7588
return new CorsFilter(source);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 1999-2025 Alibaba Group Holding Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.alibaba.nacos.console.config;
18+
19+
import com.alibaba.nacos.sys.env.EnvUtil;
20+
import org.junit.jupiter.api.AfterEach;
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.junit.jupiter.api.Test;
23+
import org.springframework.core.env.ConfigurableEnvironment;
24+
import org.springframework.mock.env.MockEnvironment;
25+
26+
import java.util.Arrays;
27+
import java.util.Collections;
28+
29+
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
import static org.junit.jupiter.api.Assertions.assertFalse;
31+
import static org.junit.jupiter.api.Assertions.assertTrue;
32+
33+
/**
34+
* ConsoleCorsConfig test.
35+
*/
36+
class ConsoleCorsConfigTest {
37+
38+
private ConfigurableEnvironment cachedEnvironment;
39+
40+
@BeforeEach
41+
void setUp() {
42+
cachedEnvironment = EnvUtil.getEnvironment();
43+
}
44+
45+
@AfterEach
46+
void tearDown() {
47+
EnvUtil.setEnvironment(cachedEnvironment);
48+
}
49+
50+
@Test
51+
void testDefaultConfiguration() {
52+
MockEnvironment environment = new MockEnvironment();
53+
EnvUtil.setEnvironment(environment);
54+
55+
ConsoleCorsConfig config = new ConsoleCorsConfig();
56+
57+
assertTrue(config.isAllowCredentials());
58+
assertEquals(Collections.emptyList(), config.getAllowedHeaders());
59+
assertEquals(18000L, config.getMaxAge());
60+
assertEquals(Collections.emptyList(), config.getAllowedMethods());
61+
assertEquals(Collections.emptyList(), config.getAllowedOrigins());
62+
}
63+
64+
@Test
65+
void testCustomConfiguration() {
66+
MockEnvironment environment = new MockEnvironment();
67+
environment.setProperty("nacos.console.cors.allow-credentials", "false");
68+
environment.setProperty("nacos.console.cors.allowed-headers", "Content-Type,Authorization");
69+
environment.setProperty("nacos.console.cors.max-age", "3600");
70+
environment.setProperty("nacos.console.cors.allowed-methods", "GET,POST,PUT");
71+
environment.setProperty("nacos.console.cors.allowed-origins", "http://localhost:8080,https://example.com");
72+
EnvUtil.setEnvironment(environment);
73+
74+
ConsoleCorsConfig config = new ConsoleCorsConfig();
75+
76+
assertFalse(config.isAllowCredentials());
77+
assertEquals(Arrays.asList("Content-Type", "Authorization"), config.getAllowedHeaders());
78+
assertEquals(3600L, config.getMaxAge());
79+
assertEquals(Arrays.asList("GET", "POST", "PUT"), config.getAllowedMethods());
80+
assertEquals(Arrays.asList("http://localhost:8080", "https://example.com"), config.getAllowedOrigins());
81+
}
82+
83+
@Test
84+
void testToString() {
85+
MockEnvironment environment = new MockEnvironment();
86+
EnvUtil.setEnvironment(environment);
87+
88+
ConsoleCorsConfig config = new ConsoleCorsConfig();
89+
String result = config.toString();
90+
91+
assertTrue(result.contains("ConsoleCorsConfig"));
92+
assertTrue(result.contains("allowCredentials=true"));
93+
assertTrue(result.contains("maxAge=18000"));
94+
}
95+
}

console/src/test/java/com/alibaba/nacos/console/config/ConsoleWebConfigTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,21 @@ void corsFilter() {
8181
assertNotNull(consoleWebConfig.corsFilter());
8282
}
8383

84+
@Test
85+
void corsFilterWithCustomConfiguration() {
86+
MockEnvironment environment = new MockEnvironment();
87+
environment.setProperty(Constants.Auth.NACOS_CORE_AUTH_ADMIN_ENABLED, "false");
88+
environment.setProperty("nacos.console.cors.allow-credentials", "false");
89+
environment.setProperty("nacos.console.cors.allowed-headers", "Content-Type");
90+
environment.setProperty("nacos.console.cors.max-age", "3600");
91+
environment.setProperty("nacos.console.cors.allowed-methods", "GET,POST");
92+
environment.setProperty("nacos.console.cors.allowed-origins", "http://localhost:8080");
93+
EnvUtil.setEnvironment(environment);
94+
95+
assertNotNull(consoleWebConfig.corsFilter());
96+
EnvUtil.setEnvironment(cachedEnvironment);
97+
}
98+
8499
@Test
85100
void xssFilter() {
86101
assertNotNull(consoleWebConfig.xssFilter());

distribution/conf/application.properties

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ management.metrics.export.influx.enabled=false
5454
#management.metrics.export.influx.consistency=one
5555
#management.metrics.export.influx.compressed=true
5656

57+
#*************** Console Related Configurations ***************#
58+
59+
### CORS (Cross-Origin Resource Sharing) configurations for console
60+
### Whether to allow credentials (cookies, authorization headers, TLS client certificates)
61+
# nacos.console.cors.allow-credentials=true
62+
63+
### Allowed headers, comma separated. Empty means allow all headers (*)
64+
# nacos.console.cors.allowed-headers=
65+
66+
### Maximum age (in seconds) of the CORS preflight request cache
67+
# nacos.console.cors.max-age=18000
68+
69+
### Allowed HTTP methods, comma separated. Empty means allow all methods (*)
70+
# nacos.console.cors.allowed-methods=
71+
72+
### Allowed origins, comma separated. Empty means allow all origin patterns (*)
73+
### Example: nacos.console.cors.allowed-origins=http://localhost:8080,https://example.com
74+
# nacos.console.cors.allowed-origins=
75+
5776
#*************** Core Related Configurations ***************#
5877

5978
### set the WorkerID manually

0 commit comments

Comments
 (0)