diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index fbe9865e5d0..e71c21e322e 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -37,6 +37,8 @@ Bug Fixes * SOLR-16452: Do not update PRS states if local version is newer (Hitesh Khamesra via noble) +* SOLR-16777: Schema Designer now correctly manages trust of the ConfigSets it is managing. (Ishan Chattopadhyaya, Skay, Houston Putman) + Optimizations --------------------- * SOLR-16555: SolrIndexSearcher - FilterCache intersections/andNot should not clone bitsets repeatedly (Kevin Risden, David Smiley) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java index cb6d2a3de85..c84243c0245 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java @@ -16,6 +16,7 @@ */ package org.apache.solr.handler.admin; +import java.io.IOException; import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.nio.charset.StandardCharsets; @@ -311,7 +312,7 @@ private void ensureOverwritingUntrustedConfigSet(SolrZkClient zkClient, String c } } - private static boolean isCurrentlyTrusted(SolrZkClient zkClient, String configSetZkPath) { + public static boolean isCurrentlyTrusted(SolrZkClient zkClient, String configSetZkPath) { byte[] configSetNodeContent; try { configSetNodeContent = zkClient.getData(configSetZkPath, null, null, true); @@ -329,7 +330,33 @@ private static boolean isCurrentlyTrusted(SolrZkClient zkClient, String configSe return (boolean) contentMap.getOrDefault("trusted", true); } - static boolean isTrusted(SolrQueryRequest req, AuthenticationPlugin authPlugin) { + public void setConfigMetadata(String configName, Map data) throws IOException { + try { + coreContainer.getZkController().getZkClient().makePath( + ZkConfigManager.CONFIGS_ZKNODE + "/" + configName, + Utils.toJSON(data), + CreateMode.PERSISTENT, + null, + false, + true); + } catch (KeeperException | InterruptedException e) { + throw new IOException("Error setting config metadata", SolrZkClient.checkInterrupted(e)); + } + } + + public void removeConfigSetTrust(String configSetName) { + try { + Map metadata = Collections.singletonMap("trusted", false); + setConfigMetadata(configSetName, metadata); + } catch (IOException e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Could not remove trusted flag for configSet " + configSetName + ": " + e.getMessage(), + e); + } + } + + public static boolean isTrusted(SolrQueryRequest req, AuthenticationPlugin authPlugin) { if (authPlugin != null && req.getUserPrincipal() != null) { log.debug("Trusted configset request"); return true; diff --git a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerAPI.java b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerAPI.java index 12b4ed93366..87088f344de 100644 --- a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerAPI.java @@ -65,6 +65,7 @@ import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrConfig; import org.apache.solr.core.SolrResourceLoader; +import org.apache.solr.handler.admin.ConfigSetsHandler; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.RawResponseWriter; import org.apache.solr.response.SolrQueryResponse; @@ -112,8 +113,8 @@ public SchemaDesignerAPI(CoreContainer coreContainer) { this.coreContainer = coreContainer; this.schemaSuggester = schemaSuggester; this.sampleDocLoader = sampleDocLoader; - this.settingsDAO = new SchemaDesignerSettingsDAO(coreContainer); this.configSetHelper = new SchemaDesignerConfigSetHelper(this.coreContainer, this.schemaSuggester); + this.settingsDAO = new SchemaDesignerSettingsDAO(coreContainer, configSetHelper); } public static SchemaSuggester newSchemaSuggester(CoreContainer coreContainer) { @@ -233,11 +234,12 @@ public void updateFileContents(SolrQueryRequest req, SolrQueryResponse rsp) thro byte[] data = DefaultSampleDocumentsLoader.streamAsBytes(extractSingleContentStream(req, true).getStream()); Exception updateFileError = null; + boolean requestIsTrusted = ConfigSetsHandler.isTrusted(req, coreContainer.getAuthenticationPlugin()); if (SOLR_CONFIG_XML.equals(file)) { // verify the updated solrconfig.xml is valid before saving to ZK (to avoid things blowing up later) try { InMemoryResourceLoader loader = new InMemoryResourceLoader(coreContainer, mutableId, SOLR_CONFIG_XML, data); - SolrConfig.readFromResourceLoader(loader, SOLR_CONFIG_XML, true, null); + SolrConfig.readFromResourceLoader(loader, SOLR_CONFIG_XML, requestIsTrusted, null); } catch (Exception exc) { updateFileError = exc; } @@ -260,6 +262,11 @@ public void updateFileContents(SolrQueryRequest req, SolrQueryResponse rsp) thro } catch (KeeperException | InterruptedException e) { throw new IOException("Failed to save data in ZK at path: " + zkPath, SolrZkClient.checkInterrupted(e)); } + // If the request is untrusted, and the configSet is trusted, remove the trusted flag on the + // configSet. + if (ConfigSetsHandler.isCurrentlyTrusted(zkClient, ZkConfigManager.CONFIGS_ZKNODE + "/" + mutableId) && !requestIsTrusted) { + coreContainer.getConfigSetsHandler().removeConfigSetTrust(mutableId); + } configSetHelper.reloadTempCollection(mutableId, false); diff --git a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerConfigSetHelper.java b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerConfigSetHelper.java index a960288ca0f..8b944d22467 100644 --- a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerConfigSetHelper.java +++ b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerConfigSetHelper.java @@ -610,10 +610,9 @@ ManagedIndexSchema deleteNestedDocsFieldsIfNeeded(ManagedIndexSchema schema, boo } SolrConfig loadSolrConfig(String configSet) { - SolrResourceLoader resourceLoader = cc.getResourceLoader(); - ZkSolrResourceLoader zkLoader = - new ZkSolrResourceLoader(resourceLoader.getInstancePath(), configSet, resourceLoader.getClassLoader(), new Properties(), cc.getZkController()); - return SolrConfig.readFromResourceLoader(zkLoader, SOLR_CONFIG_XML, false, null); + ZkSolrResourceLoader zkLoader = zkLoaderForConfigSet(configSet); + boolean trusted = isConfigSetTrusted(configSet); + return SolrConfig.readFromResourceLoader(zkLoader, SOLR_CONFIG_XML, trusted, null); } ManagedIndexSchema loadLatestSchema(String configSet) { @@ -1075,4 +1074,34 @@ void deleteConfig(String configSet) throws IOException { void copyConfig(String from, String to) throws IOException { configManager.copyConfigDir(from, to); } + + public boolean isConfigSetTrusted(String configSetName) { + try { + return cc.getConfigSetsHandler().isCurrentlyTrusted(cc.getZkController().getZkClient(), ZkConfigManager.CONFIGS_ZKNODE + "/" + configSetName); + } catch (Exception e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Could not load conf " + configSetName + ": " + e.getMessage(), + e); + } + } + + public void removeConfigSetTrust(String configSetName) { + try { + Map metadata = Collections.singletonMap("trusted", false); + cc.getConfigSetsHandler().setConfigMetadata(configSetName, metadata); + } catch (IOException e) { + throw new SolrException( + SolrException.ErrorCode.SERVER_ERROR, + "Could not remove trusted flag for configSet " + configSetName + ": " + e.getMessage(), + e); + } + } + + protected ZkSolrResourceLoader zkLoaderForConfigSet(final String configSet) { + SolrResourceLoader resourceLoader = cc.getResourceLoader(); + ZkSolrResourceLoader zkLoader = + new ZkSolrResourceLoader(resourceLoader.getInstancePath(), configSet, resourceLoader.getClassLoader(), new Properties(), cc.getZkController()); + return zkLoader; + } } diff --git a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java index 90373e2eb52..a0cd45975d2 100644 --- a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java +++ b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java @@ -24,7 +24,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import org.apache.solr.cloud.ZkController; import org.apache.solr.cloud.ZkSolrResourceLoader; @@ -33,7 +32,6 @@ import org.apache.solr.core.CoreContainer; import org.apache.solr.core.PluginInfo; import org.apache.solr.core.SolrConfig; -import org.apache.solr.core.SolrResourceLoader; import org.apache.solr.update.processor.UpdateRequestProcessorChain; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.data.Stat; @@ -49,14 +47,15 @@ class SchemaDesignerSettingsDAO implements SchemaDesignerConstants { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final CoreContainer cc; + private final SchemaDesignerConfigSetHelper configSetHelper; - SchemaDesignerSettingsDAO(CoreContainer cc) { + SchemaDesignerSettingsDAO(CoreContainer cc, SchemaDesignerConfigSetHelper configSetHelper) { this.cc = cc; + this.configSetHelper = configSetHelper; } SchemaDesignerSettings getSettings(String configSet) { - SolrConfig solrConfig = - SolrConfig.readFromResourceLoader(zkLoaderForConfigSet(configSet), SOLR_CONFIG_XML, true, null); + SolrConfig solrConfig = configSetHelper.loadSolrConfig(configSet); return getSettings(solrConfig); } @@ -97,8 +96,14 @@ boolean persistIfChanged(String configSet, SchemaDesignerSettings settings) thro } if (changed) { - ZkController.persistConfigResourceToZooKeeper(zkLoaderForConfigSet(configSet), overlay.getZnodeVersion(), - ConfigOverlay.RESOURCE_NAME, overlay.toByteArray(), true); + try (ZkSolrResourceLoader resourceLoader = configSetHelper.zkLoaderForConfigSet(configSet)) { + ZkController.persistConfigResourceToZooKeeper( + resourceLoader, + overlay.getZnodeVersion(), + ConfigOverlay.RESOURCE_NAME, + overlay.toByteArray(), + true); + } } return changed; @@ -160,9 +165,4 @@ private boolean hasFieldGuessingURPChain(final SolrConfig solrConfig) { } return hasPlugin; } - - private ZkSolrResourceLoader zkLoaderForConfigSet(final String configSet) { - SolrResourceLoader loader = cc.getResourceLoader(); - return new ZkSolrResourceLoader(loader.getInstancePath(), configSet, loader.getClassLoader(), new Properties(), cc.getZkController()); - } } diff --git a/solr/core/src/test/org/apache/solr/handler/designer/TestSchemaDesignerSettingsDAO.java b/solr/core/src/test/org/apache/solr/handler/designer/TestSchemaDesignerSettingsDAO.java index c4b0e148aa3..21fe98fcd4b 100644 --- a/solr/core/src/test/org/apache/solr/handler/designer/TestSchemaDesignerSettingsDAO.java +++ b/solr/core/src/test/org/apache/solr/handler/designer/TestSchemaDesignerSettingsDAO.java @@ -69,7 +69,8 @@ public void testDAO() throws Exception { CollectionAdminRequest.createCollection(collection, configSet, 1, 1).process(cluster.getSolrClient()); CollectionsHandler.waitForActiveCollection(collection, cc, rsp); - SchemaDesignerSettingsDAO dao = new SchemaDesignerSettingsDAO(cc); + SchemaDesignerConfigSetHelper csh = new SchemaDesignerConfigSetHelper(cc, null); + SchemaDesignerSettingsDAO dao = new SchemaDesignerSettingsDAO(cc, csh); SchemaDesignerSettings settings = dao.getSettings(configSet); assertNotNull(settings);