diff --git a/changelog/unreleased/SOLR-18163-remove-v2-disabling-sysprop.yml b/changelog/unreleased/SOLR-18163-remove-v2-disabling-sysprop.yml new file mode 100644 index 00000000000..7ab3bc801bf --- /dev/null +++ b/changelog/unreleased/SOLR-18163-remove-v2-disabling-sysprop.yml @@ -0,0 +1,7 @@ +title: Remove experimental 'solr.api.v2.enabled' sysprop, formerly used to disable the v2 API. +type: removed +authors: + - name: Jason Gerlowski +links: + - name: SOLR-18163 + url: https://issues.apache.org/jira/browse/SOLR-18163 diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 18437df3cca..2ee59aeee07 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -124,7 +124,6 @@ import org.apache.solr.handler.admin.ZookeeperInfoHandler; import org.apache.solr.handler.admin.ZookeeperRead; import org.apache.solr.handler.admin.ZookeeperStatusHandler; -import org.apache.solr.handler.api.V2ApiUtils; import org.apache.solr.handler.component.ShardHandlerFactory; import org.apache.solr.handler.designer.SchemaDesignerAPI; import org.apache.solr.jersey.InjectionFactories; @@ -721,7 +720,7 @@ public ObjectCache getObjectCache() { return objectCache; } - private void registerV2ApiIfEnabled(Object apiObject) { + private void registerV2Api(Object apiObject) { if (apiObject == null || containerHandlers.getApiBag() == null) { return; } @@ -729,7 +728,7 @@ private void registerV2ApiIfEnabled(Object apiObject) { containerHandlers.getApiBag().registerObject(apiObject); } - private void registerV2ApiIfEnabled(Class clazz) { + private void registerV2Api(Class clazz) { if (containerHandlers.getJerseyEndpoints() == null) { return; } @@ -845,12 +844,12 @@ private void loadInternal() { Attributes.builder().put(HANDLER_ATTR, "/authentication/pki").build()); fileStore = new DistribFileStore(this); - registerV2ApiIfEnabled(ClusterFileStore.class); + registerV2Api(ClusterFileStore.class); packageLoader = new SolrPackageLoader(this); - registerV2ApiIfEnabled(packageLoader.getPackageAPI().editAPI); - registerV2ApiIfEnabled(packageLoader.getPackageAPI().readAPI); - registerV2ApiIfEnabled(ZookeeperRead.class); + registerV2Api(packageLoader.getPackageAPI().editAPI); + registerV2Api(packageLoader.getPackageAPI().readAPI); + registerV2Api(ZookeeperRead.class); } MDCLoggingContext.setNode(this); @@ -872,11 +871,11 @@ private void loadInternal() { createHandler( CONFIGSETS_HANDLER_PATH, cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class); ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler, configSetsHandler); - registerV2ApiIfEnabled(clusterAPI); - registerV2ApiIfEnabled(clusterAPI.commands); + registerV2Api(clusterAPI); + registerV2Api(clusterAPI.commands); if (isZooKeeperAware()) { - registerV2ApiIfEnabled(new SchemaDesignerAPI(this)); + registerV2Api(new SchemaDesignerAPI(this)); } // else Schema Designer not available in standalone (non-cloud) mode /* @@ -1027,8 +1026,8 @@ private void loadInternal() { if (isZooKeeperAware()) { containerPluginsRegistry.refresh(); getZkController().zkStateReader.registerClusterPropertiesListener(containerPluginsRegistry); - registerV2ApiIfEnabled(pluginsSource.getReadApi()); - registerV2ApiIfEnabled(pluginsSource.getEditApi()); + registerV2Api(pluginsSource.getReadApi()); + registerV2Api(pluginsSource.getEditApi()); // initialize the placement plugin factory wrapper // with the plugin configuration from the registry @@ -1051,51 +1050,49 @@ private void loadInternal() { }); } - if (V2ApiUtils.isEnabled()) { - final CoreContainer thisCCRef = this; - // Init the Jersey app once all CC endpoints have been registered - containerHandlers - .getJerseyEndpoints() - .register( - new AbstractBinder() { - @Override - protected void configure() { - bindFactory(new InjectionFactories.SingletonFactory<>(thisCCRef)) - .to(CoreContainer.class) - .in(Singleton.class); - } - }) - .register( - new AbstractBinder() { - @Override - protected void configure() { - bindFactory(new InjectionFactories.SingletonFactory<>(nodeKeyPair)) - .to(SolrNodeKeyPair.class) - .in(Singleton.class); - } - }) - .register( - new AbstractBinder() { - @Override - protected void configure() { - bindFactory(new InjectionFactories.SingletonFactory<>(fileStore)) - .to(DistribFileStore.class) - .in(Singleton.class); - } - }) - .register( - new AbstractBinder() { - @Override - protected void configure() { - bindFactory( - new InjectionFactories.SingletonFactory<>( - coreAdminHandler.getCoreAdminAsyncTracker())) - .to(CoreAdminHandler.CoreAdminAsyncTracker.class) - .in(Singleton.class); - } - }); - jerseyAppHandler = new ApplicationHandler(containerHandlers.getJerseyEndpoints()); - } + final CoreContainer thisCCRef = this; + // Init the Jersey app once all CC endpoints have been registered + containerHandlers + .getJerseyEndpoints() + .register( + new AbstractBinder() { + @Override + protected void configure() { + bindFactory(new InjectionFactories.SingletonFactory<>(thisCCRef)) + .to(CoreContainer.class) + .in(Singleton.class); + } + }) + .register( + new AbstractBinder() { + @Override + protected void configure() { + bindFactory(new InjectionFactories.SingletonFactory<>(nodeKeyPair)) + .to(SolrNodeKeyPair.class) + .in(Singleton.class); + } + }) + .register( + new AbstractBinder() { + @Override + protected void configure() { + bindFactory(new InjectionFactories.SingletonFactory<>(fileStore)) + .to(DistribFileStore.class) + .in(Singleton.class); + } + }) + .register( + new AbstractBinder() { + @Override + protected void configure() { + bindFactory( + new InjectionFactories.SingletonFactory<>( + coreAdminHandler.getCoreAdminAsyncTracker())) + .to(CoreAdminHandler.CoreAdminAsyncTracker.class) + .in(Singleton.class); + } + }); + jerseyAppHandler = new ApplicationHandler(containerHandlers.getJerseyEndpoints()); // Do Node setup logic after all handlers have been registered. if (isZooKeeperAware()) { diff --git a/solr/core/src/java/org/apache/solr/core/PluginBag.java b/solr/core/src/java/org/apache/solr/core/PluginBag.java index 024cdb632fa..600b9a0b351 100644 --- a/solr/core/src/java/org/apache/solr/core/PluginBag.java +++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java @@ -42,7 +42,6 @@ import org.apache.solr.common.SolrException; import org.apache.solr.common.util.StrUtils; import org.apache.solr.handler.RequestHandlerBase; -import org.apache.solr.handler.api.V2ApiUtils; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.jersey.APIConfigProvider; import org.apache.solr.jersey.APIConfigProviderBinder; @@ -95,7 +94,7 @@ public JaxrsResourceToHandlerMappings getJaxrsRegistry() { /** Pass needThreadSafety=true if plugins can be added and removed concurrently with lookups. */ public PluginBag(Class klass, SolrCore core, boolean needThreadSafety) { - if (klass == SolrRequestHandler.class && V2ApiUtils.isEnabled()) { + if (klass == SolrRequestHandler.class) { this.loadV2ApisIfPresent = true; this.apiBag = new ApiBag(core != null); this.jaxrsResourceRegistry = new JaxrsResourceToHandlerMappings(); @@ -251,7 +250,7 @@ public PluginHolder put(String name, PluginHolder plugin) { if (registerApi == null) registerApi = apiSupport.registerV2(); if (disableV1 == null) disableV1 = !apiSupport.registerV1(); - if (registerApi && V2ApiUtils.isEnabled()) { + if (registerApi) { Collection apis = apiSupport.getApis(); if (apis != null) { Map nameSubstitutes = singletonMap(HANDLER_NAME, name); diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java index 2176c0a392a..6bdba0ef12b 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -110,7 +110,6 @@ import org.apache.solr.handler.IndexFetcher; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.handler.SolrConfigHandler; -import org.apache.solr.handler.api.V2ApiUtils; import org.apache.solr.handler.component.HighlightComponent; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.logging.MDCLoggingContext; @@ -1146,23 +1145,19 @@ protected SolrCore( updateProcessorChains = loadUpdateProcessorChains(); reqHandlers = new RequestHandlers(this); reqHandlers.initHandlersFromConfig(solrConfig); - if (V2ApiUtils.isEnabled()) { - final String effectiveConfigSetId = configSet.getName() + "-" + solrConfig.effectiveId(); - jerseyAppHandler = - coreContainer - .getJerseyAppHandlerCache() - .computeIfAbsent( - effectiveConfigSetId, - () -> { - log.debug( - "Creating Jersey ApplicationHandler for 'effective solrConfig' [{}]", - effectiveConfigSetId); - return new ApplicationHandler( - reqHandlers.getRequestHandlers().getJerseyEndpoints()); - }); - } else { - jerseyAppHandler = null; - } + final String effectiveConfigSetId = configSet.getName() + "-" + solrConfig.effectiveId(); + jerseyAppHandler = + coreContainer + .getJerseyAppHandlerCache() + .computeIfAbsent( + effectiveConfigSetId, + () -> { + log.debug( + "Creating Jersey ApplicationHandler for 'effective solrConfig' [{}]", + effectiveConfigSetId); + return new ApplicationHandler( + reqHandlers.getRequestHandlers().getJerseyEndpoints()); + }); // cause the executor to stall so firstSearcher events won't fire // until after inform() has been called for all components. diff --git a/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java b/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java index 737a63cef1a..25758ccee03 100644 --- a/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java +++ b/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java @@ -28,7 +28,6 @@ import org.apache.solr.client.api.model.SolrJerseyResponse; import org.apache.solr.common.MapWriter.EntryWriter; import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.EnvUtils; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; @@ -42,10 +41,6 @@ private V2ApiUtils() { /* Private ctor prevents instantiation */ } - public static boolean isEnabled() { - return EnvUtils.getPropertyAsBool("solr.api.v2.enabled", true); - } - public static void flattenMapWithPrefix( Map toFlatten, Map destination, String additionalPrefix) { if (toFlatten == null || toFlatten.isEmpty() || destination == null) { diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrServlet.java b/solr/core/src/java/org/apache/solr/servlet/SolrServlet.java index 3722ea2a26a..a8732ae2f9d 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrServlet.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrServlet.java @@ -32,7 +32,6 @@ import org.apache.solr.common.util.ExecutorUtil; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.NodeRoles; -import org.apache.solr.handler.api.V2ApiUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -156,7 +155,7 @@ default HttpSolrCall createInstance( HttpServletRequest request, HttpServletResponse response, boolean retry) { - if (V2ApiUtils.isEnabled() && (path.startsWith("/____v2/") || path.equals("/____v2"))) { + if (path.startsWith("/____v2/") || path.equals("/____v2")) { return new V2HttpCall(cores, request, response, retry); } else { return new HttpSolrCall(cores, request, response, retry); diff --git a/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java b/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java index 9c00837a434..95750839dff 100644 --- a/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java +++ b/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java @@ -27,19 +27,6 @@ public class V2ApiUtilsTest extends SolrTestCaseJ4 { - @Test - public void testReadsEnableV2ApiSysprop() { - System.clearProperty("solr.api.v2.enabled"); - assertTrue("v2 API should be enabled if sysprop not specified", V2ApiUtils.isEnabled()); - - System.setProperty("solr.api.v2.enabled", "true"); - assertTrue("v2 API should be enabled if sysprop explicitly enables it", V2ApiUtils.isEnabled()); - - System.setProperty("solr.api.v2.enabled", "false"); - assertFalse( - "v2 API should be disabled if sysprop explicitly disables it", V2ApiUtils.isEnabled()); - } - @Test public void testConvertsWtToMediaTypeString() { assertEquals("someDefault", V2ApiUtils.getMediaTypeFromWtParam(SolrParams.of(), "someDefault")); diff --git a/solr/packaging/test/test_start_solr.bats b/solr/packaging/test/test_start_solr.bats index 6d978bd146d..ef25ea32ee7 100644 --- a/solr/packaging/test/test_start_solr.bats +++ b/solr/packaging/test/test_start_solr.bats @@ -84,8 +84,8 @@ teardown() { } @test "deprecated system properties converted to modern properties" { - solr start -Ddisable.v2.api=true - assert_file_contains "${SOLR_LOGS_DIR}/solr.log" 'You are passing in deprecated system property disable.v2.api and should upgrade to using solr.api.v2.enabled instead.' + solr start -Ddisable.config.edit=true + assert_file_contains "${SOLR_LOGS_DIR}/solr.log" 'You are passing in deprecated system property disable.config.edit and should upgrade to using solr.api.config.edit.enabled instead.' } @test "start with custom jetty options" { diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc index 7cb304cd2f7..837c7282b5e 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc @@ -32,8 +32,6 @@ NOTE: Properties marked with "!" indicate inverted meaning between pre Solr 10 a |solr.api.config.edit.enabled|!disable.config.edit|true|Controls whether configuration editing via API is enabled. When set to `true`, configuration editing is enabled. -|solr.api.v2.enabled|!disable.v2.api|true|Controls whether the V2 API is enabled. When set to `true`, the V2 API is enabled. - |solr.auth.jwt.outbound.http.enabled|solr.auth.jwt.allowOutboundHttp|false|Controls whether JWT authentication for outbound HTTP connections is enabled. |solr.auth.superuser|solr.authorization.superuser|solr|Specifies the superuser for authorization. This user has all permissions when using SASL authentication. @@ -159,13 +157,13 @@ Many Solr properties follow a standard naming convention. Newer properties typic System properties can be set in several ways: -1. JVM command line arguments using `-D`: `-Dsolr.api.v2.enabled=true` +1. JVM command line arguments using `-D`: `-Dsolr.api.config.edit.enabled=true` 2. In `solr.in.sh` (Unix) or `solr.in.cmd` (Windows) using environment variables 3. Through environment variables (with appropriate naming conventions) Environment variables can also be used to set these properties. You may find this useful in environments such as Docker. -Environment variables should be uppercase with dot notations equivalents, e.g. `SOLR_API_V2_ENABLED` for the property `solr.api.v2.enabled`. +Environment variables should be uppercase with dot notations equivalents, e.g. `SOLR_API_CONFIG_EDIT_ENABLED` for the property `solr.api.config.edit.enabled`. == See Also diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc index a9e1e8cff3c..844297cdce0 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc @@ -20,7 +20,6 @@ The v2 API is a modernized self-documenting API interface covering most current Solr APIs. It is anticipated that once the v2 API reaches full coverage, and Solr-internal API usages like SolrJ and the Admin UI have been converted from the old API to the v2 API, the old API will eventually be retired. Today, the two API styles coexist, and all the old APIs will continue to work without any change. -You can disable all v2 API endpoints if desired by starting your servers with this system property: `-Dsolr.api.v2.enabled=false`. NOTE: The v2 API is classified as "experimental". It may change in backwards-incompatible ways as it evolves to cover additional functionality. diff --git a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc index 269bf1df6f6..e7b55492e3b 100644 --- a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc +++ b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc @@ -34,6 +34,15 @@ This compatibility safeguard can be disabled via the environment variable `SOLR_ Solr 10.0 requires at least Java 21, while SolrJ 10.0 requires at least Java 17. +== Solr 10.1 + +=== v2 API +Starting in Solr 10.1 it is no longer possible for users to disable the v2 API by use of the `solr.api.v2.enabled` system property, and the Solr server and tooling (`bin/solr`, Admin UI, etc.) will start using these APIs internally. + +Former users of `solr.api.v2.enabled` looking to upgrade to Solr 10.1 or newer should take care to review any custom `RuleBasedAuthorizationPlugin` permissions and ensure that v2 API paths are adequately secured. + +Users who deploy a proxy in front of Solr should also review this setup to ensure that it allows access to the v2 API root path, `/api`. + == Solr 10.0 === Solr Jetty parameters diff --git a/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties b/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties index f8d84642505..662ea883e5a 100644 --- a/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties +++ b/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties @@ -10,7 +10,6 @@ solr.admin.handler.systeminfo.dns.reverse.lookup.enabled=!solr.dns.prevent.reverse.lookup solr.api.config.edit.enabled=!disable.config.edit -solr.api.v2.enabled=!disable.v2.api solr.auth.jwt.outbound.http.enabled=solr.auth.jwt.allow.outbound.http solr.auth.superuser=solr.authorization.superuser