mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-24 23:27:25 -04:00
Fixes CORS headers needed by Elastic clients (#85791)
* Fixes CORS headers needed by Elastic clients Updates the default value for the `http.cors.allow-headers` setting to include headers used by Elastic client libraries. Also adds the `access-control-expose-headers` header to responses to CORS requests so that clients can successfully perform their product check.
This commit is contained in:
parent
354d3aea18
commit
484d3f4ada
5 changed files with 62 additions and 4 deletions
5
docs/changelog/85791.yaml
Normal file
5
docs/changelog/85791.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
pr: 85791
|
||||
summary: Fixes CORS headers needed by Elastic clients
|
||||
area: Infra/REST API
|
||||
type: bug
|
||||
issues: []
|
|
@ -119,9 +119,16 @@ Which methods to allow. Defaults to `OPTIONS, HEAD, GET, POST, PUT, DELETE`.
|
|||
// tag::http-cors-allow-headers-tag[]
|
||||
`http.cors.allow-headers` {ess-icon}::
|
||||
(<<static-cluster-setting,Static>>, string)
|
||||
Which headers to allow. Defaults to `X-Requested-With, Content-Type, Content-Length`.
|
||||
Which headers to allow. Defaults to `X-Requested-With, Content-Type, Content-Length, Authorization, Accept, User-Agent, X-Elastic-Client-Meta`.
|
||||
// end::http-cors-allow-headers-tag[]
|
||||
|
||||
[[http-cors-expose-headers]]
|
||||
// tag::http-cors-expose-headers-tag[]
|
||||
`http.cors.expose-headers` {ess-icon}::
|
||||
(<<static-cluster-setting,Static>>)
|
||||
Which response headers to expose in the client. Defaults to `X-elastic-product`.
|
||||
// end::http-cors-expose-headers-tag[]
|
||||
|
||||
[[http-cors-allow-credentials]]
|
||||
// tag::http-cors-allow-credentials-tag[]
|
||||
`http.cors.allow-credentials` {ess-icon}::
|
||||
|
|
|
@ -54,6 +54,7 @@ import static org.elasticsearch.http.HttpTransportSettings.SETTING_CORS_ALLOW_HE
|
|||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_CORS_ALLOW_METHODS;
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_CORS_ALLOW_ORIGIN;
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_CORS_ENABLED;
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_CORS_EXPOSE_HEADERS;
|
||||
import static org.elasticsearch.http.HttpTransportSettings.SETTING_CORS_MAX_AGE;
|
||||
|
||||
/**
|
||||
|
@ -77,6 +78,7 @@ public class CorsHandler {
|
|||
public static final String ACCESS_CONTROL_ALLOW_METHODS = "access-control-allow-methods";
|
||||
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "access-control-allow-origin";
|
||||
public static final String ACCESS_CONTROL_MAX_AGE = "access-control-max-age";
|
||||
public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "access-control-expose-headers";
|
||||
|
||||
private static final Pattern SCHEME_PATTERN = Pattern.compile("^https?://");
|
||||
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss O", Locale.ENGLISH);
|
||||
|
@ -105,6 +107,7 @@ public class CorsHandler {
|
|||
}
|
||||
if (setOrigin(httpRequest, httpResponse)) {
|
||||
setAllowCredentials(httpResponse);
|
||||
setExposeHeaders(httpResponse);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,6 +231,12 @@ public class CorsHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void setExposeHeaders(final HttpResponse response) {
|
||||
for (String header : config.accessControlExposeHeaders) {
|
||||
response.addHeader(ACCESS_CONTROL_EXPOSE_HEADERS, header);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAllowCredentials(final HttpResponse response) {
|
||||
if (config.isCredentialsAllowed()) {
|
||||
response.addHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
|
||||
|
@ -247,6 +256,7 @@ public class CorsHandler {
|
|||
private final boolean credentialsAllowed;
|
||||
private final Set<RestRequest.Method> allowedRequestMethods;
|
||||
private final Set<String> allowedRequestHeaders;
|
||||
private final Set<String> accessControlExposeHeaders;
|
||||
private final long maxAge;
|
||||
|
||||
public Config(Builder builder) {
|
||||
|
@ -257,6 +267,7 @@ public class CorsHandler {
|
|||
this.credentialsAllowed = builder.allowCredentials;
|
||||
this.allowedRequestMethods = Collections.unmodifiableSet(builder.requestMethods);
|
||||
this.allowedRequestHeaders = Collections.unmodifiableSet(builder.requestHeaders);
|
||||
this.accessControlExposeHeaders = Collections.unmodifiableSet(builder.accessControlExposeHeaders);
|
||||
this.maxAge = builder.maxAge;
|
||||
}
|
||||
|
||||
|
@ -314,6 +325,8 @@ public class CorsHandler {
|
|||
+ allowedRequestMethods
|
||||
+ ", allowedRequestHeaders="
|
||||
+ allowedRequestHeaders
|
||||
+ ", accessControlExposeHeaders="
|
||||
+ accessControlExposeHeaders
|
||||
+ ", maxAge="
|
||||
+ maxAge
|
||||
+ '}';
|
||||
|
@ -329,6 +342,7 @@ public class CorsHandler {
|
|||
long maxAge;
|
||||
private final Set<RestRequest.Method> requestMethods = new HashSet<>();
|
||||
private final Set<String> requestHeaders = new HashSet<>();
|
||||
private final Set<String> accessControlExposeHeaders = new HashSet<>();
|
||||
|
||||
private Builder() {
|
||||
anyOrigin = true;
|
||||
|
@ -380,6 +394,11 @@ public class CorsHandler {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder accessControlExposeHeaders(String[] headers) {
|
||||
accessControlExposeHeaders.addAll(Arrays.asList(headers));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Config build() {
|
||||
return new Config(this);
|
||||
}
|
||||
|
@ -427,6 +446,7 @@ public class CorsHandler {
|
|||
Config config = builder.allowedRequestMethods(methods)
|
||||
.maxAge(SETTING_CORS_MAX_AGE.get(settings))
|
||||
.allowedRequestHeaders(Strings.tokenizeToStringArray(SETTING_CORS_ALLOW_HEADERS.get(settings), ","))
|
||||
.accessControlExposeHeaders(Strings.tokenizeToStringArray(SETTING_CORS_EXPOSE_HEADERS.get(settings), ","))
|
||||
.build();
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,13 @@ public final class HttpTransportSettings {
|
|||
);
|
||||
public static final Setting<String> SETTING_CORS_ALLOW_HEADERS = new Setting<>(
|
||||
"http.cors.allow-headers",
|
||||
"X-Requested-With,Content-Type,Content-Length",
|
||||
"X-Requested-With,Content-Type,Content-Length,Authorization,Accept,User-Agent,X-Elastic-Client-Meta",
|
||||
(value) -> value,
|
||||
Property.NodeScope
|
||||
);
|
||||
public static final Setting<String> SETTING_CORS_EXPOSE_HEADERS = new Setting<>(
|
||||
"http.cors.expose-headers",
|
||||
"X-elastic-product",
|
||||
(value) -> value,
|
||||
Property.NodeScope
|
||||
);
|
||||
|
|
|
@ -204,7 +204,15 @@ public class CorsHandlerTests extends ESTestCase {
|
|||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_METHODS), containsInAnyOrder("HEAD", "OPTIONS", "GET", "DELETE", "POST"));
|
||||
assertThat(
|
||||
headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_HEADERS),
|
||||
containsInAnyOrder("X-Requested-With", "Content-Type", "Content-Length")
|
||||
containsInAnyOrder(
|
||||
"X-Requested-With",
|
||||
"Content-Type",
|
||||
"Content-Length",
|
||||
"Authorization",
|
||||
"Accept",
|
||||
"User-Agent",
|
||||
"X-Elastic-Client-Meta"
|
||||
)
|
||||
);
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_CREDENTIALS), containsInAnyOrder("true"));
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_MAX_AGE), containsInAnyOrder("1728000"));
|
||||
|
@ -232,7 +240,15 @@ public class CorsHandlerTests extends ESTestCase {
|
|||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_METHODS), containsInAnyOrder("HEAD", "OPTIONS", "GET", "DELETE", "POST"));
|
||||
assertThat(
|
||||
headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_HEADERS),
|
||||
containsInAnyOrder("X-Requested-With", "Content-Type", "Content-Length")
|
||||
containsInAnyOrder(
|
||||
"X-Requested-With",
|
||||
"Content-Type",
|
||||
"Content-Length",
|
||||
"Authorization",
|
||||
"Accept",
|
||||
"User-Agent",
|
||||
"X-Elastic-Client-Meta"
|
||||
)
|
||||
);
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_CREDENTIALS), containsInAnyOrder("true"));
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_MAX_AGE), containsInAnyOrder("1728000"));
|
||||
|
@ -254,6 +270,7 @@ public class CorsHandlerTests extends ESTestCase {
|
|||
|
||||
Map<String, List<String>> headers = response.headers();
|
||||
assertNull(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_ORIGIN));
|
||||
assertNull(headers.get(CorsHandler.ACCESS_CONTROL_EXPOSE_HEADERS));
|
||||
}
|
||||
|
||||
public void testSetResponseHeadersWithWildcardOrigin() {
|
||||
|
@ -270,6 +287,7 @@ public class CorsHandlerTests extends ESTestCase {
|
|||
|
||||
Map<String, List<String>> headers = response.headers();
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_ORIGIN), containsInAnyOrder("*"));
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_EXPOSE_HEADERS), containsInAnyOrder("X-elastic-product"));
|
||||
assertNull(headers.get(CorsHandler.VARY));
|
||||
}
|
||||
|
||||
|
@ -288,6 +306,7 @@ public class CorsHandlerTests extends ESTestCase {
|
|||
|
||||
Map<String, List<String>> headers = response.headers();
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_ORIGIN), containsInAnyOrder("valid-origin"));
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_EXPOSE_HEADERS), containsInAnyOrder("X-elastic-product"));
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_CREDENTIALS), containsInAnyOrder("true"));
|
||||
assertThat(headers.get(CorsHandler.VARY), containsInAnyOrder(CorsHandler.ORIGIN));
|
||||
}
|
||||
|
@ -308,6 +327,7 @@ public class CorsHandlerTests extends ESTestCase {
|
|||
|
||||
Map<String, List<String>> headers = response.headers();
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_ORIGIN), containsInAnyOrder("valid-origin"));
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_EXPOSE_HEADERS), containsInAnyOrder("X-elastic-product"));
|
||||
assertThat(headers.get(CorsHandler.VARY), containsInAnyOrder(CorsHandler.ORIGIN));
|
||||
if (allowCredentials) {
|
||||
assertThat(headers.get(CorsHandler.ACCESS_CONTROL_ALLOW_CREDENTIALS), containsInAnyOrder("true"));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue