Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@
import org.apache.zookeeper.metrics.Gauge;
import org.apache.zookeeper.metrics.GaugeSet;
import org.apache.zookeeper.metrics.MetricsContext;
import org.apache.zookeeper.metrics.MetricsContext.DetailLevel;
import org.apache.zookeeper.metrics.MetricsProvider;
import org.apache.zookeeper.metrics.MetricsProviderLifeCycleException;
import org.apache.zookeeper.metrics.Summary;
import org.apache.zookeeper.metrics.SummarySet;
import org.apache.zookeeper.server.admin.UnifiedConnectionFactory;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
Expand Down Expand Up @@ -83,6 +87,7 @@ public class PrometheusMetricsProvider implements MetricsProvider {
private String trustStoreType;
private boolean needClientAuth = true; // Secure default
private boolean wantClientAuth = true; // Secure default
private int httpVersion;

// Constants for configuration
public static final String NUM_WORKER_THREADS = "numWorkerThreads";
Expand All @@ -94,7 +99,10 @@ public class PrometheusMetricsProvider implements MetricsProvider {
public static final String SSL_TRUSTSTORE_TYPE = "ssl.trustStore.type";
public static final String SSL_NEED_CLIENT_AUTH = "ssl.need.client.auth";
public static final String SSL_WANT_CLIENT_AUTH = "ssl.want.client.auth";
public static final String HTTP_VERSION = "httpVersion";
public static final int SCAN_INTERVAL = 60 * 10; // 10 minutes
public static final int DEFAULT_HTTP_VERSION = 11; // based on HttpVersion.java in jetty
public static final int DEFAULT_STS_MAX_AGE = 1 * 24 * 60 * 60; // seconds in a day

/**
* Custom servlet to disable the TRACE method for security reasons.
Expand Down Expand Up @@ -130,6 +138,7 @@ public void configure(Properties configuration) throws MetricsProviderLifeCycleE
this.trustStoreType = configuration.getProperty(SSL_TRUSTSTORE_TYPE, "PKCS12");
this.needClientAuth = Boolean.parseBoolean(configuration.getProperty(SSL_NEED_CLIENT_AUTH, "true"));
this.wantClientAuth = Boolean.parseBoolean(configuration.getProperty(SSL_WANT_CLIENT_AUTH, "true"));
this.httpVersion = Integer.getInteger(HTTP_VERSION, DEFAULT_HTTP_VERSION);
}

// Validate that at least one port is configured.
Expand Down Expand Up @@ -162,23 +171,47 @@ public void start() throws MetricsProviderLifeCycleException {
int acceptors = 1;
int selectors = 1;

// Configure HTTP connector if enabled
if (this.httpPort != -1) {
ServerConnector httpConnector = new ServerConnector(server, acceptors, selectors);
httpConnector.setPort(this.httpPort);
httpConnector.setHost(this.host);
server.addConnector(httpConnector);
}
ServerConnector connector = null;

if (this.httpPort != -1 && this.httpsPort != -1 && this.httpPort == this.httpsPort) {
SecureRequestCustomizer customizer = new SecureRequestCustomizer();
customizer.setStsMaxAge(DEFAULT_STS_MAX_AGE);
customizer.setStsIncludeSubDomains(true);

HttpConfiguration config = new HttpConfiguration();
config.setSecureScheme("https");
config.addCustomizer(customizer);

// Configure HTTPS connector if enabled
if (this.httpsPort != -1) {
SslContextFactory.Server sslContextFactory = createSslContextFactory();
KeyStoreScanner keystoreScanner = new KeyStoreScanner(sslContextFactory);
keystoreScanner.setScanInterval(SCAN_INTERVAL);
server.addBean(keystoreScanner);
server.addConnector(createSslConnector(server, acceptors, selectors, sslContextFactory));
setKeyStoreScanner(sslContextFactory);

String nextProtocol = HttpVersion.fromVersion(httpVersion).asString();
connector = new ServerConnector(server,
new UnifiedConnectionFactory(sslContextFactory, nextProtocol),
new HttpConnectionFactory(config));
connector.setPort(this.httpPort);
connector.setHost(this.host);
LOG.debug("Created unified ServerConnector for host: {}, httpPort: {}", host, httpPort);
} else {
// Configure HTTP connector if enabled
if (this.httpPort != -1) {
connector = new ServerConnector(server, acceptors, selectors);
connector.setPort(this.httpPort);
connector.setHost(this.host);
LOG.debug("Created ServerConnector for host: {}, httpPort: {}", host, httpPort);
}

// Configure HTTPS connector if enabled
if (this.httpsPort != -1) {
SslContextFactory.Server sslContextFactory = createSslContextFactory();
setKeyStoreScanner(sslContextFactory);
connector = createSslConnector(server, acceptors, selectors, sslContextFactory);
LOG.debug("Created HTTPS ServerConnector for host: {}, httpsPort: {}", host, httpsPort);
}
}

server.addConnector(connector);

// Set up the servlet context handler
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
Expand All @@ -198,6 +231,12 @@ public void start() throws MetricsProviderLifeCycleException {
}
}

private void setKeyStoreScanner(SslContextFactory.Server sslContextFactory) {
KeyStoreScanner keystoreScanner = new KeyStoreScanner(sslContextFactory);
keystoreScanner.setScanInterval(SCAN_INTERVAL);
server.addBean(keystoreScanner);
}

/**
* Creates and configures the SslContextFactory for the server.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@
public class PrometheusHttpsMetricsProviderTest extends PrometheusMetricsTestBase {

private PrometheusMetricsProvider provider;
private String httpHost = "127.0.0.1";
private int httpsPort = 4443;
private int httpPort = 4000;
private String testDataPath = System.getProperty("test.data.dir", "src/test/resources/data");
private final String httpHost = "127.0.0.1";
private final int httpsPort = 4443;
private final int httpPort = 4000;
private final String testDataPath = System.getProperty("test.data.dir", "src/test/resources/data");

public void initializeProviderWithCustomConfig(Properties inputConfiguration) throws Exception {
provider = new PrometheusMetricsProvider();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,20 @@ public void testInvalidSslConfig() throws MetricsProviderLifeCycleException {
provider.start();
});
}

@Test
public void testPortUnification() throws Exception {
int unifiedPort = 5400;
Properties configuration = new Properties();
configuration.setProperty("httpsPort", String.valueOf(unifiedPort));
configuration.setProperty("httpPort", String.valueOf(unifiedPort));
String testDataPath = System.getProperty("test.data.dir", "src/test/resources/data");
configuration.setProperty("ssl.keyStore.location", testDataPath + "/ssl/server_keystore.jks");
configuration.setProperty("ssl.keyStore.password", "testpass");
configuration.setProperty("ssl.trustStore.location", testDataPath + "/ssl/server_truststore.jks");
configuration.setProperty("ssl.trustStore.password", "testpass");
PrometheusMetricsProvider provider = new PrometheusMetricsProvider();
provider.configure(configuration);
provider.start();
}
}
Loading