From d0f39ed96b150cbcf656956859bc8bea10bf53b6 Mon Sep 17 00:00:00 2001 From: Michael Peterson Date: Tue, 21 Jan 2025 13:21:34 -0500 Subject: [PATCH] Added restriction to no allow index options for clusterInfoOnly endpoint --- .../TransportResolveClusterAction.java | 2 +- .../indices/RestResolveClusterAction.java | 27 +++++++++++++++++++ ...teClusterSecurityRCS1ResolveClusterIT.java | 22 ++++++++++++++- ...teClusterSecurityRCS2ResolveClusterIT.java | 22 ++++++++++++++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/resolve/TransportResolveClusterAction.java b/server/src/main/java/org/elasticsearch/action/admin/indices/resolve/TransportResolveClusterAction.java index b65267cd24303..9d82b1edff0a9 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/resolve/TransportResolveClusterAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/resolve/TransportResolveClusterAction.java @@ -110,7 +110,7 @@ protected void doExecuteForked(Task task, ResolveClusterActionRequest request, A * just "*" since that could be an expensive operation on clusters with thousands of indices/aliases/datastreams */ String[] dummyIndexExpr = new String[] { DUMMY_INDEX_FOR_OLDER_CLUSTERS }; - remoteClusterIndices = remoteClusterService.groupIndices(request.indicesOptions(), dummyIndexExpr, false); + remoteClusterIndices = remoteClusterService.groupIndices(IndicesOptions.DEFAULT, dummyIndexExpr, false); if (remoteClusterIndices.isEmpty()) { // no remote clusters are configured on the primary "querying" cluster listener.onResponse(new ResolveClusterActionResponse(Map.of())); diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestResolveClusterAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestResolveClusterAction.java index 623fcc0500e9e..9126d641d6dfe 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestResolveClusterAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestResolveClusterAction.java @@ -21,7 +21,9 @@ import org.elasticsearch.rest.action.RestToXContentListener; import java.io.IOException; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -47,6 +49,14 @@ protected BaseRestHandler.RestChannelConsumer prepareRequest(RestRequest request } else { indexExpressions = new String[0]; clusterInfoOnly = true; + Set indexOptions = requestIndexOptionsParams(request); + if (indexOptions.isEmpty() == false) { + // this restriction avoids problems with having to send wildcarded index expressions to older clusters + // when no index expression is provided by the user + throw new IllegalArgumentException( + "No index options are allowed on _resolve/cluster when no index expression is specified, but received: " + indexOptions + ); + } } ResolveClusterActionRequest resolveRequest = new ResolveClusterActionRequest( indexExpressions, @@ -58,4 +68,21 @@ protected BaseRestHandler.RestChannelConsumer prepareRequest(RestRequest request .indices() .execute(TransportResolveClusterAction.TYPE, resolveRequest, new RestToXContentListener<>(channel)); } + + private static Set requestIndexOptionsParams(RestRequest request) { + Set indexOptions = new HashSet<>(); + if (request.hasParam("expand_wildcards")) { + indexOptions.add("expand_wildcards"); + } + if (request.hasParam("ignore_unavailable")) { + indexOptions.add("ignore_unavailable"); + } + if (request.hasParam("allow_no_indices")) { + indexOptions.add("allow_no_indices"); + } + if (request.hasParam("ignore_throttled")) { + indexOptions.add("ignore_throttled"); + } + return indexOptions; + } } diff --git a/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS1ResolveClusterIT.java b/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS1ResolveClusterIT.java index b3d1732bcce84..dabda4a216dc7 100644 --- a/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS1ResolveClusterIT.java +++ b/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS1ResolveClusterIT.java @@ -12,6 +12,7 @@ import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; import org.elasticsearch.core.Strings; +import org.elasticsearch.core.Tuple; import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.junit.ClassRule; import org.junit.rules.RuleChain; @@ -261,11 +262,30 @@ public void testResolveClusterUnderRCS1() throws Exception { assertNull(remoteClusterResponse.get("error")); assertNotNull(remoteClusterResponse.get("version")); } + { + // TEST CASE 12: Query resolve/cluster with no index expression, but include index options - should return error + Request getRequest = new Request("GET", "_resolve/cluster"); + Tuple indexOptionTuple = randomFrom( + new Tuple<>("ignore_throttled", "false"), + new Tuple<>("expand_wildcards", "none"), + new Tuple<>("allow_no_indices", "true"), + new Tuple<>("ignore_unavailable", "true") + ); + getRequest.addParameter(indexOptionTuple.v1(), indexOptionTuple.v2()); + + ResponseException exc = expectThrows(ResponseException.class, () -> performRequestWithRemoteSearchUser(getRequest)); + assertThat(exc.getResponse().getStatusLine().getStatusCode(), is(400)); + assertThat( + exc.getMessage(), + containsString("No index options are allowed on _resolve/cluster when no index expression is specified") + ); + assertThat(exc.getMessage(), containsString(indexOptionTuple.v1())); + } // TODO: The security pathways are not using the new // RemoteClusterService.groupIndices(IndicesOptions indicesOptions, String[] indices, boolean returnLocalAll) method // so this use case still behaves badly - fix in follow on PR // { - // // TEST CASE 12: Resolution against wildcarded remote cluster expression that matches no remotes + // // TEST CASE 13: Resolution against wildcarded remote cluster expression that matches no remotes // final Request remoteOnly1 = new Request("GET", "_resolve/cluster/no_such_remote*:*"); // Response response = performRequestWithRemoteSearchUser(remoteOnly1); // assertOK(response); diff --git a/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS2ResolveClusterIT.java b/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS2ResolveClusterIT.java index 16af2ad0b76fd..fab49c9c2932d 100644 --- a/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS2ResolveClusterIT.java +++ b/x-pack/plugin/security/qa/multi-cluster/src/javaRestTest/java/org/elasticsearch/xpack/remotecluster/RemoteClusterSecurityRCS2ResolveClusterIT.java @@ -13,6 +13,7 @@ import org.elasticsearch.client.ResponseException; import org.elasticsearch.common.UUIDs; import org.elasticsearch.core.Strings; +import org.elasticsearch.core.Tuple; import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.test.cluster.util.resource.Resource; import org.elasticsearch.test.junit.RunnableTestRuleAdapter; @@ -356,9 +357,28 @@ public void testResolveCluster() throws Exception { assertNull(remoteClusterResponse.get("error")); assertNotNull(remoteClusterResponse.get("version")); } + { + // TEST CASE 12: Query resolve/cluster with no index expression, but include index options - should return error + Request getRequest = new Request("GET", "_resolve/cluster"); + Tuple indexOptionTuple = randomFrom( + new Tuple<>("ignore_throttled", "false"), + new Tuple<>("expand_wildcards", "none"), + new Tuple<>("allow_no_indices", "true"), + new Tuple<>("ignore_unavailable", "true") + ); + getRequest.addParameter(indexOptionTuple.v1(), indexOptionTuple.v2()); + + ResponseException exc = expectThrows(ResponseException.class, () -> performRequestWithRemoteSearchUser(getRequest)); + assertThat(exc.getResponse().getStatusLine().getStatusCode(), is(400)); + assertThat( + exc.getMessage(), + containsString("No index options are allowed on _resolve/cluster when no index expression is specified") + ); + assertThat(exc.getMessage(), containsString(indexOptionTuple.v1())); + } // TODO: fix this in a follow-on PR // { - // // TEST CASE 12: Resolution against wildcarded remote cluster expression that matches no remotes + // // TEST CASE 13: Resolution against wildcarded remote cluster expression that matches no remotes // final Request remoteOnly1 = new Request("GET", "_resolve/cluster/no_such_remote*:*"); // Response response = performRequestWithRemoteSearchUser(remoteOnly1); // assertOK(response);