diff --git a/changelog/unreleased/SOLR-18014-filestore-getFrom-improvements.yml b/changelog/unreleased/SOLR-18014-filestore-getFrom-improvements.yml new file mode 100644 index 00000000000..da93aa07b59 --- /dev/null +++ b/changelog/unreleased/SOLR-18014-filestore-getFrom-improvements.yml @@ -0,0 +1,9 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: Ensure File Store API "getFrom" param rejects values not in liveNodes +type: security # added, changed, fixed, deprecated, removed, dependency_update, security, other +authors: + - name: Jason Gerlowski + - name: monkeontheroof +links: + - name: SOLR-18014 + url: https://issues.apache.org/jira/browse/SOLR-18014 diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ClusterFileStoreApis.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ClusterFileStoreApis.java index 2445b17e7aa..e8dafdd4498 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ClusterFileStoreApis.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ClusterFileStoreApis.java @@ -107,7 +107,9 @@ SolrJerseyResponse fetchFile( @Parameter(description = "Path to a file or directory within the filestore") @PathParam("path") String path, - @Parameter(description = "An optional Solr node name to fetch the file from") + @Parameter( + description = + "An optional Solr node name to fetch the file from, typically in the form \"host:port_solr\".") @QueryParam("getFrom") String getFrom); diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java b/solr/core/src/java/org/apache/solr/cloud/ZkController.java index f8551e6fb3c..a1069f4055a 100644 --- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java +++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java @@ -1301,6 +1301,9 @@ public void removeEphemeralLiveNode() throws KeeperException, InterruptedExcepti }); } + /** + * @return the "live node" name of this Solr process, in the form "${host}:${port}_solr" + */ public String getNodeName() { return nodeName; } diff --git a/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java b/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java index 043192aa0d8..ac00a094a27 100644 --- a/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java +++ b/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java @@ -18,6 +18,7 @@ package org.apache.solr.filestore; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST; import static org.apache.solr.handler.admin.api.ReplicationAPIBase.FILE_STREAM; import static org.apache.solr.response.RawResponseWriter.CONTENT; @@ -320,6 +321,19 @@ public SolrJerseyResponse fetchFile(String path, String getFrom) { if (path == null) { path = ""; } + + // Ensure 'getFrom' points to a node in this cluster + final var zkStateReader = coreContainer.getZkController().getZkStateReader(); + if (StrUtils.isNotBlank(getFrom) + && !getFrom.equals("*") + && !zkStateReader.isNodeLive(getFrom)) { + throw new SolrException( + BAD_REQUEST, + "File store cannot fetch from source node [" + + getFrom + + "] as it does not appear in live-nodes"); + } + pullFileFromNode(coreContainer, fileStore, path, getFrom); return response; } diff --git a/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java b/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java index a4de2935534..26679369d6e 100644 --- a/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java +++ b/solr/core/src/test/org/apache/solr/filestore/TestDistribFileStore.java @@ -175,6 +175,19 @@ public void testFileStoreManagement() throws Exception { String url = baseUrl + "/cluster/filestore/metadata/package/mypkg/v1.0?wt=javabin"; assertResponseValues(10, new Fetcher(url, jettySolrRunner), expected); } + + // Ensure that invalid 'getFrom' parameter causes failures + for (JettySolrRunner jettySolrRunner : cluster.getJettySolrRunners()) { + final var fetchReq = new FileStoreApi.FetchFile("/package/mypkg/v1.0/runtimelibs.jar2"); + fetchReq.setGetFrom("someFakeSolrNode:8983_solr"); + try (final var solrClient = jettySolrRunner.newClient()) { + final var asdf = fetchReq.process(solrClient); + assertEquals(400, asdf.responseHeader.status); + assertThat(asdf.error.msg, containsString("File store cannot fetch from source node")); + assertThat(asdf.error.msg, containsString("does not appear in live-nodes")); + } + } + // Delete Jars DistribFileStore.deleteZKFileEntry( cluster.getZkClient(), "/package/mypkg/v1.0/runtimelibs.jar");