Skip to content

Commit 0b7a305

Browse files
authored
Add support for Apache HTTP client 5 in X-Pack SSL (#133895)
This extends the X-Pack SslProfile class to have support for HTTP Client 5's TlsStrategy class. This is needed in order to support a migration from HTTP client 4 to HTTP client 5
1 parent 689ee42 commit 0b7a305

File tree

43 files changed

+1026
-185
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1026
-185
lines changed

build-tools-internal/version.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ opensaml = 4.3.0
2929
# client dependencies
3030
httpclient = 4.5.14
3131
httpcore = 4.4.16
32+
httpclient5 = 5.5
33+
httpcore5 = 5.3.5
3234
httpasyncclient = 4.1.5
3335
commonslogging = 1.2
3436
commonscodec = 1.15

gradle/verification-metadata.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,16 +2907,31 @@
29072907
<sha256 value="a0a9dcd3696a6281f82e392d39aa674bf9662496605411de2a00d44435a7fb26" origin="Generated by Gradle"/>
29082908
</artifact>
29092909
</component>
2910+
<component group="org.apache.httpcomponents.client5" name="httpclient5" version="5.5">
2911+
<artifact name="httpclient5-5.5.jar">
2912+
<sha256 value="496b4b0e8d5f3a8139a5d2638486d304758bac3a9c39d76989f663cfd9354fc9" origin="Generated by Gradle"/>
2913+
</artifact>
2914+
</component>
29102915
<component group="org.apache.httpcomponents.core5" name="httpcore5" version="5.3.3">
29112916
<artifact name="httpcore5-5.3.3.jar">
29122917
<sha256 value="087b7ae9bde9d3518b4b5d06f3560d7fd0db04098655e76b64e791773847d503" origin="Generated by Gradle"/>
29132918
</artifact>
29142919
</component>
2920+
<component group="org.apache.httpcomponents.core5" name="httpcore5" version="5.3.5">
2921+
<artifact name="httpcore5-5.3.5.jar">
2922+
<sha256 value="34ce80396dcf2927406ddcd7c1c9063879220952ad0a2121c10103d3ad2cc3a4" origin="Generated by Gradle"/>
2923+
</artifact>
2924+
</component>
29152925
<component group="org.apache.httpcomponents.core5" name="httpcore5-h2" version="5.3.3">
29162926
<artifact name="httpcore5-h2-5.3.3.jar">
29172927
<sha256 value="a121f4b14ec525e54e29b9f5db7b93f4a97e088774e81c7143b5198f67d81bec" origin="Generated by Gradle"/>
29182928
</artifact>
29192929
</component>
2930+
<component group="org.apache.httpcomponents.core5" name="httpcore5-h2" version="5.3.5">
2931+
<artifact name="httpcore5-h2-5.3.5.jar">
2932+
<sha256 value="2a661d8756fb298db7d561c2dabb5e79144b0dae6676735134ef6a8f4c3125e3" origin="Generated by Gradle"/>
2933+
</artifact>
2934+
</component>
29202935
<component group="org.apache.james" name="apache-mime4j-core" version="0.8.13">
29212936
<artifact name="apache-mime4j-core-0.8.13.jar">
29222937
<sha256 value="00496c123926395d59e5dfdfc8342c607600c6c9e6e6dcab981a673b62481cdf" origin="Generated by Gradle"/>
@@ -4935,6 +4950,11 @@
49354950
<sha256 value="2f2a92d410b268139d7d63b75ed25e21995cfe4100c19bf23577cfdbc8077bda" origin="Generated by Gradle"/>
49364951
</artifact>
49374952
</component>
4953+
<component group="org.slf4j" name="slf4j-ext" version="2.0.6">
4954+
<artifact name="slf4j-ext-2.0.6.jar">
4955+
<sha256 value="0f6ef03bc0291899f3fb324baba0dee02fa8c6c1adc7b465f5b923ac70379efd" origin="Generated by Gradle"/>
4956+
</artifact>
4957+
</component>
49384958
<component group="org.slf4j" name="slf4j-log4j12" version="1.7.10">
49394959
<artifact name="slf4j-log4j12-1.7.10.jar">
49404960
<sha256 value="2e4eebc6e346c92c417aa4e662738802645ef21c5eb4435132dc78d631f2eebb" origin="Generated by Gradle"/>

x-pack/plugin/core/build.gradle

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ esplugin {
3232
tasks.named("dependencyLicenses").configure {
3333
mapping from: /http.*/, to: 'httpclient' // pulled in by rest client
3434
mapping from: /commons-.*/, to: 'commons' // pulled in by rest client
35+
mapping from: /slf4j-.*/, to: 'slf4j'
3536
}
3637

3738
configurations {
@@ -43,13 +44,30 @@ dependencies {
4344
compileOnly project(":server")
4445
api project(':libs:grok')
4546
api project(":libs:ssl-config")
47+
4648
api "org.apache.httpcomponents:httpclient:${versions.httpclient}"
4749
api "org.apache.httpcomponents:httpcore:${versions.httpcore}"
4850
api "org.apache.httpcomponents:httpcore-nio:${versions.httpcore}"
4951
api "org.apache.httpcomponents:httpasyncclient:${versions.httpasyncclient}"
52+
53+
api "org.apache.httpcomponents.client5:httpclient5:${versions.httpclient5}"
54+
api "org.apache.httpcomponents.core5:httpcore5:${versions.httpcore5}"
55+
api "org.apache.httpcomponents.core5:httpcore5-h2:${versions.httpcore5}"
56+
57+
// Ideally this would be `runtimeOnly` so that we don't accidentally write code against the SLF4j API
58+
// However, some child plugins (like security) need to use slf4j directly in order to manage logging for their dependencies :(
59+
// And due to the way our plugin loading handles java modules between dependent plugins, this plugin (x-pack-core) needs to declare
60+
// a module dependency on slf4j (`requires org.slf4j`) so that security can also be dependent on it
61+
// And having a module dependency counts as using the jar, so we can't make it `runtimeOnly` :(
62+
63+
implementation "org.slf4j:slf4j-api:${versions.slf4j}"
64+
runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:${versions.log4j}"
65+
5066
api "commons-logging:commons-logging:${versions.commonslogging}"
5167
api "org.apache.logging.log4j:log4j-1.2-api:${versions.log4j}"
68+
5269
api "commons-codec:commons-codec:${versions.commonscodec}"
70+
5371
testImplementation project(path: ':modules:aggregations')
5472
testImplementation project(path: ':modules:data-streams')
5573
testImplementation project(':modules:mapper-extras')
@@ -60,9 +78,6 @@ dependencies {
6078
implementation project(":x-pack:plugin:core:template-resources")
6179

6280
testImplementation "org.elasticsearch:mocksocket:${versions.mocksocket}"
63-
testImplementation "org.apache.logging.log4j:log4j-slf4j-impl:${versions.log4j}"
64-
// this might suffer from https://github.com/elastic/elasticsearch/issues/93714
65-
testImplementation "org.slf4j:slf4j-api:${versions.slf4j}"
6681
testImplementation project(path: ':modules:reindex')
6782
testImplementation project(path: ':modules:parent-join')
6883
testImplementation project(path: ':modules:lang-mustache')
@@ -139,7 +154,11 @@ tasks.named("thirdPartyAudit").configure {
139154
//commons-logging provided dependencies
140155
'javax.servlet.ServletContextEvent',
141156
'javax.servlet.ServletContextListener',
142-
'javax.jms.Message'
157+
'javax.jms.Message',
158+
// HttpClient5 can use Conscrypt (TLS using BoringSSL), but we don't want that
159+
'org.conscrypt.Conscrypt',
160+
// SLF4j via HttpClient5
161+
'org.slf4j.ext.EventData'
143162
)
144163
}
145164

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

x-pack/plugin/core/src/main/java/module-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
requires unboundid.ldapsdk;
2424
requires org.elasticsearch.tdigest;
2525
requires org.elasticsearch.xcore.templates;
26+
requires org.apache.httpcomponents.client5.httpclient5;
27+
requires org.apache.httpcomponents.core5.httpcore5;
28+
requires org.slf4j;
2629

2730
exports org.elasticsearch.index.engine.frozen;
2831
exports org.elasticsearch.license;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.core.ssl;
9+
10+
import org.apache.http.conn.ssl.NoopHostnameVerifier;
11+
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
12+
import org.elasticsearch.common.Strings;
13+
import org.elasticsearch.common.ssl.SslConfiguration;
14+
15+
import java.util.List;
16+
17+
import javax.net.ssl.HostnameVerifier;
18+
import javax.net.ssl.SSLContext;
19+
import javax.net.ssl.SSLParameters;
20+
21+
public abstract class AbstractSslBuilder<T> {
22+
23+
public T build(SslConfiguration config, SSLContext sslContext) {
24+
String[] ciphers = supportedCiphers(sslParameters(sslContext).getCipherSuites(), config.getCipherSuites(), false);
25+
String[] supportedProtocols = config.supportedProtocols().toArray(Strings.EMPTY_ARRAY);
26+
HostnameVerifier verifier;
27+
28+
if (config.verificationMode().isHostnameVerificationEnabled()) {
29+
verifier = SSLIOSessionStrategy.getDefaultHostnameVerifier();
30+
} else {
31+
verifier = NoopHostnameVerifier.INSTANCE;
32+
}
33+
34+
return build(sslContext, supportedProtocols, ciphers, verifier);
35+
}
36+
37+
/**
38+
* This method exists to simplify testing
39+
*/
40+
String[] supportedCiphers(String[] supportedCiphers, List<String> requestedCiphers, boolean log) {
41+
return SSLService.supportedCiphers(supportedCiphers, requestedCiphers, log);
42+
}
43+
44+
/**
45+
* The {@link SSLParameters} that are associated with the {@code sslContext}.
46+
* <p>
47+
* This method exists to simplify testing since {@link SSLContext#getSupportedSSLParameters()} is {@code final}.
48+
*
49+
* @param sslContext The SSL context for the current SSL settings
50+
* @return Never {@code null}.
51+
*/
52+
SSLParameters sslParameters(SSLContext sslContext) {
53+
return sslContext.getSupportedSSLParameters();
54+
}
55+
56+
abstract T build(SSLContext sslContext, String[] protocols, String[] ciphers, HostnameVerifier verifier);
57+
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLIOSessionStrategyBuilder.java

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,68 +8,32 @@
88
package org.elasticsearch.xpack.core.ssl;
99

1010
import org.apache.http.HttpHost;
11-
import org.apache.http.conn.ssl.NoopHostnameVerifier;
1211
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
1312
import org.apache.http.nio.reactor.IOSession;
1413
import org.elasticsearch.common.Strings;
1514
import org.elasticsearch.common.logging.LoggerMessageFormat;
16-
import org.elasticsearch.common.ssl.SslConfiguration;
1715
import org.elasticsearch.common.ssl.SslDiagnostics;
1816

1917
import java.security.cert.Certificate;
2018
import java.security.cert.X509Certificate;
21-
import java.util.List;
2219

2320
import javax.net.ssl.HostnameVerifier;
2421
import javax.net.ssl.SSLContext;
2522
import javax.net.ssl.SSLException;
26-
import javax.net.ssl.SSLParameters;
2723
import javax.net.ssl.SSLPeerUnverifiedException;
2824
import javax.net.ssl.SSLSession;
2925
import javax.security.auth.x500.X500Principal;
3026

31-
public class SSLIOSessionStrategyBuilder {
27+
class SSLIOSessionStrategyBuilder extends AbstractSslBuilder<SSLIOSessionStrategy> {
3228

3329
public static final SSLIOSessionStrategyBuilder INSTANCE = new SSLIOSessionStrategyBuilder();
3430

35-
public SSLIOSessionStrategy sslIOSessionStrategy(SslConfiguration config, SSLContext sslContext) {
36-
String[] ciphers = supportedCiphers(sslParameters(sslContext).getCipherSuites(), config.getCipherSuites(), false);
37-
String[] supportedProtocols = config.supportedProtocols().toArray(Strings.EMPTY_ARRAY);
38-
HostnameVerifier verifier;
39-
40-
if (config.verificationMode().isHostnameVerificationEnabled()) {
41-
verifier = SSLIOSessionStrategy.getDefaultHostnameVerifier();
42-
} else {
43-
verifier = NoopHostnameVerifier.INSTANCE;
44-
}
45-
46-
return sslIOSessionStrategy(sslContext, supportedProtocols, ciphers, verifier);
47-
}
48-
49-
/**
50-
* This method exists to simplify testing
51-
*/
52-
String[] supportedCiphers(String[] supportedCiphers, List<String> requestedCiphers, boolean log) {
53-
return SSLService.supportedCiphers(supportedCiphers, requestedCiphers, log);
54-
}
55-
56-
/**
57-
* The {@link SSLParameters} that are associated with the {@code sslContext}.
58-
* <p>
59-
* This method exists to simplify testing since {@link SSLContext#getSupportedSSLParameters()} is {@code final}.
60-
*
61-
* @param sslContext The SSL context for the current SSL settings
62-
* @return Never {@code null}.
63-
*/
64-
SSLParameters sslParameters(SSLContext sslContext) {
65-
return sslContext.getSupportedSSLParameters();
66-
}
67-
6831
/**
6932
* This method only exists to simplify testing because {@link SSLIOSessionStrategy} does
7033
* not expose any of the parameters that you give it.
7134
*/
72-
SSLIOSessionStrategy sslIOSessionStrategy(SSLContext sslContext, String[] protocols, String[] ciphers, HostnameVerifier verifier) {
35+
@Override
36+
SSLIOSessionStrategy build(SSLContext sslContext, String[] protocols, String[] ciphers, HostnameVerifier verifier) {
7337
return new SSLIOSessionStrategy(sslContext, protocols, ciphers, verifier) {
7438
@Override
7539
protected void verifySession(HttpHost host, IOSession iosession, SSLSession session) throws SSLException {

0 commit comments

Comments
 (0)