Skip to content

Commit 979136b

Browse files
fix(security): upgrade Jetty 11.0.26 -> 12.0.35 to fix CVE-2026-2332 (#2894)
1 parent 628543b commit 979136b

13 files changed

Lines changed: 471 additions & 82 deletions

File tree

tika-grpc/src/test/java/org/apache/tika/pipes/grpc/PipesBiDirectionalStreamingIntegrationTest.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import org.awaitility.Awaitility;
4444
import org.eclipse.jetty.server.Server;
4545
import org.eclipse.jetty.server.handler.ResourceHandler;
46-
import org.eclipse.jetty.util.resource.PathResource;
4746
import org.junit.jupiter.api.AfterAll;
4847
import org.junit.jupiter.api.Assertions;
4948
import org.junit.jupiter.api.BeforeAll;
@@ -92,9 +91,7 @@ static void setUpHttpServer() throws Exception {
9291

9392
ResourceHandler resourceHandler = new ResourceHandler();
9493
resourceHandler.setDirAllowed(true);
95-
// TODO when using jetty 12:
96-
// resourceHandler.setBaseResourceAsString("src/test/resources/test-files")
97-
resourceHandler.setBaseResource(new PathResource(Paths.get("src", "test", "resources", "test-files")));
94+
resourceHandler.setBaseResourceAsString("src/test/resources/test-files");
9895
httpServer.setHandler(resourceHandler);
9996
httpServer.start();
10097

tika-integration-tests/tika-pipes-solr-integration-tests/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@
7676
<version>${solrj.version}</version>
7777
<scope>test</scope>
7878
</dependency>
79+
<dependency>
80+
<groupId>org.apache.solr</groupId>
81+
<artifactId>solr-solrj-jetty</artifactId>
82+
<version>${solrj.version}</version>
83+
<scope>test</scope>
84+
</dependency>
85+
<dependency>
86+
<groupId>org.apache.solr</groupId>
87+
<artifactId>solr-solrj-zookeeper</artifactId>
88+
<version>${solrj.version}</version>
89+
<scope>test</scope>
90+
</dependency>
7991

8092

8193
</dependencies>

tika-integration-tests/tika-pipes-solr-integration-tests/src/test/java/org/apache/tika/pipes/solr/tests/TikaPipesSolrTestBase.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
import org.apache.http.impl.client.CloseableHttpClient;
3737
import org.apache.http.impl.client.HttpClients;
3838
import org.apache.solr.client.solrj.SolrClient;
39-
import org.apache.solr.client.solrj.SolrQuery;
40-
import org.apache.solr.client.solrj.impl.Http2SolrClient;
39+
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
40+
import org.apache.solr.client.solrj.request.SolrQuery;
4141
import org.apache.solr.common.SolrInputDocument;
4242
import org.jetbrains.annotations.NotNull;
4343
import org.junit.jupiter.api.AfterEach;
@@ -190,7 +190,7 @@ protected void setupSolr(Path pipesDirectory) throws Exception {
190190
}
191191
LOG.info("Created Solr collection '{}': {}", collection, createResult.getStdout().trim());
192192

193-
try (SolrClient solrClient = new Http2SolrClient.Builder(solrEndpoint).build()) {
193+
try (SolrClient solrClient = new HttpJettySolrClient.Builder(solrEndpoint).build()) {
194194

195195
addBasicSchemaFields(solrEndpoint + "/" + collection);
196196
addSchemaFieldsForNestedDocs(solrEndpoint + "/" + collection);
@@ -262,7 +262,7 @@ protected void runTikaAsyncSolrPipeIteratorFileFetcherSolrEmitter(Path pipesDire
262262

263263
TikaCLI.main(new String[]{"-a", "-c", tikaConfigFile.toAbsolutePath().toString()});
264264

265-
try (SolrClient solrClient = new Http2SolrClient.Builder(solrEndpoint).build()) {
265+
try (SolrClient solrClient = new HttpJettySolrClient.Builder(solrEndpoint).build()) {
266266
solrClient.commit(collection, true, true);
267267
assertEquals(numDocs, solrClient.query(collection,
268268
new SolrQuery("mime_s:text/html*")).getResults()
@@ -296,7 +296,7 @@ protected void runTikaAsyncSolrPipeIteratorFileFetcherSolrEmitter(Path pipesDire
296296

297297
TikaCLI.main(new String[]{"-a", "-c", tikaConfigFile.toAbsolutePath().toString()});
298298

299-
try (SolrClient solrClient = new Http2SolrClient.Builder(solrEndpoint).build()) {
299+
try (SolrClient solrClient = new HttpJettySolrClient.Builder(solrEndpoint).build()) {
300300
solrClient.commit(collection, true, true);
301301
assertEquals(numDocs, solrClient.query(collection,
302302
new SolrQuery("mime_s:text/html*")).getResults()

tika-parent/pom.xml

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@
342342
<commons.math3.version>3.6.1</commons.math3.version>
343343
<commons.net.version>3.12.0</commons.net.version>
344344
<ctakes.version>6.0.0</ctakes.version>
345-
<!-- can't use 4.1.0, fails in tika server core because it uses jetty 12, which we can't
346-
use due to the problems explained there -->
347-
<cxf.version>4.0.11</cxf.version>
345+
<!-- Upgraded to 4.1.7 (from 4.0.11) as part of the Jetty 12 migration (CVE-2026-2332).
346+
CXF 4.1.x ships cxf-rt-transports-http-jetty built against Jetty 12. -->
347+
<cxf.version>4.1.7</cxf.version>
348348
<ddplist.version>1.29</ddplist.version>
349349
<dl4j.version>1.0.0-M2.1</dl4j.version>
350350
<fakeload.version>0.7.0</fakeload.version>
@@ -372,6 +372,7 @@
372372
<jai.imageio.core.version>1.4.0</jai.imageio.core.version>
373373
<jakarta.activation.version>2.1.4</jakarta.activation.version>
374374
<jakarta.annotation.version>3.0.0</jakarta.annotation.version>
375+
<jakarta.servlet.version>6.0.0</jakarta.servlet.version>
375376
<jakarta.ws.rs.version>4.0.0</jakarta.ws.rs.version>
376377
<jakarta.xml.bind.version>4.0.5</jakarta.xml.bind.version>
377378
<jakarta.xml.soap.version>3.0.2</jakarta.xml.soap.version>
@@ -382,18 +383,14 @@
382383
<jcommander.version>1.82</jcommander.version>
383384
<jdom2.version>2.0.6.1</jdom2.version>
384385
<jempbox.version>1.8.17</jempbox.version>
385-
<!-- can't update to jetty 12 because of problem in solr integration tests
386-
due to Http2SolrClient (solrj 9.10.0)
387-
(only on the CI, not on local Windows with Docker, see comment in TIKA-4327 on 14.12.2024)
388-
expecting org.eclipse.jetty.client.util.InputStreamResponseListener which is only available
389-
in Jetty up to 11.0.26
390-
but this class is now in org.eclipse.jetty.client, see also
386+
<!-- Upgraded from 11.0.26 to 12.0.35 to fix CVE-2026-2332 (HTTP/1.1 request smuggling,
387+
CVSS 9.1 Critical). Jetty 11.x is EOL and 11.0.28 was never released; the fix
388+
is only available in the Jetty 12 line (>=12.0.33). Jetty 12.0.x requires Java 17,
389+
the same minimum as this project. Migration guide:
391390
https://jetty.org/docs/jetty/12/programming-guide/migration/11-to-12.html
392-
when updating, see also TODO in PipesBiDirectionalStreamingIntegrationTest
393-
and add jakarta.servlet jakarta.servlet-api 6.0.0 to tika-server-core
394391
-->
395-
<jetty.version>11.0.26</jetty.version>
396-
<jetty.http2.version>11.0.26</jetty.http2.version>
392+
<jetty.version>12.0.35</jetty.version>
393+
<jetty.http2.version>12.0.35</jetty.http2.version>
397394
<jhighlight.version>2.0.0</jhighlight.version>
398395
<jna.version>5.19.1</jna.version>
399396
<json.simple.version>1.1.1</json.simple.version>
@@ -441,13 +438,14 @@
441438
<slf4j.version>2.0.18</slf4j.version>
442439
<sis.version>1.6</sis.version>
443440
<snappy.version>1.1.10.8</snappy.version>
444-
<!-- TODO (incomplete) if updating to solrj 10:
445-
https://solr.apache.org/guide/solr/latest/upgrade-notes/major-changes-in-solr-10.html
446-
add solr-solrj-jetty artifact, add log4j
447-
Http2SolrClient -> HttpJettySolrClient
448-
LBHttpSolrClient -> LBHttp2SolrClient -> LBJettySolrClient (doesn't work)
449-
-->
450-
<solrj.version>9.10.1</solrj.version>
441+
<!-- Upgraded to 10.0.0 (from 9.10.1): SolrJ 9.x bundles Jetty 11 HTTP client APIs
442+
internally (Http2SolrClient / solr-solrj-jetty), which conflict with Jetty 12.
443+
SolrJ 10 renames Http2SolrClient -> HttpJettySolrClient (in solr-solrj-jetty)
444+
and LBHttpSolrClient -> LBJettySolrClient; the solr-solrj-jetty artifact must
445+
be added alongside solr-solrj wherever those classes are used.
446+
NOTE: proxy and basic auth are wired via HttpJettySolrClient.Builder;
447+
only basic auth is supported (non-basic schemes are rejected at startup). -->
448+
<solrj.version>10.0.0</solrj.version>
451449
<spring.version>7.0.8</spring.version>
452450
<sqlite.version>3.53.2.0</sqlite.version>
453451
<stax.ex.version>2.1.0</stax.ex.version>
@@ -574,30 +572,30 @@
574572
<type>pom</type>
575573
<scope>import</scope>
576574
</dependency>
577-
<!-- avoid outdated http2 dependencies when using solr 8 -->
575+
<!-- Jetty 12 renamed all http2 artifacts with a jetty- prefix -->
578576
<dependency>
579577
<groupId>org.eclipse.jetty.http2</groupId>
580-
<artifactId>http2-http-client-transport</artifactId>
578+
<artifactId>jetty-http2-client-transport</artifactId>
581579
<version>${jetty.http2.version}</version>
582580
</dependency>
583581
<dependency>
584582
<groupId>org.eclipse.jetty.http2</groupId>
585-
<artifactId>http2-hpack</artifactId>
583+
<artifactId>jetty-http2-hpack</artifactId>
586584
<version>${jetty.http2.version}</version>
587585
</dependency>
588586
<dependency>
589587
<groupId>org.eclipse.jetty.http2</groupId>
590-
<artifactId>http2-client</artifactId>
588+
<artifactId>jetty-http2-client</artifactId>
591589
<version>${jetty.http2.version}</version>
592590
</dependency>
593591
<dependency>
594592
<groupId>org.eclipse.jetty.http2</groupId>
595-
<artifactId>http2-common</artifactId>
593+
<artifactId>jetty-http2-common</artifactId>
596594
<version>${jetty.http2.version}</version>
597595
</dependency>
598596
<dependency>
599597
<groupId>org.eclipse.jetty.http2</groupId>
600-
<artifactId>http2-server</artifactId>
598+
<artifactId>jetty-http2-server</artifactId>
601599
<version>${jetty.http2.version}</version>
602600
</dependency>
603601
<dependency>
@@ -821,6 +819,11 @@
821819
<artifactId>jakarta.xml.bind-api</artifactId>
822820
<version>${jakarta.xml.bind.version}</version>
823821
</dependency>
822+
<dependency>
823+
<groupId>jakarta.servlet</groupId>
824+
<artifactId>jakarta.servlet-api</artifactId>
825+
<version>${jakarta.servlet.version}</version>
826+
</dependency>
824827
<dependency>
825828
<groupId>jakarta.xml.soap</groupId>
826829
<artifactId>jakarta.xml.soap-api</artifactId>
@@ -1361,17 +1364,11 @@
13611364
<version>3.2.0</version>
13621365
<configuration>
13631366
<excludeCoordinates>
1364-
<!-- solr emitter -->
1365-
<coordinate>
1366-
<groupId>org.eclipse.jetty</groupId>
1367-
<artifactId>jetty-http</artifactId>
1368-
<version>11.0.26</version>
1369-
</coordinate>
1370-
<!-- [CVE-2025-1948], used in the Solr emitter. No apparent upgrade available yet. -->
1367+
<!-- [CVE-2025-1948] check if still present in ${jetty.http2.version}; CVE-2026-2332 is fixed. -->
13711368
<coordinate>
13721369
<groupId>org.eclipse.jetty.http2</groupId>
1373-
<artifactId>http2-common</artifactId>
1374-
<version>11.0.26</version>
1370+
<artifactId>jetty-http2-common</artifactId>
1371+
<version>${jetty.http2.version}</version>
13751372
</coordinate>
13761373
<!-- used only in tests and in tika-eval, and this problem requires the use of the console.
13771374
https://github.com/h2database/h2database/issues/1294 -->

tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ public void setDisableContentCompression(boolean disableContentCompression) {
238238
this.disableContentCompression = disableContentCompression;
239239
}
240240

241+
public boolean isVerifySsl() {
242+
return verifySsl;
243+
}
244+
241245
public void setVerifySsl(boolean verifySsl) {
242246
this.verifySsl = verifySsl;
243247
}

tika-pipes/tika-pipes-plugins/tika-pipes-solr/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,25 @@
6969
<artifactId>solr-solrj</artifactId>
7070
<version>${solrj.version}</version>
7171
</dependency>
72+
<dependency>
73+
<groupId>org.apache.solr</groupId>
74+
<artifactId>solr-solrj-jetty</artifactId>
75+
<version>${solrj.version}</version>
76+
</dependency>
77+
<dependency>
78+
<groupId>org.apache.solr</groupId>
79+
<artifactId>solr-solrj-zookeeper</artifactId>
80+
<version>${solrj.version}</version>
81+
</dependency>
7282
<dependency>
7383
<groupId>com.fasterxml.jackson.core</groupId>
7484
<artifactId>jackson-databind</artifactId>
7585
</dependency>
86+
<dependency>
87+
<groupId>org.mockito</groupId>
88+
<artifactId>mockito-core</artifactId>
89+
<scope>test</scope>
90+
</dependency>
7691
</dependencies>
7792

7893
<build>

tika-pipes/tika-pipes-plugins/tika-pipes-solr/src/main/java/org/apache/tika/pipes/emitter/solr/SolrEmitter.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525

2626
import org.apache.solr.client.solrj.SolrClient;
2727
import org.apache.solr.client.solrj.impl.CloudSolrClient;
28-
import org.apache.solr.client.solrj.impl.Http2SolrClient;
29-
import org.apache.solr.client.solrj.impl.LBHttpSolrClient;
28+
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
3029
import org.apache.solr.client.solrj.request.UpdateRequest;
3130
import org.apache.solr.client.solrj.response.UpdateResponse;
3231
import org.apache.solr.common.SolrInputDocument;
@@ -39,6 +38,7 @@
3938
import org.apache.tika.parser.ParseContext;
4039
import org.apache.tika.pipes.api.emitter.AbstractEmitter;
4140
import org.apache.tika.pipes.api.emitter.EmitData;
41+
import org.apache.tika.pipes.plugin.solr.SolrClientHelper;
4242
import org.apache.tika.plugins.ExtensionConfig;
4343
import org.apache.tika.utils.StringUtils;
4444

@@ -105,29 +105,29 @@ private static SolrClient buildSolrClient(SolrEmitterConfig config) throws TikaC
105105
if (config.proxyPort() != null && config.proxyPort() > 0) {
106106
httpClientFactory.setProxyPort(config.proxyPort());
107107
}
108+
httpClientFactory.setVerifySsl(config.verifySslOrDefault());
108109

109110
if (config.solrUrls() == null || config.solrUrls().isEmpty()) {
110111
// Use ZooKeeper-based CloudSolrClient
111-
Http2SolrClient.Builder http2SolrClientBuilder = new Http2SolrClient.Builder();
112-
if (!StringUtils.isBlank(httpClientFactory.getUserName())) {
113-
http2SolrClientBuilder.withBasicAuthCredentials(httpClientFactory.getUserName(), httpClientFactory.getPassword());
114-
}
115-
http2SolrClientBuilder
112+
HttpJettySolrClient.Builder jettyClientBuilder = new HttpJettySolrClient.Builder();
113+
SolrClientHelper.applyClientSettings(jettyClientBuilder, httpClientFactory);
114+
jettyClientBuilder
116115
.withRequestTimeout(httpClientFactory.getRequestTimeoutMillis(), TimeUnit.MILLISECONDS)
117-
.withConnectionTimeout(config.getConnectionTimeoutMillisOrDefault(), TimeUnit.MILLISECONDS);
116+
.withConnectionTimeout(config.getConnectionTimeoutMillisOrDefault(), TimeUnit.MILLISECONDS)
117+
.withIdleTimeout(config.getSocketTimeoutMillisOrDefault(), TimeUnit.MILLISECONDS);
118118

119-
Http2SolrClient http2SolrClient = http2SolrClientBuilder.build();
120119
return new CloudSolrClient.Builder(config.solrZkHosts(), Optional.ofNullable(config.solrZkChroot()))
121-
.withHttpClient(http2SolrClient)
120+
.withHttpClientBuilder(jettyClientBuilder)
122121
.build();
123122
} else {
124-
// Use direct URL-based LBHttpSolrClient
125-
return new LBHttpSolrClient.Builder()
123+
// Use direct URL-based LBJettySolrClient
124+
HttpJettySolrClient.Builder jettyClientBuilder = new HttpJettySolrClient.Builder();
125+
SolrClientHelper.applyClientSettings(jettyClientBuilder, httpClientFactory);
126+
jettyClientBuilder
127+
.withRequestTimeout(httpClientFactory.getRequestTimeoutMillis(), TimeUnit.MILLISECONDS)
126128
.withConnectionTimeout(config.getConnectionTimeoutMillisOrDefault(), TimeUnit.MILLISECONDS)
127-
.withSocketTimeout(config.getSocketTimeoutMillisOrDefault(), TimeUnit.MILLISECONDS)
128-
.withHttpClient(httpClientFactory.build())
129-
.withBaseEndpoints(config.solrUrls().toArray(new String[]{}))
130-
.build();
129+
.withIdleTimeout(config.getSocketTimeoutMillisOrDefault(), TimeUnit.MILLISECONDS);
130+
return SolrClientHelper.buildLbClient(jettyClientBuilder, config.solrUrls());
131131
}
132132
}
133133

tika-pipes/tika-pipes-plugins/tika-pipes-solr/src/main/java/org/apache/tika/pipes/emitter/solr/SolrEmitterConfig.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public record SolrEmitterConfig(
4141
String password,
4242
String authScheme,
4343
String proxyHost,
44-
Integer proxyPort
44+
Integer proxyPort,
45+
@JsonProperty(defaultValue = "true") Boolean verifySsl
4546
) {
4647

4748
public enum AttachmentStrategy {
@@ -109,4 +110,9 @@ public int getSocketTimeoutMillisOrDefault() {
109110
public String getEmbeddedFileFieldNameOrDefault() {
110111
return embeddedFileFieldName != null ? embeddedFileFieldName : "embedded";
111112
}
113+
114+
/** SSL verification is on unless explicitly disabled (unset == secure). */
115+
public boolean verifySslOrDefault() {
116+
return verifySsl == null || verifySsl;
117+
}
112118
}

0 commit comments

Comments
 (0)