diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java index 224723904b5..aaa5b9b6d32 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/ShowFileRequestHandler.java @@ -36,6 +36,8 @@ import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.RawResponseWriter; import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.schema.IndexSchema; +import org.apache.solr.schema.ManagedIndexSchema; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -170,13 +172,11 @@ public class ShowFileRequestHandler extends RequestHandlerBase if (fname == null) { rsp.setException(new SolrException(ErrorCode.BAD_REQUEST, "No file name specified for write operation.")); } else { - if (coreContainer.isZooKeeperAware()) { - if (isHiddenFile(rsp, fname) == false) { + fname = fname.replace('\\', '/'); + if (isHiddenFile(req, rsp, fname, true) == false) { + if (coreContainer.isZooKeeperAware()) { writeToZooKeeper(req, rsp, coreContainer); - } - } else { - fname = fname.replace('\\', '/'); // normalize slashes. Should be done above too? - if (isHiddenFile(rsp, fname) == false) { + } else { writeToFileSystem(req, rsp); } } @@ -186,21 +186,38 @@ public class ShowFileRequestHandler extends RequestHandlerBase // See if we should deal with this file - private boolean isHiddenFile(SolrQueryResponse rsp, String fnameIn) { + private boolean isHiddenFile(SolrQueryRequest req, SolrQueryResponse rsp, String fnameIn, boolean reportError) { String fname = fnameIn.toUpperCase(Locale.ROOT); if (hiddenFiles.contains(fname) || hiddenFiles.contains("*")) { - log.error("Cannot access " + fname); - rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Can not access: " + fnameIn)); + if (reportError) { + log.error("Cannot access " + fname); + rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Can not access: " + fnameIn)); + } return true; } // This is slightly off, a valid path is something like ./schema.xml. I don't think it's worth the effort though // to fix it to handle all possibilities though. if (fname.indexOf("..") >= 0 || fname.startsWith(".")) { - log.error("Invalid path: " + fname); - rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Invalid path: " + fnameIn)); + if (reportError) { + log.error("Invalid path: " + fname); + rsp.setException(new SolrException(ErrorCode.FORBIDDEN, "Invalid path: " + fnameIn)); + } return true; } + + // Make sure that if the schema is managed, we don't allow editing. Don't really want to put + // this in the init since we're not entirely sure when the managed schema will get initialized relative to this + // handler. + SolrCore core = req.getCore(); + IndexSchema schema = core.getLatestSchema(); + if (schema instanceof ManagedIndexSchema) { + String managed = schema.getResourceName(); + + if (fname.equalsIgnoreCase(managed)) { + return true; + } + } return false; } @@ -223,7 +240,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase adminFile = confPath; } else { fname = fname.replace('\\', '/'); // normalize slashes - if (isHiddenFile(rsp, fname)) { + if (isHiddenFile(req, rsp, fname, true)) { return null; } if (fname.startsWith("/")) { // Only files relative to conf are valid @@ -291,7 +308,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase NamedList> files = new SimpleOrderedMap>(); for (String f : children) { - if (isHiddenFile(rsp, f)) { + if (isHiddenFile(req, rsp, f, false)) { continue; } @@ -452,13 +469,11 @@ public class ShowFileRequestHandler extends RequestHandlerBase for( File f : adminFile.listFiles() ) { String path = f.getAbsolutePath().substring( basePath ); path = path.replace( '\\', '/' ); // normalize slashes - if( hiddenFiles.contains( path.toUpperCase(Locale.ROOT) ) ) { - continue; // don't show 'hidden' files + + if (isHiddenFile(req, rsp, f.getName().replace('\\', '/'), false)) { + continue; } - if( f.isHidden() || f.getName().startsWith( "." ) ) { - continue; // skip hidden system files... - } - + SimpleOrderedMap fileInfo = new SimpleOrderedMap(); files.add( path, fileInfo ); if( f.isDirectory() ) { @@ -480,7 +495,7 @@ public class ShowFileRequestHandler extends RequestHandlerBase req.setParams(params); ContentStreamBase content = new ContentStreamBase.FileStream( adminFile ); - content.setContentType( req.getParams().get( USE_CONTENT_TYPE ) ); + content.setContentType(req.getParams().get(USE_CONTENT_TYPE)); rsp.add(RawResponseWriter.CONTENT, content); } diff --git a/solr/core/src/test/org/apache/solr/schema/TestCloudManagedSchema.java b/solr/core/src/test/org/apache/solr/schema/TestCloudManagedSchema.java index f1cc4904d36..6deaa45b526 100644 --- a/solr/core/src/test/org/apache/solr/schema/TestCloudManagedSchema.java +++ b/solr/core/src/test/org/apache/solr/schema/TestCloudManagedSchema.java @@ -16,23 +16,20 @@ package org.apache.solr.schema; * limitations under the License. */ -import org.apache.commons.io.IOUtils; -import org.apache.solr.client.solrj.ResponseParser; -import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.cloud.AbstractFullDistribZkTestBase; import org.apache.solr.common.SolrException; +import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.NamedList; +import org.apache.zookeeper.KeeperException; import org.junit.BeforeClass; import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.util.regex.Pattern; +import java.util.List; public class TestCloudManagedSchema extends AbstractFullDistribZkTestBase { @@ -69,72 +66,40 @@ public class TestCloudManagedSchema extends AbstractFullDistribZkTestBase { String collectionSchema = (String)collectionStatus.get(CoreAdminParams.SCHEMA); // Make sure the upgrade to managed schema happened assertEquals("Schema resource name differs from expected name", "managed-schema", collectionSchema); - - // Make sure "DO NOT EDIT" is in the content of the managed schema - String fileContent = getFileContentFromZooKeeper("managed-schema"); - assertTrue("Managed schema is missing", fileContent.contains("DO NOT EDIT")); - - // Make sure the original non-managed schema is no longer in ZooKeeper - assertFileNotInZooKeeper("schema.xml"); - // Make sure the renamed non-managed schema is present in ZooKeeper - fileContent = getFileContentFromZooKeeper("schema.xml.bak"); - assertTrue("schema file doesn't contain ' processResponse(InputStream body, String encoding) { - try { - rawFileContent = IOUtils.toString(body, encoding); - } catch (Exception e) { - throw new RuntimeException(e); - } - return null; - } - @Override - public NamedList processResponse(Reader reader) { - throw new UnsupportedOperationException("TODO unimplemented");//TODO - } - } - - protected final void assertFileNotInZooKeeper(String fileName) throws Exception { - // Stolen from AbstractBadConfigTestBase - String errString = "Not Found"; - ignoreException(Pattern.quote(errString)); - String rawContent = null; + SolrZkClient zkClient = new SolrZkClient(zkServer.getZkHost(), 30000); try { - rawContent = getFileContentFromZooKeeper(fileName); - } catch (Exception e) { - // short circuit out if we found what we expected - if (-1 != e.getMessage().indexOf(errString)) return; - // otherwise, rethrow it, possibly completely unrelated - throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, - "Unexpected error, expected error matching: " + errString, e); + // Make sure "DO NOT EDIT" is in the content of the managed schema + String fileContent = getFileContentFromZooKeeper(zkClient, "/solr/configs/conf1/managed-schema"); + assertTrue("Managed schema is missing", fileContent.contains("DO NOT EDIT")); + + // Make sure the original non-managed schema is no longer in ZooKeeper + assertFileNotInZooKeeper(zkClient, "/solr/configs/conf1", "schema.xml"); + + // Make sure the renamed non-managed schema is present in ZooKeeper + fileContent = getFileContentFromZooKeeper(zkClient, "/solr/configs/conf1/schema.xml.bak"); + assertTrue("schema file doesn't contain ' kids = zkClient.getChildren(parent, null, true); + for (String kid : kids) { + if (kid.equalsIgnoreCase(fileName)) { + String rawContent = new String(zkClient.getData(fileName, null, null, true), "UTF-8"); + fail("File '" + fileName + "' was unexpectedly found in ZooKeeper. Content starts with '" + + rawContent.substring(0, 100) + " [...]'"); + } } - fail("File '" + fileName + "' was unexpectedly found in ZooKeeper. Content starts with '" - + rawContent.substring(0, 100) + " [...]'"); } }