Skip to content

Commit afe8f08

Browse files
authored
ZOOKEEPER-5029: Port unification for PrometheusMetricsProvider
Reviewers: meszibalu, anmolnar Author: PDavid Closes #2362 from PDavid/ZOOKEEPER-5029-PrometheusMetricsProvider-portUnification
1 parent dc3150a commit afe8f08

3 files changed

Lines changed: 79 additions & 17 deletions

File tree

zookeeper-metrics-providers/zookeeper-prometheus-metrics/src/main/java/org/apache/zookeeper/metrics/prometheus/PrometheusMetricsProvider.java

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
import org.apache.zookeeper.metrics.MetricsProviderLifeCycleException;
4242
import org.apache.zookeeper.metrics.Summary;
4343
import org.apache.zookeeper.metrics.SummarySet;
44+
import org.apache.zookeeper.server.admin.UnifiedConnectionFactory;
45+
import org.eclipse.jetty.http.HttpVersion;
46+
import org.eclipse.jetty.server.HttpConfiguration;
47+
import org.eclipse.jetty.server.HttpConnectionFactory;
48+
import org.eclipse.jetty.server.SecureRequestCustomizer;
4449
import org.eclipse.jetty.server.Server;
4550
import org.eclipse.jetty.server.ServerConnector;
4651
import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -84,6 +89,7 @@ public class PrometheusMetricsProvider implements MetricsProvider {
8489
private boolean wantClientAuth = true; // Secure default
8590
private String enabledProtocols;
8691
private String cipherSuites;
92+
private int httpVersion;
8793

8894
// Constants for configuration
8995
public static final String HTTP_HOST = "httpHost";
@@ -101,7 +107,14 @@ public class PrometheusMetricsProvider implements MetricsProvider {
101107
public static final String SSL_WANT_CLIENT_AUTH = "ssl.want.client.auth";
102108
public static final String SSL_ENABLED_PROTOCOLS = "ssl.enabledProtocols";
103109
public static final String SSL_ENABLED_CIPHERS = "ssl.ciphersuites";
110+
public static final String HTTP_VERSION = "httpVersion";
104111
public static final int SCAN_INTERVAL = 60 * 10; // 10 minutes
112+
public static final int DEFAULT_HTTP_VERSION = 11; // based on HttpVersion.java in jetty
113+
/**
114+
* The time, in seconds, that the browser should remember that a host is only to be accessed using HTTPS.
115+
* Seconds in a day.
116+
*/
117+
public static final int DEFAULT_STS_MAX_AGE = 1 * 24 * 60 * 60;
105118

106119
/**
107120
* Custom servlet to disable the TRACE method for security reasons.
@@ -139,6 +152,7 @@ public void configure(Properties configuration) throws MetricsProviderLifeCycleE
139152
this.wantClientAuth = Boolean.parseBoolean(configuration.getProperty(SSL_WANT_CLIENT_AUTH, "true"));
140153
this.enabledProtocols = configuration.getProperty(SSL_ENABLED_PROTOCOLS);
141154
this.cipherSuites = configuration.getProperty(SSL_ENABLED_CIPHERS);
155+
this.httpVersion = Integer.getInteger(HTTP_VERSION, DEFAULT_HTTP_VERSION);
142156
}
143157

144158
// Validate that at least one port is configured.
@@ -171,23 +185,49 @@ public void start() throws MetricsProviderLifeCycleException {
171185
int acceptors = 1;
172186
int selectors = 1;
173187

174-
// Configure HTTP connector if enabled
175-
if (this.httpPort != -1) {
176-
ServerConnector httpConnector = new ServerConnector(server, acceptors, selectors);
177-
httpConnector.setPort(this.httpPort);
178-
httpConnector.setHost(this.host);
179-
server.addConnector(httpConnector);
180-
}
188+
ServerConnector connector = null;
189+
190+
if (this.httpPort != -1 && this.httpsPort != -1 && this.httpPort == this.httpsPort) {
191+
// Set Strict-Transport-Security HTTP response header.
192+
SecureRequestCustomizer customizer = new SecureRequestCustomizer();
193+
customizer.setStsMaxAge(DEFAULT_STS_MAX_AGE);
194+
// Strict-Transport-Security HTTP header should apply to all subdomains of the host's domain as well.
195+
customizer.setStsIncludeSubDomains(true);
196+
197+
HttpConfiguration config = new HttpConfiguration();
198+
config.setSecureScheme("https");
199+
config.addCustomizer(customizer);
181200

182-
// Configure HTTPS connector if enabled
183-
if (this.httpsPort != -1) {
184201
SslContextFactory.Server sslContextFactory = createSslContextFactory();
185-
KeyStoreScanner keystoreScanner = new KeyStoreScanner(sslContextFactory);
186-
keystoreScanner.setScanInterval(SCAN_INTERVAL);
187-
server.addBean(keystoreScanner);
188-
server.addConnector(createSslConnector(server, acceptors, selectors, sslContextFactory));
202+
setKeyStoreScanner(sslContextFactory);
203+
204+
String nextProtocol = HttpVersion.fromVersion(httpVersion).asString();
205+
connector = new ServerConnector(server,
206+
new UnifiedConnectionFactory(sslContextFactory, nextProtocol),
207+
new HttpConnectionFactory(config));
208+
connector.setPort(this.httpPort);
209+
connector.setHost(this.host);
210+
LOG.info("Created unified ServerConnector for host: {}, httpPort: {}", host, httpPort);
211+
} else {
212+
// Configure HTTP connector if enabled
213+
if (this.httpPort != -1) {
214+
connector = new ServerConnector(server, acceptors, selectors);
215+
connector.setPort(this.httpPort);
216+
connector.setHost(this.host);
217+
LOG.info("Created HTTP ServerConnector for host: {}, httpPort: {}", host, httpPort);
218+
}
219+
220+
// Configure HTTPS connector if enabled
221+
if (this.httpsPort != -1) {
222+
SslContextFactory.Server sslContextFactory = createSslContextFactory();
223+
setKeyStoreScanner(sslContextFactory);
224+
connector = createSslConnector(server, acceptors, selectors, sslContextFactory);
225+
LOG.info("Created HTTPS ServerConnector for host: {}, httpsPort: {}", host, httpsPort);
226+
}
189227
}
190228

229+
server.addConnector(connector);
230+
191231
// Set up the servlet context handler
192232
ServletContextHandler context = new ServletContextHandler();
193233
context.setContextPath("/");
@@ -207,6 +247,12 @@ public void start() throws MetricsProviderLifeCycleException {
207247
}
208248
}
209249

250+
private void setKeyStoreScanner(SslContextFactory.Server sslContextFactory) {
251+
KeyStoreScanner keystoreScanner = new KeyStoreScanner(sslContextFactory);
252+
keystoreScanner.setScanInterval(SCAN_INTERVAL);
253+
server.addBean(keystoreScanner);
254+
}
255+
210256
/**
211257
* Creates and configures the SslContextFactory for the server.
212258
*

zookeeper-metrics-providers/zookeeper-prometheus-metrics/src/test/java/org/apache/zookeeper/metrics/prometheus/PrometheusHttpsMetricsProviderTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@
4343
public class PrometheusHttpsMetricsProviderTest extends PrometheusMetricsTestBase {
4444

4545
private PrometheusMetricsProvider provider;
46-
private String httpHost = "127.0.0.1";
47-
private int httpsPort = 4443;
48-
private int httpPort = 4000;
49-
private String testDataPath = System.getProperty("test.data.dir", "src/test/resources/data");
46+
private final String httpHost = "127.0.0.1";
47+
private final int httpsPort = 4443;
48+
private final int httpPort = 4000;
49+
private final String testDataPath = System.getProperty("test.data.dir", "src/test/resources/data");
5050

5151
public void initializeProviderWithCustomConfig(Properties inputConfiguration) throws Exception {
5252
provider = new PrometheusMetricsProvider();

zookeeper-metrics-providers/zookeeper-prometheus-metrics/src/test/java/org/apache/zookeeper/metrics/prometheus/PrometheusMetricsProviderConfigTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,20 @@ public void checkServerTrusted(X509Certificate[] certs, String authType) {
292292
}
293293
};
294294
}
295+
296+
@Test
297+
public void testPortUnification() throws Exception {
298+
int unifiedPort = 5400;
299+
Properties configuration = new Properties();
300+
configuration.setProperty("httpsPort", String.valueOf(unifiedPort));
301+
configuration.setProperty("httpPort", String.valueOf(unifiedPort));
302+
String testDataPath = System.getProperty("test.data.dir", "src/test/resources/data");
303+
configuration.setProperty("ssl.keyStore.location", testDataPath + "/ssl/server_keystore.jks");
304+
configuration.setProperty("ssl.keyStore.password", "testpass");
305+
configuration.setProperty("ssl.trustStore.location", testDataPath + "/ssl/server_truststore.jks");
306+
configuration.setProperty("ssl.trustStore.password", "testpass");
307+
PrometheusMetricsProvider provider = new PrometheusMetricsProvider();
308+
provider.configure(configuration);
309+
provider.start();
310+
}
295311
}

0 commit comments

Comments
 (0)